kivi.js: format/round/parse_amount, format/parse_date
authorMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 23 Feb 2015 13:49:39 +0000 (14:49 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Thu, 2 Apr 2015 12:02:52 +0000 (14:02 +0200)
js/kivi.js
js/t/kivi/format_amount.js [new file with mode: 0644]
js/t/kivi/parse_amount.js [new file with mode: 0644]
js/t/kivi/parse_format_date.js [new file with mode: 0644]
js/t/kivi/round_amount.js [new file with mode: 0644]
js/t/kivi/setup_formats.js [new file with mode: 0644]
templates/webpages/layout/javascript_setup.js

index b04a88c..0a84e88 100644 (file)
@@ -1,5 +1,114 @@
 namespace("kivi", function(ns) {
   ns._locale = {};
+  ns._date_format   = {
+    sep: '.',
+    y:   2,
+    m:   1,
+    d:   0
+  };
+  ns._number_format = {
+    decimalSep:  ',',
+    thousandSep: '.'
+  };
+
+  ns.setup_formats = function(params) {
+    var res = (params.dates || "").match(/^([ymd]+)([^a-z])([ymd]+)[^a-z]([ymd]+)$/);
+    if (res) {
+      ns._date_format                      = { sep: res[2] };
+      ns._date_format[res[1].substr(0, 1)] = 0;
+      ns._date_format[res[3].substr(0, 1)] = 1;
+      ns._date_format[res[4].substr(0, 1)] = 2;
+    }
+
+    res = (params.numbers || "").match(/^\d*([^\d]?)\d+([^\d])\d+$/);
+    if (res)
+      ns._number_format = {
+        decimalSep:  res[2],
+        thousandSep: res[1]
+      };
+  };
+
+  ns.parse_date = function(date) {
+    var parts = date.replace(/\s+/g, "").split(ns._date_format.sep);
+    date     = new Date(
+      ((parts[ ns._date_format.y ] || 0) * 1) || (new Date).getFullYear(),
+       (parts[ ns._date_format.m ] || 0) * 1 - 1, // Months are 0-based.
+       (parts[ ns._date_format.d ] || 0) * 1
+    );
+
+    return isNaN(date.getTime()) ? undefined : date;
+  };
+
+  ns.format_date = function(date) {
+    if (isNaN(date.getTime()))
+      return undefined;
+
+    var parts = [ "", "", "" ]
+    parts[ ns._date_format.y ] = date.getFullYear();
+    parts[ ns._date_format.m ] = (date.getMonth() <  9 ? "0" : "") + (date.getMonth() + 1); // Months are 0-based, but days are 1-based.
+    parts[ ns._date_format.d ] = (date.getDate()  < 10 ? "0" : "") + date.getDate();
+    return parts.join(ns._date_format.sep);
+  };
+
+  ns.parse_amount = function(amount) {
+    if ((amount == undefined) || (amount == ''))
+      return 0;
+
+    if (ns._number_format.decimalSep == ',')
+      amount = amount.replace(/\./g, "").replace(/,/g, ".");
+
+    amount = amount.replace(/[\',]/g, "")
+
+    return eval(amount);
+  };
+
+  ns.round_amount = function(amount, places) {
+    var neg  = amount >= 0 ? 1 : -1;
+    var mult = Math.pow(10, places + 1);
+    var temp = Math.abs(amount) * mult;
+    var diff = Math.abs(1 - temp + Math.floor(temp));
+    temp     = Math.floor(temp) + (diff <= 0.00001 ? 1 : 0);
+    var dec  = temp % 10;
+    temp    += dec >= 5 ? 10 - dec: dec * -1;
+
+    return neg * temp / mult;
+  };
+
+  ns.format_amount = function(amount, places) {
+    amount = amount || 0;
+
+    if ((places != undefined) && (places >= 0))
+      amount = ns.round_amount(amount, Math.abs(places));
+
+    var parts = ("" + Math.abs(amount)).split(/\./);
+    var intg  = parts[0];
+    var dec   = parts.length > 1 ? parts[1] : "";
+    var sign  = amount  < 0      ? "-"      : "";
+
+    if (places != undefined) {
+      while (dec.length < Math.abs(places))
+        dec += "0";
+
+      if ((places > 0) && (dec.length > Math.abs(places)))
+        dec = d.substr(0, places);
+    }
+
+    if ((ns._number_format.thousandSep != "") && (intg.length > 3)) {
+      var len   = ((intg.length + 2) % 3) + 1,
+          start = len,
+          res   = intg.substr(0, len);
+      while (start < intg.length) {
+        res   += ns._number_format.thousandSep + intg.substr(start, 3);
+        start += 3;
+      }
+
+      intg = res;
+    }
+
+    var sep = (places != 0) && (dec != "") ? ns._number_format.decimalSep : "";
+
+    return sign + intg + sep + dec;
+  };
 
   ns.t8 = function(text, params) {
     var text = ns._locale[text] || text;
diff --git a/js/t/kivi/format_amount.js b/js/t/kivi/format_amount.js
new file mode 100644 (file)
index 0000000..bfc093d
--- /dev/null
@@ -0,0 +1,69 @@
+QUnit.test("kivi.format_amount function German number style with thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1.000,00' });
+
+  assert.equal(kivi.format_amount('1e1', 2), '10,00', 'format 1e1');
+  assert.equal(kivi.format_amount(1000, 2), '1.000,00', 'format 1000');
+  assert.equal(kivi.format_amount(1000.1234, 2), '1.000,12', 'format 1000.1234');
+  assert.equal(kivi.format_amount(1000000000.1234, 2), '1.000.000.000,12', 'format 1000000000.1234');
+  assert.equal(kivi.format_amount(-1000000000.1234, 2), '-1.000.000.000,12', 'format -1000000000.1234');
+});
+
+QUnit.test("kivi.format_amount function German number style without thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1000,00' });
+
+  assert.equal(kivi.format_amount('1e1', 2), '10,00', 'format 1e1');
+  assert.equal(kivi.format_amount(1000, 2), '1000,00', 'format 1000');
+  assert.equal(kivi.format_amount(1000.1234, 2), '1000,12', 'format 1000.1234');
+  assert.equal(kivi.format_amount(1000000000.1234, 2), '1000000000,12', 'format 1000000000.1234');
+  assert.equal(kivi.format_amount(-1000000000.1234, 2), '-1000000000,12', 'format -1000000000.1234');
+});
+
+QUnit.test("kivi.format_amount function English number style with thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1,000.00' });
+
+  assert.equal(kivi.format_amount('1e1', 2), '10.00', 'format 1e1');
+  assert.equal(kivi.format_amount(1000, 2), '1,000.00', 'format 1000');
+  assert.equal(kivi.format_amount(1000.1234, 2), '1,000.12', 'format 1000.1234');
+  assert.equal(kivi.format_amount(1000000000.1234, 2), '1,000,000,000.12', 'format 1000000000.1234');
+  assert.equal(kivi.format_amount(-1000000000.1234, 2), '-1,000,000,000.12', 'format -1000000000.1234');
+});
+
+QUnit.test("kivi.format_amount function English number style without thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1000.00' });
+
+  assert.equal(kivi.format_amount('1e1', 2), '10.00', 'format 1e1');
+  assert.equal(kivi.format_amount(1000, 2), '1000.00', 'format 1000');
+  assert.equal(kivi.format_amount(1000.1234, 2), '1000.12', 'format 1000.1234');
+  assert.equal(kivi.format_amount(1000000000.1234, 2), '1000000000.12', 'format 1000000000.1234');
+  assert.equal(kivi.format_amount(-1000000000.1234, 2), '-1000000000.12', 'format -1000000000.1234');
+});
+
+QUnit.test("kivi.format_amount function negative places", function( assert ) {
+  kivi.setup_formats({ numbers: '1000.00' });
+
+  assert.equal(kivi.format_amount(1.00045, -2), '1.00045', 'negative places');
+  assert.equal(kivi.format_amount(1.00045, -5), '1.00045', 'negative places 2');
+  assert.equal(kivi.format_amount(1, -2), '1.00', 'negative places 3');
+});
+
+QUnit.test("kivi.format_amount function bugs and edge cases", function( assert ) {
+  kivi.setup_formats({ numbers: '1.000,00' });
+
+  assert.equal(kivi.format_amount(0.00005), '0,00005', 'messing with small numbers and no precision');
+  assert.equal(kivi.format_amount(undefined), '0', 'undefined');
+  assert.equal(kivi.format_amount(''), '0', 'empty string');
+  assert.equal(kivi.format_amount(undefined, 2), '0,00', 'undefined with precision');
+  assert.equal(kivi.format_amount('', 2), '0,00', 'empty string with prcesion');
+
+  assert.equal(kivi.format_amount(0.545, 0), '1', 'rounding up with precision 0');
+  assert.equal(kivi.format_amount(-0.545, 0), '-1', 'neg rounding up with precision 0');
+
+  assert.equal(kivi.format_amount(1.00), '1', 'autotrim to 0 places');
+
+  assert.equal(kivi.format_amount(10), '10', 'autotrim does not harm integers');
+  assert.equal(kivi.format_amount(10, 2), '10,00' , 'autotrim does not harm integers 2');
+  assert.equal(kivi.format_amount(10, -2), '10,00' , 'autotrim does not harm integers 3');
+  assert.equal(kivi.format_amount(10, 0), '10', 'autotrim does not harm integers 4');
+
+  assert.equal(kivi.format_amount(0, 0), '0' , 'trivial zero');
+});
diff --git a/js/t/kivi/parse_amount.js b/js/t/kivi/parse_amount.js
new file mode 100644 (file)
index 0000000..d0c6e88
--- /dev/null
@@ -0,0 +1,83 @@
+QUnit.test("kivi.parse_amount function German number style with thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1.000,00' });
+
+  assert.equal(kivi.parse_amount('10,00'), 10, '10,00');
+  assert.equal(kivi.parse_amount('10,'), 10, '10,');
+  assert.equal(kivi.parse_amount('1010,00'), 1010, '1010,00');
+  assert.equal(kivi.parse_amount('1010,'), 1010, '1010,');
+  assert.equal(kivi.parse_amount('1.010,00'), 1010, '1.010,00');
+  assert.equal(kivi.parse_amount('1.010,'), 1010, '1.010,');
+  assert.equal(kivi.parse_amount('9.080.070.060.050.040.030.020.010,00'), 9080070060050040030020010, '9.080.070.060.050.040.030.020.010,00');
+  assert.equal(kivi.parse_amount('9.080.070.060.050.040.030.020.010,'), 9080070060050040030020010, '9.080.070.060.050.040.030.020.010,');
+
+  assert.equal(kivi.parse_amount('10,98'), 10.98, '10,98');
+  assert.equal(kivi.parse_amount('1010,98'), 1010.98, '1010,98');
+  assert.equal(kivi.parse_amount('1.010,98'), 1010.98, '1.010,98');
+
+  assert.equal(kivi.parse_amount('10,987654321'), 10.987654321, '10,987654321');
+  assert.equal(kivi.parse_amount('1010,987654321'), 1010.987654321, '1010,987654321');
+  assert.equal(kivi.parse_amount('1.010,987654321'), 1010.987654321, '1.010,987654321');
+});
+
+QUnit.test("kivi.parse_amount function German number style without thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1000,00' });
+
+  assert.equal(kivi.parse_amount('10,00'), 10, '10,00');
+  assert.equal(kivi.parse_amount('10,'), 10, '10,');
+  assert.equal(kivi.parse_amount('1010,00'), 1010, '1010,00');
+  assert.equal(kivi.parse_amount('1010,'), 1010, '1010,');
+  assert.equal(kivi.parse_amount('1.010,00'), 1010, '1.010,00');
+  assert.equal(kivi.parse_amount('1.010,'), 1010, '1.010,');
+  assert.equal(kivi.parse_amount('9.080.070.060.050.040.030.020.010,00'), 9080070060050040030020010, '9.080.070.060.050.040.030.020.010,00');
+  assert.equal(kivi.parse_amount('9.080.070.060.050.040.030.020.010,'), 9080070060050040030020010, '9.080.070.060.050.040.030.020.010,');
+
+  assert.equal(kivi.parse_amount('10,98'), 10.98, '10,98');
+  assert.equal(kivi.parse_amount('1010,98'), 1010.98, '1010,98');
+  assert.equal(kivi.parse_amount('1.010,98'), 1010.98, '1.010,98');
+
+  assert.equal(kivi.parse_amount('10,987654321'), 10.987654321, '10,987654321');
+  assert.equal(kivi.parse_amount('1010,987654321'), 1010.987654321, '1010,987654321');
+  assert.equal(kivi.parse_amount('1.010,987654321'), 1010.987654321, '1.010,987654321');
+});
+
+QUnit.test("kivi.parse_amount function English number style with thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1,000.00' });
+
+  assert.equal(kivi.parse_amount('10.00'), 10, '10.00');
+  assert.equal(kivi.parse_amount('10.'), 10, '10.');
+  assert.equal(kivi.parse_amount('1010.00'), 1010, '1010.00');
+  assert.equal(kivi.parse_amount('1010.'), 1010, '1010.');
+  assert.equal(kivi.parse_amount('1,010.00'), 1010, '1,010.00');
+  assert.equal(kivi.parse_amount('1,010.'), 1010, '1,010.');
+  assert.equal(kivi.parse_amount('9,080,070,060,050,040,030,020,010.00'), 9080070060050040030020010, '9,080,070,060,050,040,030,020,010.00');
+  assert.equal(kivi.parse_amount('9,080,070,060,050,040,030,020,010.'), 9080070060050040030020010, '9,080,070,060,050,040,030,020,010.');
+
+  assert.equal(kivi.parse_amount('10.98'), 10.98, '10.98');
+  assert.equal(kivi.parse_amount('1010.98'), 1010.98, '1010.98');
+  assert.equal(kivi.parse_amount('1,010.98'), 1010.98, '1,010.98');
+
+  assert.equal(kivi.parse_amount('10.987654321'), 10.987654321, '10.987654321');
+  assert.equal(kivi.parse_amount('1010.987654321'), 1010.987654321, '1010.987654321');
+  assert.equal(kivi.parse_amount('1,010.987654321'), 1010.987654321, '1,010.987654321');
+});
+
+QUnit.test("kivi.parse_amount function English number style without thousand separator", function( assert ) {
+  kivi.setup_formats({ numbers: '1000.00' });
+
+  assert.equal(kivi.parse_amount('10.00'), 10, '10.00');
+  assert.equal(kivi.parse_amount('10.'), 10, '10.');
+  assert.equal(kivi.parse_amount('1010.00'), 1010, '1010.00');
+  assert.equal(kivi.parse_amount('1010.'), 1010, '1010.');
+  assert.equal(kivi.parse_amount('1,010.00'), 1010, '1,010.00');
+  assert.equal(kivi.parse_amount('1,010.'), 1010, '1,010.');
+  assert.equal(kivi.parse_amount('9,080,070,060,050,040,030,020,010.00'), 9080070060050040030020010, '9,080,070,060,050,040,030,020,010.00');
+  assert.equal(kivi.parse_amount('9,080,070,060,050,040,030,020,010.'), 9080070060050040030020010, '9,080,070,060,050,040,030,020,010.');
+
+  assert.equal(kivi.parse_amount('10.98'), 10.98, '10.98');
+  assert.equal(kivi.parse_amount('1010.98'), 1010.98, '1010.98');
+  assert.equal(kivi.parse_amount('1,010.98'), 1010.98, '1,010.98');
+
+  assert.equal(kivi.parse_amount('10.987654321'), 10.987654321, '10.987654321');
+  assert.equal(kivi.parse_amount('1010.987654321'), 1010.987654321, '1010.987654321');
+  assert.equal(kivi.parse_amount('1,010.987654321'), 1010.987654321, '1,010.987654321');
+});
diff --git a/js/t/kivi/parse_format_date.js b/js/t/kivi/parse_format_date.js
new file mode 100644 (file)
index 0000000..b488b1e
--- /dev/null
@@ -0,0 +1,104 @@
+QUnit.test("kivi.parse_date function for German date style with dots", function( assert ) {
+  kivi.setup_formats({ dates: "dd.mm.yy" });
+
+  assert.deepEqual(kivi.parse_date("01.01.2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("1.1.2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("      01 .  1. 2007   "), new Date(2007, 0, 1));
+
+  assert.deepEqual(kivi.parse_date("29.02.2008"), new Date(2008, 1, 29));
+
+  assert.deepEqual(kivi.parse_date("11.12.2014"), new Date(2014, 11, 11));
+
+  assert.deepEqual(kivi.parse_date("25.12."), new Date((new Date).getFullYear(), 11, 25));
+  assert.deepEqual(kivi.parse_date("25.12"), new Date((new Date).getFullYear(), 11, 25));
+
+  assert.deepEqual(kivi.parse_date("Totally Invalid!"), undefined);
+});
+
+QUnit.test("kivi.parse_date function for German date style with slashes", function( assert ) {
+  kivi.setup_formats({ dates: "dd/mm/yy" });
+
+  assert.deepEqual(kivi.parse_date("01/01/2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("1/1/2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("      01 /  1/ 2007   "), new Date(2007, 0, 1));
+
+  assert.deepEqual(kivi.parse_date("29/02/2008"), new Date(2008, 1, 29));
+
+  assert.deepEqual(kivi.parse_date("11/12/2014"), new Date(2014, 11, 11));
+
+  assert.deepEqual(kivi.parse_date("25/12/"), new Date((new Date).getFullYear(), 11, 25));
+  assert.deepEqual(kivi.parse_date("25/12"), new Date((new Date).getFullYear(), 11, 25));
+
+  assert.deepEqual(kivi.parse_date("Totally Invalid!"), undefined);
+});
+
+QUnit.test("kivi.parse_date function for American date style", function( assert ) {
+  kivi.setup_formats({ dates: "mm/dd/yy" });
+
+  assert.deepEqual(kivi.parse_date("01/01/2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("1/1/2007"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("      01 /  1/ 2007   "), new Date(2007, 0, 1));
+
+  assert.deepEqual(kivi.parse_date("02/29/2008"), new Date(2008, 1, 29));
+
+  assert.deepEqual(kivi.parse_date("12/11/2014"), new Date(2014, 11, 11));
+
+  assert.deepEqual(kivi.parse_date("12/25/"), new Date((new Date).getFullYear(), 11, 25));
+  assert.deepEqual(kivi.parse_date("12/25"), new Date((new Date).getFullYear(), 11, 25));
+
+  assert.deepEqual(kivi.parse_date("Totally Invalid!"), undefined);
+});
+
+QUnit.test("kivi.parse_date function for ISO date style", function( assert ) {
+  kivi.setup_formats({ dates: "yyyy-mm-dd" });
+
+  assert.deepEqual(kivi.parse_date("2007-01-01"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("2007-1-1"), new Date(2007, 0, 1));
+  assert.deepEqual(kivi.parse_date("      2007 - 1     -01   "), new Date(2007, 0, 1));
+
+  assert.deepEqual(kivi.parse_date("2008-02-29"), new Date(2008, 1, 29));
+
+  assert.deepEqual(kivi.parse_date("2014-12-11"), new Date(2014, 11, 11));
+
+  assert.deepEqual(kivi.parse_date("-12-25"), new Date((new Date).getFullYear(), 11, 25));
+});
+
+QUnit.test("kivi.format_date function for German date style with dots", function( assert ) {
+  kivi.setup_formats({ dates: "dd.mm.yy" });
+
+  assert.deepEqual(kivi.format_date(new Date(2007, 0, 1)), "01.01.2007");
+  assert.deepEqual(kivi.format_date(new Date(2008, 1, 29)), "29.02.2008");
+  assert.deepEqual(kivi.format_date(new Date(2014, 11, 11)), "11.12.2014");
+
+  assert.deepEqual(kivi.format_date(new Date(undefined, undefined, undefined)), undefined);
+});
+
+QUnit.test("kivi.format_date function for German date style with slashes", function( assert ) {
+  kivi.setup_formats({ dates: "dd/mm/yy" });
+
+  assert.deepEqual(kivi.format_date(new Date(2007, 0, 1)), "01/01/2007");
+  assert.deepEqual(kivi.format_date(new Date(2008, 1, 29)), "29/02/2008");
+  assert.deepEqual(kivi.format_date(new Date(2014, 11, 11)), "11/12/2014");
+
+  assert.deepEqual(kivi.format_date(new Date(undefined, undefined, undefined)), undefined);
+});
+
+QUnit.test("kivi.format_date function for American date style", function( assert ) {
+  kivi.setup_formats({ dates: "mm/dd/yy" });
+
+  assert.deepEqual(kivi.format_date(new Date(2007, 0, 1)), "01/01/2007");
+  assert.deepEqual(kivi.format_date(new Date(2008, 1, 29)), "02/29/2008");
+  assert.deepEqual(kivi.format_date(new Date(2014, 11, 11)), "12/11/2014");
+
+  assert.deepEqual(kivi.format_date(new Date(undefined, undefined, undefined)), undefined);
+});
+
+QUnit.test("kivi.format_date function for ISO date style", function( assert ) {
+  kivi.setup_formats({ dates: "yyyy-mm-dd" });
+
+  assert.deepEqual(kivi.format_date(new Date(2007, 0, 1)), "2007-01-01");
+  assert.deepEqual(kivi.format_date(new Date(2008, 1, 29)), "2008-02-29");
+  assert.deepEqual(kivi.format_date(new Date(2014, 11, 11)), "2014-12-11");
+
+  assert.deepEqual(kivi.format_date(new Date(undefined, undefined, undefined)), undefined);
+});
diff --git a/js/t/kivi/round_amount.js b/js/t/kivi/round_amount.js
new file mode 100644 (file)
index 0000000..3e28c79
--- /dev/null
@@ -0,0 +1,115 @@
+QUnit.test("kivi.round_amount function, 0..2 places", function( assert ) {
+  assert.equal(kivi.round_amount(1.05, 2), '1.05', '1.05 @ 2');
+  assert.equal(kivi.round_amount(1.05, 1), '1.1',  '1.05 @ 1');
+  assert.equal(kivi.round_amount(1.05, 0), '1',    '1.05 @ 0');
+
+  assert.equal(kivi.round_amount(1.045, 2), '1.05', '1.045 @ 2');
+  assert.equal(kivi.round_amount(1.045, 1), '1',    '1.045 @ 1');
+  assert.equal(kivi.round_amount(1.045, 0), '1',    '1.045 @ 0');
+
+  assert.equal(kivi.round_amount(33.675, 2), '33.68', '33.675 @ 2');
+  assert.equal(kivi.round_amount(33.675, 1), '33.7',  '33.675 @ 1');
+  assert.equal(kivi.round_amount(33.675, 0), '34',    '33.675 @ 0');
+
+  assert.equal(kivi.round_amount(64.475, 2), '64.48', '64.475 @ 2');
+  assert.equal(kivi.round_amount(64.475, 1), '64.5',  '64.475 @ 1');
+  assert.equal(kivi.round_amount(64.475, 0), '64',    '64.475 @ 0');
+
+  assert.equal(kivi.round_amount(44.9 * 0.75, 2), '33.68', '44.9 * 0.75 @ 2');
+  assert.equal(kivi.round_amount(44.9 * 0.75, 1), '33.7',  '44.9 * 0.75 @ 1');
+  assert.equal(kivi.round_amount(44.9 * 0.75, 0), '34',    '44.9 * 0.75 @ 0');
+
+  assert.equal(kivi.round_amount(143.20, 2), '143.2', '143.20 @ 2');
+  assert.equal(kivi.round_amount(143.20, 1), '143.2', '143.20 @ 1');
+  assert.equal(kivi.round_amount(143.20, 0), '143',   '143.20 @ 0');
+
+  assert.equal(kivi.round_amount(149.175, 2), '149.18', '149.175 @ 2');
+  assert.equal(kivi.round_amount(149.175, 1), '149.2',  '149.175 @ 1');
+  assert.equal(kivi.round_amount(149.175, 0), '149',    '149.175 @ 0');
+
+  assert.equal(kivi.round_amount(198.90 * 0.75, 2), '149.18', '198.90 * 0.75 @ 2');
+  assert.equal(kivi.round_amount(198.90 * 0.75, 1), '149.2',  '198.90 * 0.75 @ 1');
+  assert.equal(kivi.round_amount(198.90 * 0.75, 0), '149',    '198.90 * 0.75 @ 0');
+});
+
+QUnit.test("kivi.round_amount function, 0..5 places", function( assert ) {
+  assert.equal(kivi.round_amount(64.475499, 5), '64.4755', '64.475499 @ 5');
+  assert.equal(kivi.round_amount(64.475499, 4), '64.4755', '64.475499 @ 4');
+  assert.equal(kivi.round_amount(64.475499, 3), '64.475',  '64.475499 @ 3');
+  assert.equal(kivi.round_amount(64.475499, 2), '64.48',   '64.475499 @ 2');
+  assert.equal(kivi.round_amount(64.475499, 1), '64.5',    '64.475499 @ 1');
+  assert.equal(kivi.round_amount(64.475499, 0), '64',      '64.475499 @ 0');
+
+  assert.equal(kivi.round_amount(64.475999, 5), '64.476', '64.475999 @ 5');
+  assert.equal(kivi.round_amount(64.475999, 4), '64.476', '64.475999 @ 4');
+  assert.equal(kivi.round_amount(64.475999, 3), '64.476', '64.475999 @ 3');
+  assert.equal(kivi.round_amount(64.475999, 2), '64.48',  '64.475999 @ 2');
+  assert.equal(kivi.round_amount(64.475999, 1), '64.5',   '64.475999 @ 1');
+  assert.equal(kivi.round_amount(64.475999, 0), '64',     '64.475999 @ 0');
+});
+
+QUnit.test("kivi.round_amount function, negative values", function( assert ) {
+  // Negative values
+  assert.equal(kivi.round_amount(-1.05, 2), '-1.05', '-1.05 @ 2');
+  assert.equal(kivi.round_amount(-1.05, 1), '-1.1',  '-1.05 @ 1');
+  assert.equal(kivi.round_amount(-1.05, 0), '-1',    '-1.05 @ 0');
+
+  assert.equal(kivi.round_amount(-1.045, 2), '-1.05', '-1.045 @ 2');
+  assert.equal(kivi.round_amount(-1.045, 1), '-1',    '-1.045 @ 1');
+  assert.equal(kivi.round_amount(-1.045, 0), '-1',    '-1.045 @ 0');
+
+  assert.equal(kivi.round_amount(-33.675, 2), '-33.68', '33.675 @ 2');
+  assert.equal(kivi.round_amount(-33.675, 1), '-33.7',  '33.675 @ 1');
+  assert.equal(kivi.round_amount(-33.675, 0), '-34',    '33.675 @ 0');
+
+  assert.equal(kivi.round_amount(-44.9 * 0.75, 2), '-33.68', '-44.9 * 0.75 @ 2');
+  assert.equal(kivi.round_amount(-44.9 * 0.75, 1), '-33.7',  '-44.9 * 0.75 @ 1');
+  assert.equal(kivi.round_amount(-44.9 * 0.75, 0), '-34',    '-44.9 * 0.75 @ 0');
+
+  assert.equal(kivi.round_amount(-149.175, 2), '-149.18', '-149.175 @ 2');
+  assert.equal(kivi.round_amount(-149.175, 1), '-149.2',  '-149.175 @ 1');
+  assert.equal(kivi.round_amount(-149.175, 0), '-149',    '-149.175 @ 0');
+
+  assert.equal(kivi.round_amount(-198.90 * 0.75, 2), '-149.18', '-198.90 * 0.75 @ 2');
+  assert.equal(kivi.round_amount(-198.90 * 0.75, 1), '-149.2',  '-198.90 * 0.75 @ 1');
+  assert.equal(kivi.round_amount(-198.90 * 0.75, 0), '-149',    '-198.90 * 0.75 @ 0');
+});
+
+QUnit.test("kivi.round_amount function, programmatic tests of all 0..1000", function( assert ) {
+  $([ -1, 1 ]).each(function(dummy, sign) {
+    for (var idx = 0; idx < 1000; idx++) {
+      var num = (9900000 * sign) + idx;
+      var str = "" + num;
+      str     = str.substr(0, str.length - 2) + "." + str.substr(str.length - 2, 2);
+      str     = str.replace(/0+$/, '').replace(/\.$/, '');
+
+      num /= 100;
+      num /= 5;
+      num /= 3;
+      num *= 5;
+      num *= 3;
+
+      assert.equal("" + kivi.round_amount(num, 2), str);
+    }
+  });
+});
+
+QUnit.test("kivi.round_amount function, up to 10 digits of Pi", function( assert ) {
+  // round to any digit we like
+  assert.equal(kivi.round_amount(Math.PI, 0),  '3',             "0 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 1),  '3.1',           "1 digit of π");
+  assert.equal(kivi.round_amount(Math.PI, 2),  '3.14',          "2 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 3),  '3.142',         "3 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 4),  '3.1416',        "4 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 5),  '3.14159',       "5 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 6),  '3.141593',      "6 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 7),  '3.1415927',     "7 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 8),  '3.14159265',    "8 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 9),  '3.141592654',   "9 digits of π");
+  assert.equal(kivi.round_amount(Math.PI, 10), '3.1415926536', "10 digits of π");
+});
+
+QUnit.test("kivi.round_amount function, other weird cases", function( assert ) {
+  // A LOT of places:
+  assert.equal(kivi.round_amount(1.2, 200), '1.2', '1.2 @ 200');
+});
diff --git a/js/t/kivi/setup_formats.js b/js/t/kivi/setup_formats.js
new file mode 100644 (file)
index 0000000..0a97492
--- /dev/null
@@ -0,0 +1,35 @@
+QUnit.test("kivi.setup_formats date format initialization", function( assert ) {
+  kivi.setup_formats({ dates: "dd.mm.yy" });
+  assert.deepEqual(kivi._date_format, { sep: '.', d: 0, m: 1, y: 2 } , "German date style with dots");
+
+  kivi.setup_formats({ dates: "dd/mm/yy" });
+  assert.deepEqual(kivi._date_format, { sep: '/', d: 0, m: 1, y: 2 } , "German date style with slashes");
+
+  kivi.setup_formats({ dates: "mm/dd/yy" });
+  assert.deepEqual(kivi._date_format, { sep: '/', d: 1, m: 0, y: 2 } , "American date style");
+
+  kivi.setup_formats({ dates: "yyyy-mm-dd" });
+  assert.deepEqual(kivi._date_format, { sep: '-', d: 2, m: 1, y: 0 } , "ISO date style");
+
+  kivi.setup_formats({ dates: "dd.mm.yy" });
+  kivi.setup_formats({ dates: "Totally invalid!" });
+  assert.deepEqual(kivi._date_format, { sep: '.', d: 0, m: 1, y: 2 } , "Invalid date style should not change previously-set style");
+});
+
+QUnit.test("kivi.setup_formats number format initialization", function( assert ) {
+  kivi.setup_formats({ numbers: "1.000,00" });
+  assert.deepEqual(kivi._number_format, { decimalSep: ',', thousandSep: '.' } , "German number style with thousands separator");
+
+  kivi.setup_formats({ numbers: "1000,00" });
+  assert.deepEqual(kivi._number_format, { decimalSep: ',', thousandSep: '' } , "German number style without thousands separator");
+
+  kivi.setup_formats({ numbers: "1,000.00" });
+  assert.deepEqual(kivi._number_format, { decimalSep: '.', thousandSep: ',' } , "English number style with thousands separator");
+
+  kivi.setup_formats({ numbers: "1000.00" });
+  assert.deepEqual(kivi._number_format, { decimalSep: '.', thousandSep: '' } , "English number style without thousands separator");
+
+  kivi.setup_formats({ numbers: "1.000,00" });
+  kivi.setup_formats({ numbers: "Totally invalid!" });
+  assert.deepEqual(kivi._number_format, { decimalSep: ',', thousandSep: '.' } , "Invalid number style should not change previously-set style");
+});
index 178bcb5..c8c9e81 100644 (file)
@@ -16,6 +16,11 @@ $(function() {
       buttonImageOnly: true
   }));
 
+  kivi.setup_formats({
+    numbers: '[% JavaScript.escape(MYCONFIG.numberformat) %]',
+    dates:   '[% JavaScript.escape(MYCONFIG.dateformat) %]'
+  });
+
   kivi.reinit_widgets();
 [% END %]