Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@ Options
<ul>
<li><code>decimals</code> Number of decimals to show in the ticket and in the result value. <i>Default is '2'</i>
<li><code>useCommaAsDecimalMark</code> If true, use the comma to parse the numbers and to show the values. <i>Default is 'false'</i>
<li><code>numberFormat</code> Intl.NumberFormat() which can contain further formatting options. See: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat">MDN: NumberFormat</a> for more. <i>Optional. Will default to 'US' if useCommaAsDecimalMark is provided and true, or 'FR' if useCommaAsDecimalMark is provided and false</i>
<li><code>parent_element</code> Parent element to attach the calculator "ticket", use to control visibility. <i>Default is <code>$("body")</code></i>
</ul>


Usage
-------
<code>
$(function () {
$("input").calculadora({decimals: 0, useCommaAsDecimalMark: false});
})
</code>
<pre><code>
$(function () {
$("input").calculadora({decimals: 0, useCommaAsDecimalMark: false});
})
</code></pre>
Or:
<pre><code>
const nF = new Intl.NumberFormat('US', {style: 'decimal', maximumFractionDigits: 2, useGrouping: false});
$("input.calculator").calculadora({numberFormat: nF, parent_element: $('.modal-body')});
</code></pre>
195 changes: 87 additions & 108 deletions jquery.calculadora.js
Original file line number Diff line number Diff line change
@@ -1,156 +1,135 @@
/*
* jQuery Calculadora 0.3
* jQuery Calculadora 0.6
* Copyright 2013, Eduardo Molteni
*
*/

