commit
message
Getting a very simple version working.
author
Ben Vogt <[email protected]>
date
2016-12-26 17:38:00
stats
5 file(s) changed,
879 insertions(+),
29 deletions(-)
files
README.md
index.html
rule.html
js/mine.js
js/ruleJS.js
mine.html
1diff --git a/README.md b/README.md
2new file mode 100644
3index 0000000..51f909b
4--- /dev/null
5+++ b/README.md
6@@ -0,0 +1,12 @@
7+# Spreadsheet
8+TypeScript implementation of a spreadsheet.
9+
10+## TODO
11+Things I should do.
12+
13+## THE PLAN FROM NOW ON
14+Take ruleJS.js and slowly alter it slowly.
15+Step by step build up to a model that is not DOM-based.
16+Then introduce types.
17+Then introduce classes.
18+
19diff --git a/js/mine.js b/js/mine.js
20new file mode 100644
21index 0000000..1ea5363
22--- /dev/null
23+++ b/js/mine.js
24@@ -0,0 +1,702 @@
25+var storage = {};
26+
27+
28+var mine = (function () {
29+ 'use strict';
30+ var instance = this;
31+
32+ var parser = {};
33+
34+ var FormulaParser = function(handler) {
35+ var formulaLexer = function () {};
36+ formulaLexer.prototype = Parser.lexer;
37+
38+ var formulaParser = function () {
39+ this.lexer = new formulaLexer();
40+ this.yy = {};
41+ };
42+
43+ formulaParser.prototype = Parser;
44+ var newParser = new formulaParser;
45+ newParser.setObj = function(obj) {
46+ newParser.yy.obj = obj;
47+ };
48+
49+ newParser.yy.parseError = function (str, hash) {
50+ throw {
51+ name: 'Parser error',
52+ message: str,
53+ prop: hash
54+ }
55+ };
56+
57+ newParser.yy.handler = handler;
58+
59+ return newParser;
60+ };
61+
62+ var Exception = {
63+ errors: [
64+ {type: 'NULL', output: '#NULL'},
65+ {type: 'DIV_ZERO', output: '#DIV/0!'},
66+ {type: 'VALUE', output: '#VALUE!'},
67+ {type: 'REF', output: '#REF!'},
68+ {type: 'NAME', output: '#NAME?'},
69+ {type: 'NUM', output: '#NUM!'},
70+ {type: 'NOT_AVAILABLE', output: '#N/A!'},
71+ {type: 'ERROR', output: '#ERROR'}
72+ ],
73+ get: function (type) {
74+ var error = Exception.errors.filter(function (item) {
75+ return item.type === type || item.output === type;
76+ })[0];
77+
78+ return error ? error.output : null;
79+ }
80+ };
81+
82+ var Matrix = function () {
83+
84+ // var item = {
85+ // id: '',
86+ // formula: '',
87+ // value: '',
88+ // error: '',
89+ // deps: [],
90+ // formulaEdit: false
91+ // };
92+
93+ this.data = [];
94+
95+ this.getItem = function (id) {
96+ return instance.matrix.data.filter(function (item) {
97+ return item.id === id;
98+ })[0];
99+ };
100+
101+ this.removeItem = function (id) {
102+ instance.matrix.data = instance.matrix.data.filter(function (item) {
103+ return item.id !== id;
104+ });
105+ };
106+
107+ this.updateItem = function (item, props) {
108+ if (instance.utils.isString(item)) {
109+ item = instance.matrix.getItem(item);
110+ }
111+
112+ if (item && props) {
113+ for (var p in props) {
114+ if (item[p] && instance.utils.isArray(item[p])) {
115+ if (instance.utils.isArray(props[p])) {
116+ props[p].forEach(function (i) {
117+ if (item[p].indexOf(i) === -1) {
118+ item[p].push(i);
119+ }
120+ });
121+ } else {
122+
123+ if (item[p].indexOf(props[p]) === -1) {
124+ item[p].push(props[p]);
125+ }
126+ }
127+ } else {
128+ item[p] = props[p];
129+ }
130+ }
131+ }
132+ };
133+
134+ this.addItem = function (item) {
135+ var cellId = item.id,
136+ coords = instance.utils.cellCoords(cellId);
137+
138+ item.row = coords.row;
139+ item.col = coords.col;
140+
141+ var cellExist = instance.matrix.data.filter(function (cell) {
142+ return cell.id === cellId;
143+ })[0];
144+
145+ if (!cellExist) {
146+ instance.matrix.data.push(item);
147+ } else {
148+ instance.matrix.updateItem(cellExist, item);
149+ }
150+
151+ return instance.matrix.getItem(cellId);
152+ };
153+
154+
155+ this.updateElementItem = function (id, props) {
156+ var item = instance.matrix.getItem(id);
157+
158+ instance.matrix.updateItem(item, props);
159+ };
160+
161+ this.getDependencies = function (id) {
162+ var getDependencies = function (id) {
163+ var filtered = instance.matrix.data.filter(function (cell) {
164+ if (cell.deps) {
165+ return cell.deps.indexOf(id) > -1;
166+ }
167+ });
168+
169+ var deps = [];
170+ filtered.forEach(function (cell) {
171+ if (deps.indexOf(cell.id) === -1) {
172+ deps.push(cell.id);
173+ }
174+ });
175+
176+ return deps;
177+ };
178+
179+ var allDependencies = [];
180+
181+ var getTotalDependencies = function (id) {
182+ var deps = getDependencies(id);
183+
184+ if (deps.length) {
185+ deps.forEach(function (refId) {
186+ if (allDependencies.indexOf(refId) === -1) {
187+ allDependencies.push(refId);
188+
189+ var item = instance.matrix.getItem(refId);
190+ if (item.deps.length) {
191+ getTotalDependencies(refId);
192+ }
193+ }
194+ });
195+ }
196+ };
197+
198+ getTotalDependencies(id);
199+
200+ return allDependencies;
201+ };
202+
203+ this.getElementDependencies = function (cell) {
204+ return instance.matrix.getDependencies(cell.id);
205+ };
206+
207+ var recalculateElementDependencies = function (cell) {
208+ var allDependencies = instance.matrix.getElementDependencies(cell);
209+
210+ allDependencies.forEach(function (refId) {
211+ var currentCell = instance.matrix.getItem(refId);
212+ if (currentCell && currentCell.formula) {
213+ calculateElementFormula(currentCell.formula, currentCell.id);
214+ }
215+ });
216+ };
217+
218+ var calculateElementFormula = function (formula, id) {
219+ // to avoid double translate formulas, update item data in parser
220+ var parsed = parse(formula, id),
221+ value = parsed.result,
222+ error = parsed.error;
223+
224+ instance.matrix.updateElementItem(id, {value: value, error: error});
225+
226+ return parsed;
227+ };
228+
229+ var registerElementInMatrix = function (cell) {
230+ instance.matrix.addItem(cell);
231+ calculateElementFormula(cell.formula, cell.id);
232+ };
233+
234+ this.scan = function () {
235+ var input = [
236+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
237+ [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
238+ [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
239+ [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
240+ [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
241+ ];
242+ for (var y = 0; y < input.length; y++) {
243+ for (var x = 0; x < input[0].length; x++) {
244+ // set the cell here
245+ var id = utils.XYtoA1(x, y);
246+ var cell = {
247+ id: id,
248+ formula: input[y][x].toString()
249+ };
250+ registerElementInMatrix(cell);
251+ recalculateElementDependencies(cell);
252+ }
253+ }
254+ };
255+ };
256+
257+ var utils = {
258+ isArray: function (value) {
259+ return Object.prototype.toString.call(value) === '[object Array]';
260+ },
261+
262+ isNumber: function (value) {
263+ return Object.prototype.toString.call(value) === '[object Number]';
264+ },
265+
266+ isString: function (value) {
267+ return Object.prototype.toString.call(value) === '[object String]';
268+ },
269+
270+ isFunction: function (value) {
271+ return Object.prototype.toString.call(value) === '[object Function]';
272+ },
273+
274+ isUndefined: function (value) {
275+ return Object.prototype.toString.call(value) === '[object Undefined]';
276+ },
277+
278+ isNull: function (value) {
279+ return Object.prototype.toString.call(value) === '[object Null]';
280+ },
281+
282+ isSet: function (value) {
283+ return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
284+ },
285+
286+ getCellAlphaNum: function (cell) {
287+ var num = cell.match(/\d+$/),
288+ alpha = cell.replace(num, '');
289+
290+ return {
291+ alpha: alpha,
292+ num: parseInt(num[0], 10)
293+ }
294+ },
295+
296+ toNum: function (chr) {
297+ chr = instance.utils.clearFormula(chr);
298+ var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
299+
300+ for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
301+ result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
302+ }
303+
304+ if (result) {
305+ --result;
306+ }
307+
308+ return result;
309+ },
310+
311+ toChar: function (num) {
312+ var s = '';
313+
314+ while (num >= 0) {
315+ s = String.fromCharCode(num % 26 + 97) + s;
316+ num = Math.floor(num / 26) - 1;
317+ }
318+
319+ return s.toUpperCase();
320+ },
321+ XYtoA1: function (x, y) {
322+ function numberToLetters(num) {
323+ var mod = num % 26,
324+ pow = num / 26 | 0,
325+ out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
326+ return pow ? numberToLetters(pow) + out : out;
327+ }
328+ return numberToLetters(x+1) + (y+1).toString();
329+ },
330+ cellCoords: function (cell) {
331+ var num = cell.match(/\d+$/),
332+ alpha = cell.replace(num, '');
333+
334+ return {
335+ row: parseInt(num[0], 10) - 1,
336+ col: instance.utils.toNum(alpha)
337+ };
338+ },
339+
340+ clearFormula: function (formula) {
341+ return formula.replace(/\$/g, '');
342+ },
343+
344+ translateCellCoords: function (coords) {
345+ return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
346+ },
347+
348+ iterateCells: function (startCell, endCell, callback) {
349+ var result = {
350+ index: [], // list of cell index: A1, A2, A3
351+ value: [] // list of cell value
352+ };
353+
354+ var cols = {
355+ start: 0,
356+ end: 0
357+ };
358+
359+ if (endCell.col >= startCell.col) {
360+ cols = {
361+ start: startCell.col,
362+ end: endCell.col
363+ };
364+ } else {
365+ cols = {
366+ start: endCell.col,
367+ end: startCell.col
368+ };
369+ }
370+
371+ var rows = {
372+ start: 0,
373+ end: 0
374+ };
375+
376+ if (endCell.row >= startCell.row) {
377+ rows = {
378+ start: startCell.row,
379+ end: endCell.row
380+ };
381+ } else {
382+ rows = {
383+ start: endCell.row,
384+ end: startCell.row
385+ };
386+ }
387+
388+ for (var column = cols.start; column <= cols.end; column++) {
389+ for (var row = rows.start; row <= rows.end; row++) {
390+ var cellIndex = instance.utils.toChar(column) + (row + 1),
391+ cellValue = instance.helper.cellValue.call(this, cellIndex);
392+
393+ result.index.push(cellIndex);
394+ result.value.push(cellValue);
395+ }
396+ }
397+
398+ if (instance.utils.isFunction(callback)) {
399+ return callback.apply(callback, [result]);
400+ } else {
401+ return result;
402+ }
403+ },
404+
405+ sort: function (rev) {
406+ return function (a, b) {
407+ return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
408+ }
409+ }
410+ };
411+
412+ var helper = {
413+ SUPPORTED_FORMULAS: [
414+ 'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
415+ 'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
416+ 'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
417+ 'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
418+ 'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
419+ 'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
420+ 'IF', 'INT', 'ISEVEN', 'ISODD',
421+ 'LN', 'LOG', 'LOG10',
422+ 'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
423+ 'NOT',
424+ 'ODD', 'OR',
425+ 'PI', 'POWER',
426+ 'ROUND', 'ROUNDDOWN', 'ROUNDUP',
427+ 'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
428+ 'TAN', 'TANH', 'TRUE', 'TRUNC',
429+ 'XOR'
430+ ],
431+
432+ number: function (num) {
433+ switch (typeof num) {
434+ case 'number':
435+ return num;
436+ case 'string':
437+ if (!isNaN(num)) {
438+ return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
439+ }
440+ }
441+
442+ return num;
443+ },
444+
445+ string: function (str) {
446+ return str.substring(1, str.length - 1);
447+ },
448+
449+ numberInverted: function (num) {
450+ return this.number(num) * (-1);
451+ },
452+
453+ specialMatch: function (type, exp1, exp2) {
454+ var result;
455+
456+ switch (type) {
457+ case '&':
458+ result = exp1.toString() + exp2.toString();
459+ break;
460+ }
461+ return result;
462+ },
463+
464+ logicMatch: function (type, exp1, exp2) {
465+ var result;
466+
467+ switch (type) {
468+ case '=':
469+ result = (exp1 === exp2);
470+ break;
471+
472+ case '>':
473+ result = (exp1 > exp2);
474+ break;
475+
476+ case '<':
477+ result = (exp1 < exp2);
478+ break;
479+
480+ case '>=':
481+ result = (exp1 >= exp2);
482+ break;
483+
484+ case '<=':
485+ result = (exp1 === exp2);
486+ break;
487+
488+ case '<>':
489+ result = (exp1 != exp2);
490+ break;
491+
492+ case 'NOT':
493+ result = (exp1 != exp2);
494+ break;
495+ }
496+
497+ return result;
498+ },
499+
500+ mathMatch: function (type, number1, number2) {
501+ var result;
502+
503+ number1 = helper.number(number1);
504+ number2 = helper.number(number2);
505+
506+ if (isNaN(number1) || isNaN(number2)) {
507+ throw Error('VALUE');
508+ }
509+
510+ switch (type) {
511+ case '+':
512+ result = number1 + number2;
513+ break;
514+ case '-':
515+ result = number1 - number2;
516+ break;
517+ case '/':
518+ result = number1 / number2;
519+ if (result == Infinity) {
520+ throw Error('DIV_ZERO');
521+ } else if (isNaN(result)) {
522+ throw Error('VALUE');
523+ }
524+ break;
525+ case '*':
526+ result = number1 * number2;
527+ break;
528+ case '^':
529+ result = Math.pow(number1, number2);
530+ break;
531+ }
532+
533+ return result;
534+ },
535+
536+ callFunction: function (fn, args) {
537+ fn = fn.toUpperCase();
538+ args = args || [];
539+
540+ if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
541+ if (instance.formulas[fn]) {
542+ return instance.formulas[fn].apply(this, args);
543+ }
544+ }
545+
546+ throw Error('NAME');
547+ },
548+
549+ callVariable: function (args) {
550+ args = args || [];
551+ var str = args[0];
552+
553+ if (str) {
554+ str = str.toUpperCase();
555+ if (instance.formulas[str]) {
556+ return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
557+ }
558+ }
559+
560+ throw Error('NAME');
561+ },
562+
563+ cellValue: function (cell) {
564+ var value,
565+ fnCellValue = instance.custom.cellValue,
566+ element = this,
567+ item = instance.matrix.getItem(cell);
568+
569+ // check if custom cellValue fn exists
570+ if (instance.utils.isFunction(fnCellValue)) {
571+
572+ var cellCoords = instance.utils.cellCoords(cell),
573+ cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
574+
575+ // get value
576+ value = item ? item.value : fnCellValue(cellCoords.row, cellCoords.col);
577+
578+ if (instance.utils.isNull(value)) {
579+ value = 0;
580+ }
581+
582+ if (cellId) {
583+ //update dependencies
584+ instance.matrix.updateItem(cellId, {deps: [cell]});
585+ }
586+
587+ } else {
588+
589+ // get value
590+ value = item ? item.value : document.getElementById(cell).value;
591+
592+ //update dependencies
593+ instance.matrix.updateElementItem(element, {deps: [cell]});
594+ }
595+
596+ // check references error
597+ if (item && item.deps) {
598+ if (item.deps.indexOf(cellId) !== -1) {
599+ throw Error('REF');
600+ }
601+ }
602+
603+ // check if any error occurs
604+ if (item && item.error) {
605+ throw Error(item.error);
606+ }
607+
608+ // return value if is set
609+ if (instance.utils.isSet(value)) {
610+ var result = instance.helper.number(value);
611+
612+ return !isNaN(result) ? result : value;
613+ }
614+
615+ // cell is not available
616+ throw Error('NOT_AVAILABLE');
617+ },
618+
619+ cellRangeValue: function (start, end) {
620+ var fnCellValue = instance.custom.cellValue,
621+ coordsStart = instance.utils.cellCoords(start),
622+ coordsEnd = instance.utils.cellCoords(end),
623+ element = this;
624+
625+ // iterate cells to get values and indexes
626+ var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd),
627+ result = [];
628+
629+ // check if custom cellValue fn exists
630+ if (instance.utils.isFunction(fnCellValue)) {
631+
632+ var cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
633+
634+ //update dependencies
635+ instance.matrix.updateItem(cellId, {deps: cells.index});
636+
637+ } else {
638+
639+ //update dependencies
640+ instance.matrix.updateElementItem(element, {deps: cells.index});
641+ }
642+
643+ result.push(cells.value);
644+ return result;
645+ },
646+
647+ fixedCellValue: function (id) {
648+ id = id.replace(/\$/g, '');
649+ return instance.helper.cellValue.call(this, id);
650+ },
651+
652+ fixedCellRangeValue: function (start, end) {
653+ start = start.replace(/\$/g, '');
654+ end = end.replace(/\$/g, '');
655+
656+ return instance.helper.cellRangeValue.call(this, start, end);
657+ }
658+ };
659+
660+ var parse = function (formula, element) {
661+ var result = null,
662+ error = null;
663+
664+ try {
665+
666+ parser.setObj(element);
667+ result = parser.parse(formula);
668+
669+ var id;
670+
671+ if (element instanceof HTMLElement) {
672+ id = element.getAttribute('id');
673+ } else if (element && element.id) {
674+ id = element.id;
675+ }
676+
677+ var deps = instance.matrix.getDependencies(id);
678+
679+ if (deps.indexOf(id) !== -1) {
680+ result = null;
681+
682+ deps.forEach(function (id) {
683+ instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
684+ });
685+
686+ throw Error('REF');
687+ }
688+
689+ } catch (ex) {
690+
691+ var message = Exception.get(ex.message);
692+
693+ if (message) {
694+ error = message;
695+ } else {
696+ error = Exception.get('ERROR');
697+ }
698+ }
699+
700+ return {
701+ error: error,
702+ result: result
703+ }
704+ };
705+
706+ var init = function () {
707+ instance = this;
708+
709+ parser = new FormulaParser(instance);
710+
711+ instance.formulas = Formula;
712+ instance.matrix = new Matrix();
713+
714+ instance.custom = {};
715+
716+ instance.matrix.scan();
717+ };
718+
719+ return {
720+ init: init,
721+ utils: utils,
722+ helper: helper,
723+ parse: parse
724+ };
725+
726+});
727diff --git a/js/ruleJS.js b/js/ruleJS.js
728index dba5e58..c3a6fed 100644
729--- a/js/ruleJS.js
730+++ b/js/ruleJS.js
731@@ -304,7 +304,6 @@ var ruleJS = (function (root) {
732
733 this.scan = function () {
734 var $totalElements = rootElement.querySelectorAll(formElements);
735-
736 [].slice.call($totalElements).forEach(function ($item) {
737 registerElementInMatrix($item);
738 registerElementEvents($item);
739diff --git a/mine.html b/mine.html
740new file mode 100644
741index 0000000..8f1ef06
742--- /dev/null
743+++ b/mine.html
744@@ -0,0 +1,159 @@
745+<!doctype html>
746+<html>
747+<head>
748+ <meta charset='utf-8'>
749+ <title>RuleJS - Like excel library to parse formulas.</title>
750+
751+ <!-- Latest compiled and minified CSS -->
752+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
753+
754+ <script src="lib/lodash/lodash.js"></script>
755+ <script src="lib/underscore.string/underscore.string.js"></script>
756+ <script src="lib/moment/moment.js"></script>
757+ <script src="lib/numeral/numeral.js"></script>
758+ <script src="lib/numericjs/numeric.js"></script>
759+ <script src="lib/js-md5/md5.js"></script>
760+ <script src="lib/jstat/jstat.js"></script>
761+ <script src="lib/formulajs/formula.js"></script>
762+
763+ <script src="js/parser.js"></script>
764+ <script src="js/mine.js"></script>
765+ <script src="js/ruleJS.js"></script>
766+ <style>
767+ .table input[type=text] {
768+ width: 50px;
769+ }
770+ #suportedList ul {
771+ -webkit-column-count: 4; -webkit-column-gap:20px;
772+ -moz-column-count:4; -moz-column-gap:20px;
773+ -o-column-count:4; -o-column-gap:20px;
774+ column-count:4; column-gap:20px;
775+ }
776+ </style>
777+</head>
778+<body>
779+<div class="col-xs-12">
780+ <section>
781+ <h1 class="page-header">RuleJS</h1>
782+ <section>
783+ <h1 class="page-header">Demo</h1>
784+ <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
785+
786+ <div class="col-xs-12" style="padding: 0px;" id="mine">
787+
788+ <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
789+
790+ <p class="bg-info" style="display: none">result: <span id="result"></span></p>
791+ <p class="bg-danger" style="display: none">error: <span id="error"></span></p>
792+ <p class="clearfix"></p>
793+
794+ <p>Try to insert formula into input field by typing ex. <code>=A1</code>. It's possible to edit formula by double clicked on input field.</p>
795+ <table class="table table-bordered">
796+ <thead>
797+ <tr>
798+ <td></td>
799+ <td>A</td>
800+ <td>B</td>
801+ <td>C</td>
802+ <td>D</td>
803+ <td>E</td>
804+ <td>F</td>
805+ <td>G</td>
806+ <td>H</td>
807+ <td>I</td>
808+ <td>J</td>
809+ <td colspan="2" class="text-center">fn(x)</td>
810+ </tr>
811+ </thead>
812+ <tbody>
813+ <tr>
814+ <td>1</td>
815+ <td><input type="text" id="A1" value="1"></td>
816+ <td><input type="text" id="B1" value="2"></td>
817+ <td><input type="text" id="C1" value="3"></td>
818+ <td><input type="text" id="D1" value="4"></td>
819+ <td><input type="text" id="E1" value="5"></td>
820+ <td><input type="text" id="F1" value="6"></td>
821+ <td><input type="text" id="G1" value="7"></td>
822+ <td><input type="text" id="H1" value="8"></td>
823+ <td><input type="text" id="I1" value="9"></td>
824+ <td><input type="text" id="J1" value="10"></td>
825+ <td>SUM(A1:D1, H1)</td>
826+ <td><span id="K1" data-formula="SUM(A1:D1, H1)"></span></td>
827+ </tr>
828+ <tr>
829+ <td>2</td>
830+ <td><input type="text" id="A2" value="-1"></td>
831+ <td><input type="text" id="B2" value="-10"></td>
832+ <td><input type="text" id="C2" value="2"></td>
833+ <td><input type="text" id="D2" value="4"></td>
834+ <td><input type="text" id="E2" value="100"></td>
835+ <td><input type="text" id="F2" value="1"></td>
836+ <td><input type="text" id="G2" value="50"></td>
837+ <td><input type="text" id="H2" value="20"></td>
838+ <td><input type="text" id="I2" value="200"></td>
839+ <td><input type="text" id="J2" value="-100"></td>
840+ <td>MAX(A2:J2)</td>
841+ <td><span id="K2" data-formula="MAX(A2:J2)"></span></td>
842+ </tr>
843+ <tr>
844+ <td>3</td>
845+ <td><input type="text" id="A3" value="-1"></td>
846+ <td><input type="text" id="B3" value="-40"></td>
847+ <td><input type="text" id="C3" value="-53"></td>
848+ <td><input type="text" id="D3" value="1"></td>
849+ <td><input type="text" id="E3" value="10"></td>
850+ <td><input type="text" id="F3" value="30"></td>
851+ <td><input type="text" id="G3" value="10"></td>
852+ <td><input type="text" id="H3" value="301"></td>
853+ <td><input type="text" id="I3" value="-1"></td>
854+ <td><input type="text" id="J3" value="-20"></td>
855+ <td>MIN(A3:J3)</td>
856+ <td><span id="K3" data-formula="MIN(A3:J3)"></span></td>
857+ </tr>
858+ <tr>
859+ <td>4</td>
860+ <td><input type="text" id="A4" value="20"></td>
861+ <td><input type="text" id="B4" value="50"></td>
862+ <td><input type="text" id="C4" value="100"></td>
863+ <td><input type="text" id="D4" value="20"></td>
864+ <td><input type="text" id="E4" value="1"></td>
865+ <td><input type="text" id="F4" value="5"></td>
866+ <td><input type="text" id="G4" value="15"></td>
867+ <td><input type="text" id="H4" value="25"></td>
868+ <td><input type="text" id="I4" value="45"></td>
869+ <td><input type="text" id="J4" value="23"></td>
870+ <td>AVERAGE(A4:J4):</td>
871+ <td><span id="K4" data-formula="AVERAGE(A4:J4)"></span></td>
872+ </tr>
873+ <tr>
874+ <td>5</td>
875+ <td><input type="text" id="A5" value="0"></td>
876+ <td><input type="text" id="B5" value="10"></td>
877+ <td><input type="text" id="C5" value="1"></td>
878+ <td><input type="text" id="D5" value="10"></td>
879+ <td><input type="text" id="E5" value="2"></td>
880+ <td><input type="text" id="F5" value="10"></td>
881+ <td><input type="text" id="G5" value="3"></td>
882+ <td><input type="text" id="H5" value="10"></td>
883+ <td><input type="text" id="I5" value="4"></td>
884+ <td><input type="text" id="J5" value="10"></td>
885+ <td>SUMIF(A5:J5,'>5')</td>
886+ <td><span id="K5" data-formula="SUMIF(A5:J5,'>5')"></span></td>
887+ </tr>
888+ </tbody>
889+ </table>
890+ </div>
891+
892+
893+
894+ </section>
895+ </section>
896+</div>
897+
898+<script>
899+ var m = new mine('mine');
900+ m.init();
901+</script>
902+</body>
903+</html>
904diff --git a/index.html b/rule.html
905similarity index 88%
906rename from index.html
907rename to rule.html
908index e135b10..7e01479 100644
909--- a/index.html
910+++ b/rule.html
911@@ -17,6 +17,7 @@
912 <script src="lib/formulajs/formula.js"></script>
913
914 <script src="js/parser.js"></script>
915+ <script src="js/mine.js"></script>
916 <script src="js/ruleJS.js"></script>
917 <style>
918 .table input[type=text] {
919@@ -38,7 +39,7 @@
920 <h1 class="page-header">Demo</h1>
921 <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
922
923- <div class="col-xs-6" style="padding: 0px;" id="demo1">
924+ <div class="col-xs-12" style="padding: 0px;" id="demo1">
925
926 <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
927
928@@ -145,6 +146,8 @@
929 </div>
930
931 </section>
932+ </section>
933+
934 </div>
935
936 <script>
937@@ -153,29 +156,6 @@
938 var rules = new ruleJS('demo1');
939 rules.init();
940
941- var button = document.querySelector('button'),
942- input = document.querySelector('input[type=text]'),
943- result = document.querySelector('#result'),
944- error = document.querySelector('#error');
945-
946- button.addEventListener('click', function () {
947- result.parentNode.style.display = 'none';
948- error.parentNode.style.display = 'none';
949-
950- var formula = input.value;
951- var parsed = rules.parse(formula, input);
952-
953- if (parsed.result !== null) {
954- result.parentNode.style.display = '';
955- result.innerText = parsed.result;
956- }
957-
958- if (parsed.error) {
959- error.parentNode.style.display = '';
960- error.innerText = parsed.error;
961- }
962- });
963-
964 })();
965 </script>
966 </body>