diff --git a/.gitignore b/.gitignore index 2bf55144..9843db63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,29 @@ -node_modules/ +# -------------------- +# OSX Files +# -------------------- .DS_Store +.AppleDouble +.LSOverride +Icon +._* +.Spotlight-V100 +.Trashes + +# -------------------- +# IntelliJ Files +# -------------------- +*.iml +*.ipr +*.iws +.idea/ + +# -------------------- +# Sublime Files +# -------------------- *.sublime-project -*.sublime-workspace \ No newline at end of file +*.sublime-workspace + +# -------------------- +# App Files +# -------------------- +node_modules/ \ No newline at end of file diff --git a/README.md b/README.md index 8c8f430d..948781cb 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,14 @@ See [the english unit tests](https://github.com/adamwdraper/Numeral-js/blob/mast # Changelog +### 1.5.3 + +Added currency symbol to optionally appear before negative sign / open paren + +Added float precision math support + +Added specification of abbreviation in thousands, millions, billions + ### 1.5.2 Bug fix: Unformat should pass through if given a number diff --git a/bower.json b/bower.json index 92ed96e9..5dcf89f5 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "numeral", "repo": "adamwdraper/Numeral-js", - "version": "1.5.2", + "version": "1.5.3", "description": "Format and manipulate numbers.", "keywords": [ "numeral", diff --git a/component.json b/component.json index 57d310cd..b8239485 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "name": "numeral", "repo": "adamwdraper/Numeral-js", - "version": "1.5.2", + "version": "1.5.3", "description": "Format and manipulate numbers.", "keywords": [ "numeral", diff --git a/languages.js b/languages.js index 8c68d6a8..2f502ea0 100644 --- a/languages.js +++ b/languages.js @@ -33,6 +33,41 @@ this.numeral.language('be-nl', language); } }()); +/*! + * numeral.js language configuration + * language : simplified chinese + * author : badplum : https://github.com/badplum + */ +(function () { + var language = { + delimiters: { + thousands: ',', + decimal: '.' + }, + abbreviations: { + thousand: '千', + million: '百万', + billion: '十亿', + trillion: '兆' + }, + ordinal: function (number) { + return '.'; + }, + currency: { + symbol: '¥' + } + }; + + // Node + if (typeof module !== 'undefined' && module.exports) { + module.exports = language; + } + // Browser + if (typeof window !== 'undefined' && this.numeral && this.numeral.language) { + this.numeral.language('chs', language); + } +}()); + /*! * numeral.js language configuration * language : czech (cs) @@ -288,6 +323,44 @@ } }()); +/*! + * numeral.js language configuration + * language : Estonian + * author : Illimar Tambek : https://github.com/ragulka + * + * Note: in Estonian, abbreviations are always separated + * from numbers with a space + */ +(function () { + var language = { + delimiters: { + thousands: ' ', + decimal: ',' + }, + abbreviations: { + thousand: ' tuh', + million: ' mln', + billion: ' mld', + trillion: ' trl' + }, + ordinal: function (number) { + return '.'; + }, + currency: { + symbol: '€' + } + }; + + // Node + if (typeof module !== 'undefined' && module.exports) { + module.exports = language; + } + // Browser + if (typeof window !== 'undefined' && this.numeral && this.numeral.language) { + this.numeral.language('et', language); + } +}()); + /*! * numeral.js language configuration * language : Finnish diff --git a/languages/chs.js b/languages/chs.js new file mode 100644 index 00000000..9c54f2f1 --- /dev/null +++ b/languages/chs.js @@ -0,0 +1,34 @@ +/*! + * numeral.js language configuration + * language : simplified chinese + * author : badplum : https://github.com/badplum + */ +(function () { + var language = { + delimiters: { + thousands: ',', + decimal: '.' + }, + abbreviations: { + thousand: '千', + million: '百万', + billion: '十亿', + trillion: '兆' + }, + ordinal: function (number) { + return '.'; + }, + currency: { + symbol: '¥' + } + }; + + // Node + if (typeof module !== 'undefined' && module.exports) { + module.exports = language; + } + // Browser + if (typeof window !== 'undefined' && this.numeral && this.numeral.language) { + this.numeral.language('chs', language); + } +}()); diff --git a/languages/et.js b/languages/et.js new file mode 100644 index 00000000..f45dd7de --- /dev/null +++ b/languages/et.js @@ -0,0 +1,37 @@ +/*! + * numeral.js language configuration + * language : Estonian + * author : Illimar Tambek : https://github.com/ragulka + * + * Note: in Estonian, abbreviations are always separated + * from numbers with a space + */ +(function () { + var language = { + delimiters: { + thousands: ' ', + decimal: ',' + }, + abbreviations: { + thousand: ' tuh', + million: ' mln', + billion: ' mld', + trillion: ' trl' + }, + ordinal: function (number) { + return '.'; + }, + currency: { + symbol: '€' + } + }; + + // Node + if (typeof module !== 'undefined' && module.exports) { + module.exports = language; + } + // Browser + if (typeof window !== 'undefined' && this.numeral && this.numeral.language) { + this.numeral.language('et', language); + } +}()); diff --git a/min/languages.min.js b/min/languages.min.js index 0fae9106..11252868 100644 --- a/min/languages.min.js +++ b/min/languages.min.js @@ -3,7 +3,12 @@ * language : belgium-dutch (be-nl) * author : Dieter Luypaert : https://github.com/moeriki */ -!function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:" mln",billion:" mld",trillion:" bln"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?"ste":"de"},currency:{symbol:"€ "}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("be-nl",a)}(),/*! +!function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:"k",million:" mln",billion:" mld",trillion:" bln"},ordinal:function(a){var b=a%100;return 0!==a&&1>=b||8===b||b>=20?"ste":"de"},currency:{symbol:"€ "}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("be-nl",a)}(),/*! + * numeral.js language configuration + * language : simplified chinese + * author : badplum : https://github.com/badplum + */ +function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"千",million:"百万",billion:"十亿",trillion:"兆"},ordinal:function(){return"."},currency:{symbol:"¥"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("chs",a)}(),/*! * numeral.js language configuration * language : czech (cs) * author : Anatoli Papirovski : https://github.com/apapirovski @@ -39,6 +44,14 @@ function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand * author : Hernan Garcia : https://github.com/hgarcia */ function(){var a={delimiters:{thousands:".",decimal:","},abbreviations:{thousand:"k",million:"mm",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===b||3===b?"er":2===b?"do":7===b||0===b?"mo":8===b?"vo":9===b?"no":"to"},currency:{symbol:"$"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("es",a)}(),/*! + * numeral.js language configuration + * language : Estonian + * author : Illimar Tambek : https://github.com/ragulka + * + * Note: in Estonian, abbreviations are always separated + * from numbers with a space + */ +function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:" tuh",million:" mln",billion:" mld",trillion:" trl"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("et",a)}(),/*! * numeral.js language configuration * language : Finnish * author : Sami Saada : https://github.com/samitheberber diff --git a/min/languages/chs.min.js b/min/languages/chs.min.js new file mode 100644 index 00000000..6d375969 --- /dev/null +++ b/min/languages/chs.min.js @@ -0,0 +1,6 @@ +/*! + * numeral.js language configuration + * language : simplified chinese + * author : badplum : https://github.com/badplum + */ +!function(){var a={delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"千",million:"百万",billion:"十亿",trillion:"兆"},ordinal:function(){return"."},currency:{symbol:"¥"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("chs",a)}(); \ No newline at end of file diff --git a/min/languages/et.min.js b/min/languages/et.min.js new file mode 100644 index 00000000..cf9f7e38 --- /dev/null +++ b/min/languages/et.min.js @@ -0,0 +1,9 @@ +/*! + * numeral.js language configuration + * language : Estonian + * author : Illimar Tambek : https://github.com/ragulka + * + * Note: in Estonian, abbreviations are always separated + * from numbers with a space + */ +!function(){var a={delimiters:{thousands:" ",decimal:","},abbreviations:{thousand:" tuh",million:" mln",billion:" mld",trillion:" trl"},ordinal:function(){return"."},currency:{symbol:"€"}};"undefined"!=typeof module&&module.exports&&(module.exports=a),"undefined"!=typeof window&&this.numeral&&this.numeral.language&&this.numeral.language("et",a)}(); \ No newline at end of file diff --git a/min/numeral.min.js b/min/numeral.min.js index 81d4e49b..d17b5571 100644 --- a/min/numeral.min.js +++ b/min/numeral.min.js @@ -1,8 +1,8 @@ /*! * numeral.js - * version : 1.5.2 + * version : 1.5.3 * author : Adam Draper * license : MIT * http://adamwdraper.github.com/Numeral-js/ */ -(function(){function a(a){this._value=a}function b(a,b,c,d){var e,f,g=Math.pow(10,b);return f=(c(a*g)/g).toFixed(b),d&&(e=new RegExp("0{1,"+d+"}$"),f=f.replace(e,"")),f}function c(a,b,c){var d;return d=b.indexOf("$")>-1?e(a,b,c):b.indexOf("%")>-1?f(a,b,c):b.indexOf(":")>-1?g(a,b):i(a._value,b,c)}function d(a,b){var c,d,e,f,g,i=b,j=["KB","MB","GB","TB","PB","EB","ZB","YB"],k=!1;if(b.indexOf(":")>-1)a._value=h(b);else if(b===o)a._value=0;else{for("."!==m[n].delimiters.decimal&&(b=b.replace(/\./g,"").replace(m[n].delimiters.decimal,".")),c=new RegExp("[^a-zA-Z]"+m[n].abbreviations.thousand+"(?:\\)|(\\"+m[n].currency.symbol+")?(?:\\))?)?$"),d=new RegExp("[^a-zA-Z]"+m[n].abbreviations.million+"(?:\\)|(\\"+m[n].currency.symbol+")?(?:\\))?)?$"),e=new RegExp("[^a-zA-Z]"+m[n].abbreviations.billion+"(?:\\)|(\\"+m[n].currency.symbol+")?(?:\\))?)?$"),f=new RegExp("[^a-zA-Z]"+m[n].abbreviations.trillion+"(?:\\)|(\\"+m[n].currency.symbol+")?(?:\\))?)?$"),g=0;g<=j.length&&!(k=b.indexOf(j[g])>-1?Math.pow(1024,g+1):!1);g++);a._value=(k?k:1)*(i.match(c)?Math.pow(10,3):1)*(i.match(d)?Math.pow(10,6):1)*(i.match(e)?Math.pow(10,9):1)*(i.match(f)?Math.pow(10,12):1)*(b.indexOf("%")>-1?.01:1)*((b.split("-").length+Math.min(b.split("(").length-1,b.split(")").length-1))%2?1:-1)*Number(b.replace(/[^0-9\.]+/g,"")),a._value=k?Math.ceil(a._value):a._value}return a._value}function e(a,b,c){var d,e=b.indexOf("$")<=1?!0:!1,f="";return b.indexOf(" $")>-1?(f=" ",b=b.replace(" $","")):b.indexOf("$ ")>-1?(f=" ",b=b.replace("$ ","")):b=b.replace("$",""),d=i(a._value,b,c),e?d.indexOf("(")>-1||d.indexOf("-")>-1?(d=d.split(""),d.splice(1,0,m[n].currency.symbol+f),d=d.join("")):d=m[n].currency.symbol+f+d:d.indexOf(")")>-1?(d=d.split(""),d.splice(-1,0,f+m[n].currency.symbol),d=d.join("")):d=d+f+m[n].currency.symbol,d}function f(a,b,c){var d,e="",f=100*a._value;return b.indexOf(" %")>-1?(e=" ",b=b.replace(" %","")):b=b.replace("%",""),d=i(f,b,c),d.indexOf(")")>-1?(d=d.split(""),d.splice(-1,0,e+"%"),d=d.join("")):d=d+e+"%",d}function g(a){var b=Math.floor(a._value/60/60),c=Math.floor((a._value-60*60*b)/60),d=Math.round(a._value-60*60*b-60*c);return b+":"+(10>c?"0"+c:c)+":"+(10>d?"0"+d:d)}function h(a){var b=a.split(":"),c=0;return 3===b.length?(c+=60*60*Number(b[0]),c+=60*Number(b[1]),c+=Number(b[2])):2===b.length&&(c+=60*Number(b[0]),c+=Number(b[1])),Number(c)}function i(a,c,d){var e,f,g,h,i,j,k=!1,l=!1,p=!1,q="",r="",s="",t=Math.abs(a),u=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],v="",w=!1;if(0===a&&null!==o)return o;if(c.indexOf("(")>-1?(k=!0,c=c.slice(1,-1)):c.indexOf("+")>-1&&(l=!0,c=c.replace(/\+/g,"")),c.indexOf("a")>-1&&(c.indexOf(" a")>-1?(q=" ",c=c.replace(" a","")):c=c.replace("a",""),t>=Math.pow(10,12)?(q+=m[n].abbreviations.trillion,a/=Math.pow(10,12)):t=Math.pow(10,9)?(q+=m[n].abbreviations.billion,a/=Math.pow(10,9)):t=Math.pow(10,6)?(q+=m[n].abbreviations.million,a/=Math.pow(10,6)):t=Math.pow(10,3)&&(q+=m[n].abbreviations.thousand,a/=Math.pow(10,3))),c.indexOf("b")>-1)for(c.indexOf(" b")>-1?(r=" ",c=c.replace(" b","")):c=c.replace("b",""),g=0;g<=u.length;g++)if(e=Math.pow(1024,g),f=Math.pow(1024,g+1),a>=e&&f>a){r+=u[g],e>0&&(a/=e);break}return c.indexOf("o")>-1&&(c.indexOf(" o")>-1?(s=" ",c=c.replace(" o","")):c=c.replace("o",""),s+=m[n].ordinal(a)),c.indexOf("[.]")>-1&&(p=!0,c=c.replace("[.]",".")),h=a.toString().split(".")[0],i=c.split(".")[1],j=c.indexOf(","),i?(i.indexOf("[")>-1?(i=i.replace("]",""),i=i.split("["),v=b(a,i[0].length+i[1].length,d,i[1].length)):v=b(a,i.length,d),h=v.split(".")[0],v=v.split(".")[1].length?m[n].delimiters.decimal+v.split(".")[1]:"",p&&0===Number(v.slice(1))&&(v="")):h=b(a,null,d),h.indexOf("-")>-1&&(h=h.slice(1),w=!0),j>-1&&(h=h.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+m[n].delimiters.thousands)),0===c.indexOf(".")&&(h=""),(k&&w?"(":"")+(!k&&w?"-":"")+(!w&&l?"+":"")+h+v+(s?s:"")+(q?q:"")+(r?r:"")+(k&&w?")":"")}function j(a,b){m[a]=b}var k,l="1.5.2",m={},n="en",o=null,p="0,0",q="undefined"!=typeof module&&module.exports;k=function(b){return k.isNumeral(b)?b=b.value():0===b||"undefined"==typeof b?b=0:Number(b)||(b=k.fn.unformat(b)),new a(Number(b))},k.version=l,k.isNumeral=function(b){return b instanceof a},k.language=function(a,b){if(!a)return n;if(a&&!b){if(!m[a])throw new Error("Unknown language : "+a);n=a}return(b||!m[a])&&j(a,b),k},k.languageData=function(a){if(!a)return m[n];if(!m[a])throw new Error("Unknown language : "+a);return m[a]},k.language("en",{delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"},currency:{symbol:"$"}}),k.zeroFormat=function(a){o="string"==typeof a?a:null},k.defaultFormat=function(a){p="string"==typeof a?a:"0.0"},k.fn=a.prototype={clone:function(){return k(this)},format:function(a,b){return c(this,a?a:p,void 0!==b?b:Math.round)},unformat:function(a){return"[object Number]"===Object.prototype.toString.call(a)?a:d(this,a?a:p)},value:function(){return this._value},valueOf:function(){return this._value},set:function(a){return this._value=Number(a),this},add:function(a){return this._value=this._value+Number(a),this},subtract:function(a){return this._value=this._value-Number(a),this},multiply:function(a){return this._value=this._value*Number(a),this},divide:function(a){return this._value=this._value/Number(a),this},difference:function(a){var b=this._value-Number(a);return 0>b&&(b=-b),b}},q&&(module.exports=k),"undefined"==typeof ender&&(this.numeral=k),"function"==typeof define&&define.amd&&define([],function(){return k})}).call(this); \ No newline at end of file +(function(){function a(a){this._value=a}function b(a,b,c,d){var e,f,g=Math.pow(10,b);return f=(c(a*g)/g).toFixed(b),d&&(e=new RegExp("0{1,"+d+"}$"),f=f.replace(e,"")),f}function c(a,b,c){var d;return d=b.indexOf("$")>-1?e(a,b,c):b.indexOf("%")>-1?f(a,b,c):b.indexOf(":")>-1?g(a,b):i(a._value,b,c)}function d(a,b){var c,d,e,f,g,i=b,j=["KB","MB","GB","TB","PB","EB","ZB","YB"],k=!1;if(b.indexOf(":")>-1)a._value=h(b);else if(b===q)a._value=0;else{for("."!==o[p].delimiters.decimal&&(b=b.replace(/\./g,"").replace(o[p].delimiters.decimal,".")),c=new RegExp("[^a-zA-Z]"+o[p].abbreviations.thousand+"(?:\\)|(\\"+o[p].currency.symbol+")?(?:\\))?)?$"),d=new RegExp("[^a-zA-Z]"+o[p].abbreviations.million+"(?:\\)|(\\"+o[p].currency.symbol+")?(?:\\))?)?$"),e=new RegExp("[^a-zA-Z]"+o[p].abbreviations.billion+"(?:\\)|(\\"+o[p].currency.symbol+")?(?:\\))?)?$"),f=new RegExp("[^a-zA-Z]"+o[p].abbreviations.trillion+"(?:\\)|(\\"+o[p].currency.symbol+")?(?:\\))?)?$"),g=0;g<=j.length&&!(k=b.indexOf(j[g])>-1?Math.pow(1024,g+1):!1);g++);a._value=(k?k:1)*(i.match(c)?Math.pow(10,3):1)*(i.match(d)?Math.pow(10,6):1)*(i.match(e)?Math.pow(10,9):1)*(i.match(f)?Math.pow(10,12):1)*(b.indexOf("%")>-1?.01:1)*((b.split("-").length+Math.min(b.split("(").length-1,b.split(")").length-1))%2?1:-1)*Number(b.replace(/[^0-9\.]+/g,"")),a._value=k?Math.ceil(a._value):a._value}return a._value}function e(a,b,c){var d,e,f=b.indexOf("$"),g=b.indexOf("("),h=b.indexOf("-"),j="";return b.indexOf(" $")>-1?(j=" ",b=b.replace(" $","")):b.indexOf("$ ")>-1?(j=" ",b=b.replace("$ ","")):b=b.replace("$",""),e=i(a._value,b,c),1>=f?e.indexOf("(")>-1||e.indexOf("-")>-1?(e=e.split(""),d=1,(g>f||h>f)&&(d=0),e.splice(d,0,o[p].currency.symbol+j),e=e.join("")):e=o[p].currency.symbol+j+e:e.indexOf(")")>-1?(e=e.split(""),e.splice(-1,0,j+o[p].currency.symbol),e=e.join("")):e=e+j+o[p].currency.symbol,e}function f(a,b,c){var d,e="",f=100*a._value;return b.indexOf(" %")>-1?(e=" ",b=b.replace(" %","")):b=b.replace("%",""),d=i(f,b,c),d.indexOf(")")>-1?(d=d.split(""),d.splice(-1,0,e+"%"),d=d.join("")):d=d+e+"%",d}function g(a){var b=Math.floor(a._value/60/60),c=Math.floor((a._value-60*b*60)/60),d=Math.round(a._value-60*b*60-60*c);return b+":"+(10>c?"0"+c:c)+":"+(10>d?"0"+d:d)}function h(a){var b=a.split(":"),c=0;return 3===b.length?(c+=60*Number(b[0])*60,c+=60*Number(b[1]),c+=Number(b[2])):2===b.length&&(c+=60*Number(b[0]),c+=Number(b[1])),Number(c)}function i(a,c,d){var e,f,g,h,i,j,k=!1,l=!1,m=!1,n="",r=!1,s=!1,t=!1,u=!1,v=!1,w="",x="",y=Math.abs(a),z=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],A="",B=!1;if(0===a&&null!==q)return q;if(c.indexOf("(")>-1?(k=!0,c=c.slice(1,-1)):c.indexOf("+")>-1&&(l=!0,c=c.replace(/\+/g,"")),c.indexOf("a")>-1&&(r=c.indexOf("aK")>=0,s=c.indexOf("aM")>=0,t=c.indexOf("aB")>=0,u=c.indexOf("aT")>=0,v=r||s||t||u,c.indexOf(" a")>-1?(n=" ",c=c.replace(" a","")):c=c.replace("a",""),y>=Math.pow(10,12)&&!v||u?(n+=o[p].abbreviations.trillion,a/=Math.pow(10,12)):y=Math.pow(10,9)&&!v||t?(n+=o[p].abbreviations.billion,a/=Math.pow(10,9)):y=Math.pow(10,6)&&!v||s?(n+=o[p].abbreviations.million,a/=Math.pow(10,6)):(y=Math.pow(10,3)&&!v||r)&&(n+=o[p].abbreviations.thousand,a/=Math.pow(10,3))),c.indexOf("b")>-1)for(c.indexOf(" b")>-1?(w=" ",c=c.replace(" b","")):c=c.replace("b",""),g=0;g<=z.length;g++)if(e=Math.pow(1024,g),f=Math.pow(1024,g+1),a>=e&&f>a){w+=z[g],e>0&&(a/=e);break}return c.indexOf("o")>-1&&(c.indexOf(" o")>-1?(x=" ",c=c.replace(" o","")):c=c.replace("o",""),x+=o[p].ordinal(a)),c.indexOf("[.]")>-1&&(m=!0,c=c.replace("[.]",".")),h=a.toString().split(".")[0],i=c.split(".")[1],j=c.indexOf(","),i?(i.indexOf("[")>-1?(i=i.replace("]",""),i=i.split("["),A=b(a,i[0].length+i[1].length,d,i[1].length)):A=b(a,i.length,d),h=A.split(".")[0],A=A.split(".")[1].length?o[p].delimiters.decimal+A.split(".")[1]:"",m&&0===Number(A.slice(1))&&(A="")):h=b(a,null,d),h.indexOf("-")>-1&&(h=h.slice(1),B=!0),j>-1&&(h=h.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+o[p].delimiters.thousands)),0===c.indexOf(".")&&(h=""),(k&&B?"(":"")+(!k&&B?"-":"")+(!B&&l?"+":"")+h+A+(x?x:"")+(n?n:"")+(w?w:"")+(k&&B?")":"")}function j(a,b){o[a]=b}function k(a){var b=a.toString().split(".");return b.length<2?1:Math.pow(10,b[1].length)}function l(){var a=Array.prototype.slice.call(arguments);return a.reduce(function(a,b){var c=k(a),d=k(b);return c>d?c:d},-1/0)}var m,n="1.5.3",o={},p="en",q=null,r="0,0",s="undefined"!=typeof module&&module.exports;m=function(b){return m.isNumeral(b)?b=b.value():0===b||"undefined"==typeof b?b=0:Number(b)||(b=m.fn.unformat(b)),new a(Number(b))},m.version=n,m.isNumeral=function(b){return b instanceof a},m.language=function(a,b){if(!a)return p;if(a&&!b){if(!o[a])throw new Error("Unknown language : "+a);p=a}return(b||!o[a])&&j(a,b),m},m.languageData=function(a){if(!a)return o[p];if(!o[a])throw new Error("Unknown language : "+a);return o[a]},m.language("en",{delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"},currency:{symbol:"$"}}),m.zeroFormat=function(a){q="string"==typeof a?a:null},m.defaultFormat=function(a){r="string"==typeof a?a:"0.0"},"function"!=typeof Array.prototype.reduce&&(Array.prototype.reduce=function(a,b){"use strict";if(null===this||"undefined"==typeof this)throw new TypeError("Array.prototype.reduce called on null or undefined");if("function"!=typeof a)throw new TypeError(a+" is not a function");var c,d,e=this.length>>>0,f=!1;for(1c;++c)this.hasOwnProperty(c)&&(f?d=a(d,this[c],c,this):(d=this[c],f=!0));if(!f)throw new TypeError("Reduce of empty array with no initial value");return d}),m.fn=a.prototype={clone:function(){return m(this)},format:function(a,b){return c(this,a?a:r,void 0!==b?b:Math.round)},unformat:function(a){return"[object Number]"===Object.prototype.toString.call(a)?a:d(this,a?a:r)},value:function(){return this._value},valueOf:function(){return this._value},set:function(a){return this._value=Number(a),this},add:function(a){function b(a,b){return a+c*b}var c=l.call(null,this._value,a);return this._value=[this._value,a].reduce(b,0)/c,this},subtract:function(a){function b(a,b){return a-c*b}var c=l.call(null,this._value,a);return this._value=[a].reduce(b,this._value*c)/c,this},multiply:function(a){function b(a,b){var c=l(a,b);return a*c*b*c/(c*c)}return this._value=[this._value,a].reduce(b,1),this},divide:function(a){function b(a,b){var c=l(a,b);return a*c/(b*c)}return this._value=[this._value,a].reduce(b),this},difference:function(a){return Math.abs(m(this._value).subtract(a).value())}},s&&(module.exports=m),"undefined"==typeof ender&&(this.numeral=m),"function"==typeof define&&define.amd&&define([],function(){return m})}).call(this); \ No newline at end of file diff --git a/numeral.js b/numeral.js index 20b51401..9f46ab65 100644 --- a/numeral.js +++ b/numeral.js @@ -1,6 +1,6 @@ /*! * numeral.js - * version : 1.5.2 + * version : 1.5.3 * author : Adam Draper * license : MIT * http://adamwdraper.github.com/Numeral-js/ @@ -13,7 +13,7 @@ ************************************/ var numeral, - VERSION = '1.5.2', + VERSION = '1.5.3', // internal storage for language config files languages = {}, currentLanguage = 'en', @@ -126,8 +126,11 @@ } function formatCurrency (n, format, roundingFunction) { - var prependSymbol = format.indexOf('$') <= 1 ? true : false, + var symbolIndex = format.indexOf('$'), + openParenIndex = format.indexOf('('), + minusSignIndex = format.indexOf('-'), space = '', + spliceIndex, output; // check for space before or after currency @@ -145,10 +148,15 @@ output = formatNumber(n._value, format, roundingFunction); // position the symbol - if (prependSymbol) { + if (symbolIndex <= 1) { if (output.indexOf('(') > -1 || output.indexOf('-') > -1) { output = output.split(''); - output.splice(1, 0, languages[currentLanguage].currency.symbol + space); + spliceIndex = 1; + if (symbolIndex < openParenIndex || symbolIndex < minusSignIndex){ + // the symbol appears before the "(" or "-" + spliceIndex = 0; + } + output.splice(spliceIndex, 0, languages[currentLanguage].currency.symbol + space); output = output.join(''); } else { output = languages[currentLanguage].currency.symbol + space + output; @@ -224,6 +232,11 @@ signed = false, optDec = false, abbr = '', + abbrK = false, // force abbreviation to thousands + abbrM = false, // force abbreviation to millions + abbrB = false, // force abbreviation to billions + abbrT = false, // force abbreviation to trillions + abbrForce = false, // force abbreviation bytes = '', ord = '', abs = Math.abs(value), @@ -253,6 +266,13 @@ // see if abbreviation is wanted if (format.indexOf('a') > -1) { + // check if abbreviation is specified + abbrK = format.indexOf('aK') >= 0; + abbrM = format.indexOf('aM') >= 0; + abbrB = format.indexOf('aB') >= 0; + abbrT = format.indexOf('aT') >= 0; + abbrForce = abbrK || abbrM || abbrB || abbrT; + // check for space before abbreviation if (format.indexOf(' a') > -1) { abbr = ' '; @@ -261,19 +281,19 @@ format = format.replace('a', ''); } - if (abs >= Math.pow(10, 12)) { + if (abs >= Math.pow(10, 12) && !abbrForce || abbrT) { // trillion abbr = abbr + languages[currentLanguage].abbreviations.trillion; value = value / Math.pow(10, 12); - } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9)) { + } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9) && !abbrForce || abbrB) { // billion abbr = abbr + languages[currentLanguage].abbreviations.billion; value = value / Math.pow(10, 9); - } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6)) { + } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6) && !abbrForce || abbrM) { // million abbr = abbr + languages[currentLanguage].abbreviations.million; value = value / Math.pow(10, 6); - } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3)) { + } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3) && !abbrForce || abbrK) { // thousand abbr = abbr + languages[currentLanguage].abbreviations.thousand; value = value / Math.pow(10, 3); @@ -468,6 +488,89 @@ languages[key] = values; } + /************************************ + Floating-point helpers + ************************************/ + + // The floating-point helper functions and implementation + // borrows heavily from sinful.js: http://guipn.github.io/sinful.js/ + + /** + * Array.prototype.reduce for browsers that don't support it + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility + */ + if ('function' !== typeof Array.prototype.reduce) { + Array.prototype.reduce = function (callback, opt_initialValue) { + 'use strict'; + + if (null === this || 'undefined' === typeof this) { + // At the moment all modern browsers, that support strict mode, have + // native implementation of Array.prototype.reduce. For instance, IE8 + // does not support strict mode, so this check is actually useless. + throw new TypeError('Array.prototype.reduce called on null or undefined'); + } + + if ('function' !== typeof callback) { + throw new TypeError(callback + ' is not a function'); + } + + var index, + value, + length = this.length >>> 0, + isValueSet = false; + + if (1 < arguments.length) { + value = opt_initialValue; + isValueSet = true; + } + + for (index = 0; length > index; ++index) { + if (this.hasOwnProperty(index)) { + if (isValueSet) { + value = callback(value, this[index], index, this); + } else { + value = this[index]; + isValueSet = true; + } + } + } + + if (!isValueSet) { + throw new TypeError('Reduce of empty array with no initial value'); + } + + return value; + }; + } + + + /** + * Computes the multiplier necessary to make x >= 1, + * effectively eliminating miscalculations caused by + * finite precision. + */ + function multiplier(x) { + var parts = x.toString().split('.'); + if (parts.length < 2) { + return 1; + } + return Math.pow(10, parts[1].length); + } + + /** + * Given a variable number of arguments, returns the maximum + * multiplier that must be used to normalize an operation involving + * all of them. + */ + function correctionFactor() { + var args = Array.prototype.slice.call(arguments); + return args.reduce(function (prev, next) { + var mp = multiplier(prev), + mn = multiplier(next); + return mp > mn ? mp : mn; + }, -Infinity); + } + /************************************ Numeral Prototype @@ -508,33 +611,44 @@ }, add : function (value) { - this._value = this._value + Number(value); + var corrFactor = correctionFactor.call(null, this._value, value); + function cback(accum, curr, currI, O) { + return accum + corrFactor * curr; + } + this._value = [this._value, value].reduce(cback, 0) / corrFactor; return this; }, subtract : function (value) { - this._value = this._value - Number(value); + var corrFactor = correctionFactor.call(null, this._value, value); + function cback(accum, curr, currI, O) { + return accum - corrFactor * curr; + } + this._value = [value].reduce(cback, this._value * corrFactor) / corrFactor; return this; }, multiply : function (value) { - this._value = this._value * Number(value); + function cback(accum, curr, currI, O) { + var corrFactor = correctionFactor(accum, curr); + return (accum * corrFactor) * (curr * corrFactor) / + (corrFactor * corrFactor); + } + this._value = [this._value, value].reduce(cback, 1); return this; }, divide : function (value) { - this._value = this._value / Number(value); + function cback(accum, curr, currI, O) { + var corrFactor = correctionFactor(accum, curr); + return (accum * corrFactor) / (curr * corrFactor); + } + this._value = [this._value, value].reduce(cback); return this; }, difference : function (value) { - var difference = this._value - Number(value); - - if (difference < 0) { - difference = -difference; - } - - return difference; + return Math.abs(numeral(this._value).subtract(value).value()); } }; diff --git a/package.json b/package.json index 3cce61f3..5e80aef9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "numeral", - "version": "1.5.2", + "version": "1.5.3", "description": "Format and manipulate numbers.", "homepage": "http://numeraljs.com", "author": { @@ -40,6 +40,9 @@ "grunt-contrib-nodeunit": "~0.1.2", "grunt-contrib-concat": "~0.3.0" }, + "scripts": { + "test": "grunt" + }, "ender": "./ender.js", "readme": "[Numeral.js](http://numeraljs.com)\n=======================================================\n\nA javascript library for formatting and manipulating numbers.\n\n[Website and documentation](http://numeraljs.com)\n\nChangelog\n=========\n\n### 1.5.2\nBug fix: Unformat should pass through if given a number\n\nAdded a mechanism to control rounding behaviour\n\nAdded languageData() for getting and setting language props at runtime### 1.5.1\nBug fix: Make sure values aren't changed during formatting### 1.5.0\nAdd defaultFormat(). numeral().format() uses the default to format if no string is provided\n\n.unformat() returns 0 when passed no string\n\nAdded languages.js that contains all languages\n\nBug fix: Fix bug while unformatting ordinals\n\nAdd format option to always show signed value\n\nAdded ability to instantiate numeral with a string value of a number\n### 1.4.9\nBug fix: Fix bug while unformatting ordinals\n### 1.4.8\nBug fix: Throw error if language is not defined\n### 1.4.7\nBug fix: Fix typo for trillion\n### 1.4.6\nBug fix: remove ' from unformatting regex that was causing an error with fr-ch.js\n### 1.4.5\nAdd zeroFormat() function that accepts a string for custom formating of zeros\n\nAdd valueOf() function\n\nChain functionality to language function\n\nMake all minified files have the same .min.js filename ending\n### 1.4.1\nBug fix: Bytes not formatting correctly\n### 1.4.0\nAdd optional format for all decimals\n### 1.3.4\nRemove AMD module id. (This is encouraged by require.js to make the module more portable, and keep it from creating a global)\n### 1.3.3\nAMD define() compatibility.\n### 1.3.2\nBug fix: Formatting some numbers results in the wrong value. Issue #21\n### 1.3.1\nBug fix: Minor fix to unformatting parser\n### 1.3.0\nAdd support for spaces before/after $, a, o, b in a format string\nBug fix: Fix unformat for languages that use '.' in ordinals\nBug fix: Fix round up floating numbers with no precision correctly.\nBug fix: Fix currency signs at the end in unformat\n### 1.2.6\nAdd support for optional decimal places\n### 1.2.5\nAdd support for appending currency symbol\n### 1.2.4\nAdd support for humanized filesizes\n### 1.2.2\nChanged language definition property 'money' to 'currency'\n### 1.2.1\nBug fix: Fix unformatting non-negative abbreviations\n### 1.2.3\nBug Fix: Fix unformatting for languages that use '.' as thousands delimiter\n### 1.2.0\nAdd localization language support\n\nUpdate testing for to include languages\n### 1.1.0\nAdd Tests\n\nBug fix: Fix difference returning negative values\n### 1.0.4\nBug fix: Non negative numbers were displaying as negative when using parentheses\n### 1.0.3\nAdd ordinal formatting using 'o' in the format\n### 1.0.2\nAdd clone functionality\n### 1.0.1\n\nAdded abbreviations for thousands and millions using 'a' in the format\n\n### 1.0.0\n\nInitial release\n\nAcknowlegements\n===============\n\nNumeral.js, while less complex, was inspired by and heavily borrowed from [Moment.js](http://momentjs.com)\n\nLicense\n=======\nNumeral.js is freely distributable under the terms of the MIT license.\nCopyright (c) 2012 Adam Draper\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use,copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", "_id": "numeral@1.5.2", diff --git a/tests/languages/chs.js b/tests/languages/chs.js new file mode 100644 index 00000000..c9afe9f2 --- /dev/null +++ b/tests/languages/chs.js @@ -0,0 +1,101 @@ +var numeral = require('../../numeral'); +var language = require('../../languages/chs'); + +numeral.language('chs', language); + +exports['language:chs'] = { + setUp: function (callback) { + numeral.language('chs'); + callback(); + }, + + tearDown: function (callback) { + numeral.language('en'); + callback(); + }, + + format: function (test) { + test.expect(16); + + var tests = [ + [10000,'0,0.0000','10,000.0000'], + [10000.23,'0,0','10,000'], + [-10000,'0,0.0','-10,000.0'], + [10000.1234,'0.000','10000.123'], + [-10000,'(0,0.0000)','(10,000.0000)'], + [-0.23,'.00','-.23'], + [-0.23,'(.00)','(.23)'], + [0.23,'0.00000','0.23000'], + [1230974,'0.0a','1.2百万'], + [1460,'0a','1千'], + [-104000,'0a','-104千'], + [1,'0o','1.'], + [52,'0o','52.'], + [23,'0o','23.'], + [100,'0o','100.'], + [1,'0[.]0','1'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + currency: function (test) { + test.expect(4); + + var tests = [ + [1000.234,'$0,0.00','¥1,000.23'], + [-1000.234,'($0,0)','(¥1,000)'], + [-1000.234,'$0.00','-¥1000.23'], + [1230974,'($0.00a)','¥1.23百万'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + percentages: function (test) { + test.expect(4); + + var tests = [ + [1,'0%','100%'], + [0.974878234,'0.000%','97.488%'], + [-0.43,'0%','-43%'], + [0.43,'(0.000%)','43.000%'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + unformat: function (test) { + test.expect(9); + + var tests = [ + ['10,000.123',10000.123], + ['(0.12345)',-0.12345], + ['(¥1.23百万)',-1230000], + ['10千',10000], + ['-10千',-10000], + ['23.',23], + ['¥10,000.00',10000], + ['-76%',-0.76], + ['2:23:57',8637] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral().unformat(tests[i][0]), tests[i][1], tests[i][0]); + } + + test.done(); + } +}; \ No newline at end of file diff --git a/tests/languages/et.js b/tests/languages/et.js new file mode 100644 index 00000000..1f1e54a3 --- /dev/null +++ b/tests/languages/et.js @@ -0,0 +1,101 @@ +var numeral = require('../../numeral'), + language = require('../../languages/et'); + +numeral.language('et', language); + +exports['language:et'] = { + setUp: function (callback) { + numeral.language('et'); + callback(); + }, + + tearDown: function (callback) { + numeral.language('en'); + callback(); + }, + + format: function (test) { + test.expect(16); + + var tests = [ + [10000,'0,0.0000','10 000,0000'], + [10000.23,'0,0','10 000'], + [-10000,'0,0.0','-10 000,0'], + [10000.1234,'0.000','10000,123'], + [-10000,'(0,0.0000)','(10 000,0000)'], + [-0.23,'.00','-,23'], + [-0.23,'(.00)','(,23)'], + [0.23,'0.00000','0,23000'], + [1230974,'0.0a','1,2 mln'], + [1460,'0a','1 tuh'], + [-104000,'0a','-104 tuh'], + [1,'0o','1.'], + [52,'0o','52.'], + [23,'0o','23.'], + [100,'0o','100.'], + [1,'0[.]0','1'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + currency: function (test) { + test.expect(4); + + var tests = [ + [1000.234,'$0,0.00','€1 000,23'], + [-1000.234,'($0,0)','(€1 000)'], + [-1000.234,'$0.00','-€1000,23'], + [1230974,'($0.00a)','€1,23 mln'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + percentages: function (test) { + test.expect(4); + + var tests = [ + [1,'0%','100%'], + [0.974878234,'0.000%','97,488%'], + [-0.43,'0%','-43%'], + [0.43,'(0.000%)','43,000%'] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral(tests[i][0]).format(tests[i][1]), tests[i][2], tests[i][1]); + } + + test.done(); + }, + + unformat: function (test) { + test.expect(9); + + var tests = [ + ['10.000,123',10000.123], + ['(0,12345)',-0.12345], + ['(€1,23 mln)',-1230000], + ['10 tuh',10000], + ['-10 tuh',-10000], + ['23.',23], + ['€10.000,00',10000], + ['-76%',-0.76], + ['2:23:57',8637] + ]; + + for (var i = 0; i < tests.length; i++) { + test.strictEqual(numeral().unformat(tests[i][0]), tests[i][1], tests[i][0]); + } + + test.done(); + } +}; \ No newline at end of file diff --git a/tests/numeral/format.js b/tests/numeral/format.js index f5754067..53427ad4 100644 --- a/tests/numeral/format.js +++ b/tests/numeral/format.js @@ -64,7 +64,13 @@ exports.format = { [1,'0o','1st'], [52,'0 o','52 nd'], [23,'0o','23rd'], - [100,'0o','100th'] + [100,'0o','100th'], + + // specified abbreviations + [-5444333222111, '0,0 aK', '-5,444,333,222 k'], + [-5444333222111, '0,0 aM', '-5,444,333 m'], + [-5444333222111, '0,0 aB', '-5,444 b'], + [-5444333222111, '0,0 aT', '-5 t'] ], i; @@ -85,7 +91,24 @@ exports.format = { [-1000.234,'($0,0)','($1,000)'], [-1000.234,'(0,0$)','(1,000$)'], [-1000.234,'$0.00','-$1000.23'], - [1230974,'($0.00 a)','$1.23 m'] + [1230974,'($0.00 a)','$1.23 m'], + + // test symbol position before negative sign / open parens + [-1000.234,'$ (0,0)','$ (1,000)'], + [-1000.234,'$(0,0)','$(1,000)'], + [-1000.234,'$ (0,0.00)','$ (1,000.23)'], + [-1000.234,'$(0,0.00)','$(1,000.23)'], + [-1000.238,'$(0,0.00)','$(1,000.24)'], + [-1000.234,'$-0,0','$-1,000'], + [-1000.234,'$ -0,0','$ -1,000'], + + [1000.234,'$ (0,0)','$ 1,000'], + [1000.234,'$(0,0)','$1,000'], + [1000.234,'$ (0,0.00)','$ 1,000.23'], + [1000.234,'$(0,0.00)','$1,000.23'], + [1000.238,'$(0,0.00)','$1,000.24'], + [1000.234,'$-0,0)','$1,000'], + [1000.234,'$ -0,0','$ 1,000'] ], i; diff --git a/tests/numeral/manipulate.js b/tests/numeral/manipulate.js index 2930475d..bddd52e8 100644 --- a/tests/numeral/manipulate.js +++ b/tests/numeral/manipulate.js @@ -3,12 +3,13 @@ var numeral = require('../../numeral'); exports.manipulate = { add: function (test) { - test.expect(3); + test.expect(4); var tests = [ [1000,10,1010], [0.5,3,3.5], - [-100,200,100] + [-100,200,100], + [0.1,0.2,0.3] ], num; @@ -22,12 +23,13 @@ exports.manipulate = { }, subtract: function (test) { - test.expect(3); + test.expect(4); var tests = [ [1000,10,990], [0.5,3,-2.5], - [-100,200,-300] + [-100,200,-300], + [0.3,0.1,0.2] ], num; @@ -41,12 +43,13 @@ exports.manipulate = { }, multiply: function (test) { - test.expect(3); + test.expect(4); var tests = [ [1000,10,10000], [0.5,3,1.5], - [-100,200,-20000] + [-100,200,-20000], + [0.1,0.2,0.02] ], num; @@ -60,12 +63,13 @@ exports.manipulate = { }, divide: function (test) { - test.expect(3); + test.expect(4); var tests = [ [1000,10,100], [0.5,3,0.16666666666666666], - [-100,200,-0.5] + [-100,200,-0.5], + [5.3,0.1,53] ], num; @@ -79,12 +83,13 @@ exports.manipulate = { }, difference: function (test) { - test.expect(3); + test.expect(4); var tests = [ [1000,10,990], [0.5,3,2.5], - [-100,200,300] + [-100,200,300], + [0.3,0.2,0.1] ], num;