(function ($) {
var defaults = {
decimals: 2,
useCommaAsDecimalMark: false
useCommaAsDecimalMark: false,
parent_element: $("body"),
};

$.fn.extend({
calculadora: function(options) {

var options = $.extend({}, defaults, options);
var options = $.extend({}, defaults, options);

if(!options.numberFormat){
options.numberFormat = (options.useCommaAsDecimalMark) ?
new Intl.NumberFormat('FR', {maximumFractionDigits: options.decimals}) :
new Intl.NumberFormat('US', {maximumFractionDigits: options.decimals});
};
var conf = {};
conf.radix = options.numberFormat.format(0.1).slice(1,2);
conf.re = new RegExp(`[^-0-9${conf.radix}]`, 'g');

var ticket = $('<div id="calculadora" style="display: none; position: absolute"><ul></ul></div>');
var ticketUl = ticket.find("ul");
$("body").append(ticket);

while($('#calculadora').length != 0) {
$('#calculadora').remove();
};
$(options.parent_element).append(ticket);

return this.each(function() {
var o = options;
var self = $(this);
var LastOperator = 0;
var LastOperator = null;
var TotalSoFar = 0;
var TicketIsVisible = false;

self.blur(function (event) {
LastOperator = 0;
LastOperator = null;
ticketUl.html("");
ticket.hide();
TicketIsVisible = false;

var number = parseLocalFloat(self.val());
self.val(formatNumber(number, o.decimals));
self.val(formatNumber(number));
});

self.keydown(
function (event) {
var number = parseLocalFloat(self.val());

// if there's a number in the input:
if (number !== 0)
switch (event.which) {
// if the key is -+/*:
case 109:
case 107:
case 111:
case 106:
event.preventDefault();
calculateSoFar( number );
addToTicket(formatNumber(number, o.decimals), event.which);
LastOperator = event.which;
self.val("");
break;
case 75: //if the key is 'k'
event.preventDefault();
self.val(number * 1000);
break;
case 77: //if the key is 'M'
event.preventDefault();
self.val(number * 1000000);
break;
break;
}

// si la tecla es enter o tab o =
if (event.which == 13 || event.which == 9) {
console.log(event.which);
if (event.which == 13) {
switch (event.key) {
case '+':
case '-':
case '*':
case '/':
event.preventDefault();
}
calculateSoFar(number);
addToTicket(formatNumber(number, o.decimals), "=");
addToTicket(formatNumber(TotalSoFar, o.decimals), 0, "tot");
self.val(formatNumber(TotalSoFar, o.decimals));
LastOperator = 0;
}
}
);

self.keypress(
function (event) {
var number = parseLocalFloat(self.val());

if (event.which == 37) {
event.preventDefault();
self.val(TotalSoFar * number / 100);
}
calculateSoFar( number );
addToTicket(formatNumber(number), event.key);
LastOperator = event.key;
self.val("");
break;
case 'Enter':
case '=':
event.preventDefault(); // allow default action for Tab key
case 'Tab':
calculateSoFar(number);
addToTicket(formatNumber(number), "=");
addToTicket(formatNumber(TotalSoFar), " ", "tot");
self.val(formatNumber(TotalSoFar));
LastOperator = null;
self.change();
break;
case 'k':
event.preventDefault();
self.val(number * 1000);
break;
case 'M':
event.preventDefault();
self.val(number * 1000000);
break;
case 'm':
event.preventDefault();
if (number !== 0) self.val(number / 1000);
break;
};
}
);

function calculateSoFar(number) {
if (LastOperator === 0) {
TotalSoFar = number;
}
else {
// prevent using eval
if (LastOperator == 109) TotalSoFar = TotalSoFar - number;
if (LastOperator == 107) TotalSoFar = TotalSoFar + number;
if (LastOperator == 111 && number !== 0) TotalSoFar = TotalSoFar / number;
if (LastOperator == 111 && number === 0) TotalSoFar = 0;
if (LastOperator == 106) TotalSoFar = TotalSoFar * number;
}
}

function addToTicket(text, which, liclass) {
var pos = self.offset();
if (!TicketIsVisible && pos) {
ticket.css('top', (pos.top - 15) + "px");
ticket.css('left', pos.left + "px");
switch (LastOperator) {
case null:
TotalSoFar = number;
break;
case '+':
TotalSoFar = TotalSoFar + number;
break;
case '-':
TotalSoFar = TotalSoFar - number;
break;
case '*':
TotalSoFar = TotalSoFar * number;
break;
case '/':
TotalSoFar = (number !== 0) ? TotalSoFar / number : 0;
break;
};
};

function addToTicket(text, display_operator, liclass) {
if (!ticket.is(":visible")) {
ticket.css('min-width', self.width() + "px");
//ticket.show("slide", { direction: "up" }, 1000);
ticket.show();
TicketIsVisible = true;
}
ticketUl.append("<li class='" + liclass + "'><div class='op'>" + operatorForCode(which) + "</div><div class='num'>" + text + "</div></li>");
ticket.css('top', (pos.top - ticket.height()) + "px");
}
ticket.offset({top: self.offset().top-15, left: self.offset().left});
};
ticketUl.append("<li class='" + liclass + "'><div class='op'>" + display_operator + "</div><div class='num'>" + text + "</div></li>");
ticket.offset({top: ticket.offset().top-15, left: ticket.offset().left});
};

});


function parseLocalFloat(num) {
if (!num) return 0;
if (options.useCommaAsDecimalMark) {
return parseFloat((num.replace(/\./g, "").replace(/ /g, "").replace("$", "").replace(",", ".")));
}
return parseFloat(num.replace(/,/g, ""));
}

function formatNumber(n, c) {
var d = "."; var t = ",";
if (options.useCommaAsDecimalMark) {
d = ","; t = ".";
}
c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
num = num.replace(conf.re, '').replace(conf.radix, '.');
return parseFloat(num)
};


function operatorForCode(whichKeyCode) {
if (whichKeyCode == 109) return("-");
if (whichKeyCode == 107) return ("+");
if (whichKeyCode == 111) return ("/");
if (whichKeyCode == 106) return ("*");
if (whichKeyCode == "=") return ("=");
return "";
}

function formatNumber(num) {
return options.numberFormat.format(num)
};
}
});

})(jQuery);

})(jQuery);
2 changes: 1 addition & 1 deletion jquery.calculadora.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.