|
|
- //This is the CalculateApp object, providing a full context for the app
- var CalculateApp = {
- /* UI Elements */
- elements: {
- resultsZoneDiv: undefined,
- calcInputDiv: undefined,
- calcInput: undefined,
- labelInput: undefined,
- modalDiv: undefined
- },
-
- /* libraries loaded by require */
- libs: {
- mustache: undefined,
- functionPlot: undefined
- },
-
- /* Application data */
- data: {
- buddyColor: {
- stroke: "#1500A7",
- fill: "#ff0000"
- },
- calculations: [],
- windowWidth: undefined,
- windowHeight: undefined,
- isMobile: /iphone|ipod|ipad|android|blackberry|opera mini|opera mobi|skyfire|maemo|windows phone|palm|iemobile|symbian|symbianos|fennec/i.test(navigator.userAgent.toLowerCase()),
- isIos: (navigator.userAgent.match(/iPad|iPhone|iPod/g) ? true : false ),
- outputBase: 10,
- outputDigits: 6,
- isRadian: false,
- pi: 3.141592653589793
- },
-
- /* Return if Chrome WebApp env. Chrome WebApp does not allow eval. */
- isFullMode: function fullModeEval() {
- if (typeof chrome != "undefined" && chrome.app && chrome.app.runtime) {
- return false;
- }
- return true;
- }(),
-
- /* Evaluate a calculation without using eval() */
- evalParser: function(input) {
- var result = Parser.parse(input).evaluate();
- return result;
- },
-
- /* Evaluate a calculation using eval() - provides advanced features */
- evalMathJS: function(input) {
- var result = mathjs.eval(input);
- return result;
- },
-
- /* Auto eval using light or full mode */
- eval: function(input) {
- var result;
- var resultBase10;
- if (CalculateApp.isFullMode) {
- result = CalculateApp.evalMathJS(input);
- resultBase10 = CalculateApp.baseConv(CalculateApp.evalMathJS(input), CalculateApp.data.outputBase, 10);
- } else {
- result = CalculateApp.evalParser(input);
- resultBase10 = CalculateApp.baseConv(CalculateApp.evalParser(input), CalculateApp.data.outputBase, 10);
- }
- return {
- resultBase10: CalculateApp.toFixed(result, CalculateApp.data.outputDigits),
- result: CalculateApp.toFixed(resultBase10, CalculateApp.data.outputDigits)
- };
- },
-
- /* Calcul f(x) with x = 0 using light or full mode*/
- evalFunctionAtZero: function(input) {
- var result;
- if (CalculateApp.isFullMode) {
- try {
- result = mathjs.eval(input)(0);
- if (isNaN(result) || !isFinite(result)) {
- return 0;
- }
- return result;
- } catch (error) {
- return 0;
- }
- } else {
- try {
- result = Parser.parse(input).evaluate({
- x: 0
- });
- if (isNaN(result) || !isFinite(result)) {
- return 0;
- }
- return result;
- } catch (error) {
- return 0;
- }
- }
- },
-
- /* Check if simple calculation or function */
- isGraph: function(input) {
- if (input.indexOf("f(x)") == -1) {
- return false;
- }
- return true;
- },
-
- /* Display a graph */
- _graph: function(equation, valueForZero, graphFn) {
- nanoModal(CalculateApp.elements.modalDiv, {
- buttons: [],
- }).onShow(function(m) {
- CalculateApp.elements.modalDiv.style.display = "block";
- CalculateApp.elements.modalDiv.style.marginLeft = "auto";
- CalculateApp.elements.modalDiv.style.marginRight = "auto";
- CalculateApp.elements.modalDiv.style.height = parseInt(CalculateApp.data.windowHeight * 80 / 100) + "px";
- CalculateApp.elements.modalDiv.style.width = parseInt(CalculateApp.data.windowWidth * 80 / 100) + "px";
- try {
- var openedModal = CalculateApp.libs.functionPlot({
- target: '#plot',
- yDomain: [valueForZero - 10, valueForZero + 10],
- xDomain: [-10, 10],
- width: parseInt(CalculateApp.data.windowWidth * 80 / 100),
- height: parseInt(CalculateApp.data.windowHeight * 80 / 100),
- data: [{
- fn: graphFn
- }]
- });
- for (var i = 0; i < 10; i++) {
- window.scroll(0, 0);
- }
- } catch (err) {
- m.hide();
- }
-
- }).onHide(function(m) {
- m.remove();
- setTimeout(function() {
- CalculateApp.focus();
- }, 300);
- }).show();
- },
-
- /* Display a graph using light mode */
- graphParser: function(equation) {
- var valueForZero = CalculateApp.evalFunctionAtZero(equation);
- var graphFn = function(x) {
- return Parser.parse(equation).evaluate({
- "x": x
- });
- };
- CalculateApp._graph(equation, valueForZero, graphFn);
- },
-
- /* Display a graph using full mode */
- graphMathJS: function(equation) {
- var valueForZero = CalculateApp.evalFunctionAtZero(equation);
- var graphFn = mathjs.eval(equation);
- CalculateApp._graph(equation, valueForZero, graphFn);
- },
-
- /* Display a graph using light or full mode */
- graph: function(input) {
- input = CalculateApp.tryPatchGraphEquation(input);
-
- if (CalculateApp.isFullMode) {
- return CalculateApp.graphMathJS(input);
- } else {
- return CalculateApp.graphParser(input);
- }
- },
-
- /* Display a calculation */
- displayCalculation: function(calculation) {
- var node = document.createElement("div");
- if (calculation.error) {
- node.innerHTML = CalculateApp.libs.mustache.render(getErrorTemplate(), calculation);
- } else {
- if (calculation.graph) {
- node.innerHTML = CalculateApp.libs.mustache.render(getGraphTemplate(), calculation);
- var childrens = node.childNodes[0].childNodes;
- var functionGraph = function(input) {
- CalculateApp.graph(input.target.value);
- };
- for (var i = 0; i < childrens.length; i++) {
- if (childrens[i].tagName === "BUTTON") {
- childrens[i].addEventListener('click', functionGraph);
- }
- }
- } else {
- node.innerHTML = CalculateApp.libs.mustache.render(getResultTemplate(), calculation);
- }
- }
- CalculateApp.elements.resultsZoneDiv.insertBefore(node, CalculateApp.elements.resultsZoneDiv.childNodes[0]);
- },
-
- /* Add calculation to list */
- storeCalculation: function(calculation) {
- if(CalculateApp.data.calculations === null){
- CalculateApp.data.calculations = [];
- }
- CalculateApp.data.calculations.push(calculation);
- },
-
- /* Persist calculation lists */
- persistCalculations: function() {
- var calculationsToSave = [];
- for (var i = CalculateApp.data.calculations.length - 1; i >= 0; i--) {
- if (calculationsToSave.length >= 20) {
- break;
- }
- calculationsToSave.unshift(CalculateApp.data.calculations[i]);
- }
- var json = JSON.stringify(calculationsToSave);
- CalculateApp.libs.activity.getDatastoreObject().setDataAsText(json);
- CalculateApp.libs.activity.getDatastoreObject().save(function() {});
- },
-
- /* Base convert */
- baseConv: function(number, to, from) {
- if (to == from) {
- return number;
- }
- return parseInt(number, from || 10).toString(to);
- },
-
- /* Handle window resize */
- onResize: function() {
- CalculateApp.data.windowHeight = getWindowHeight();
- CalculateApp.data.windowWidth = getWindowWidth();
-
- setTimeout(function() {
- CalculateApp.elements.resultsZoneDiv.style.height = CalculateApp.elements.calcInputDiv.clientHeight + "px";
- CalculateApp.elements.resultsZoneDiv.style.display = "block";
- }, 300);
- },
-
- /* Focus only if computer */
- focus: function() {
- if (!CalculateApp.data.isMobile) {
- CalculateApp.elements.calcInput.focus();
- }
- },
-
- /* Translation of the Gui */
- transateGui: function() {
- if (CalculateApp.libs.webL10n.get("calcul") !== undefined && CalculateApp.libs.webL10n.get("calcul").length > 0) {
- CalculateApp.elements.calcInput.placeholder = CalculateApp.libs.webL10n.get("calcul");
- }
- if (CalculateApp.libs.webL10n.get("label") !== undefined && CalculateApp.libs.webL10n.get("label").length > 0) {
- CalculateApp.elements.labelInput.placeholder = CalculateApp.libs.webL10n.get("label");
- }
- if (CalculateApp.libs.webL10n.get("clear") !== undefined && CalculateApp.libs.webL10n.get("clear").length > 0) {
- CalculateApp.elements.calcButtonClear.innerHTML = CalculateApp.libs.webL10n.get("clear");
- }
- },
-
- /* We clear the result box and display all previous calculations */
- displayAllCalculations: function() {
- while (CalculateApp.elements.resultsZoneDiv.firstChild) {
- CalculateApp.elements.resultsZoneDiv.removeChild(CalculateApp.elements.resultsZoneDiv.firstChild);
- }
- if(CalculateApp.data.calculations !== null){
- for (var i = 0; i < CalculateApp.data.calculations.length; i++) {
- CalculateApp.displayCalculation(CalculateApp.data.calculations[i]);
- }
- }
- },
-
- /* We try to patch the equation to handle things like degree to radians conversion */
- tryPatchEquation: function(equation) {
- if (CalculateApp.data.isRadian) {
- return equation;
- }
- var matchingFunctions = [
- "cos",
- "sin",
- "tan",
- "acos",
- "asin",
- "atan",
- "cosh",
- "sinh",
- "tanh"
- ];
-
- for (var i = 0; i < matchingFunctions.length; i++) {
- var regex = new RegExp(matchingFunctions[i] + "\\((.+?)\\)", "gi");
- var results = equation.match(regex);
- if (results) {
- for (var j = 0; j < results.length; j++) {
- var parenthesisRegex = new RegExp("\\(([^\\)]+)\\)", "gi");
- var arrayToReplace = parenthesisRegex.exec(results[j]);
- if (arrayToReplace && arrayToReplace.length >= 2) {
- equation = equation.replace(arrayToReplace[1], arrayToReplace[1] + " * " + CalculateApp.data.pi + " / 180");
- }
- }
- }
- }
- return equation;
- },
-
- /* We try to patch the equation to make the graph working on both full mode and light mode */
- tryPatchGraphEquation: function(question) {
- if (!CalculateApp.isFullMode) {
- question = question.replace("f(x)=", "");
- }
- return question;
- },
-
- /* Simple toFixed method to format the output with max digits */
- toFixed: function(value, precision) {
- if (isNaN(value) || (Number(value) === value && value % 1 === 0)) {
- return value;
- }
- var power = Math.pow(10, precision || 0);
- return String(Math.round(value * power) / power);
- }
- };
|