From 6e2d09fdce3627b0bc0e5839edf6b8c62a85f45d Mon Sep 17 00:00:00 2001 From: sipp11 Date: Fri, 18 Dec 2015 00:52:55 +0700 Subject: [PATCH] wip --- package.json | 1 + src/actions/AccountActions.js | 25 +- src/actions/TxActions.js | 9 +- src/components/Tx.js | 12 +- src/components/TxForm.js | 67 +- src/constants/AccountConstants.js | 5 +- src/constants/TxConstants.js | 1 + src/libs/parser.js | 1077 +++++++++++++++++++++++++++++ src/services/AccountService.js | 46 ++ src/services/AuthService.js | 1 + src/services/TxService.js | 21 +- src/stores/AccountStore.js | 31 +- src/stores/TxStore.js | 14 +- 13 files changed, 1293 insertions(+), 17 deletions(-) create mode 100644 src/libs/parser.js diff --git a/package.json b/package.json index 21e0d83..e8537eb 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "homepage": "https://github.com/mgonto/react-browserify-spa-seed", "dependencies": { "autobind-decorator": "^1.3.2", + "classnames": "^2.2.1", "flux": "^2.0.1", "foundation-apps": "^1.1.0", "foundation-sites": "^6.0.0", diff --git a/src/actions/AccountActions.js b/src/actions/AccountActions.js index 820a891..68113c1 100644 --- a/src/actions/AccountActions.js +++ b/src/actions/AccountActions.js @@ -1,5 +1,6 @@ import AppDispatcher from '../dispatchers/AppDispatcher.js'; -import {ACCOUNT_GET, ALL_ACCOUNTS_GET} from '../constants/AccountConstants.js'; +import {ACCOUNT_GET, ALL_ACCOUNTS_GET, ACCOUNT_NEW, + ACCOUNT_UPDATE, ACCOUNT_DELETE} from '../constants/AccountConstants.js'; export default { @@ -15,5 +16,27 @@ export default { actionType: ACCOUNT_GET, account: account }) + }, + + newAccount: (account) => { + AppDispatcher.dispatch({ + actionType: ACCOUNT_NEW, + account: account + }) + }, + + updateAccount: (account) => { + AppDispatcher.dispatch({ + actionType: ACCOUNT_UPDATE, + account: account + }) + }, + + deleteAccount: (account) => { + AppDispatcher.dispatch({ + actionType: ACCOUNT_DELETE, + account: account + }) } + } diff --git a/src/actions/TxActions.js b/src/actions/TxActions.js index 84fe59b..9c38153 100644 --- a/src/actions/TxActions.js +++ b/src/actions/TxActions.js @@ -1,5 +1,5 @@ import AppDispatcher from '../dispatchers/AppDispatcher.js'; -import {TX_GET, TX_NEW, TX_UPDATE} from '../constants/TxConstants.js'; +import {TX_GET, TX_NEW, TX_UPDATE, TX_DELETE} from '../constants/TxConstants.js'; export default { @@ -22,6 +22,13 @@ export default { actionType: TX_UPDATE, tx: tx }) + }, + + deleteTx: (tx) => { + AppDispatcher.dispatch({ + actionType: TX_DELETE, + tx: tx + }) } } diff --git a/src/components/Tx.js b/src/components/Tx.js index 1ac2332..d3f35ff 100644 --- a/src/components/Tx.js +++ b/src/components/Tx.js @@ -93,6 +93,16 @@ class Tx extends React.Component { }); } + deleteTx(tx) { + + return TxService + .deleteTx(tx) + .catch(function(err) { + alert("Error deleting"); + console.log("Error deleting tx ", err); + }); + } + render() { return (
@@ -106,7 +116,7 @@ class Tx extends React.Component {

+ tx={this.state.tx} deleteTx={this.deleteTx} />
) diff --git a/src/components/TxForm.js b/src/components/TxForm.js index e70f737..c31d318 100644 --- a/src/components/TxForm.js +++ b/src/components/TxForm.js @@ -6,6 +6,10 @@ import React from 'react'; import ReactMixin from 'react-mixin'; import Catalyst from 'react-catalyst'; import autobind from 'autobind-decorator'; +import cx from 'classnames'; +import parser from '../libs/parser'; +import Moment from 'moment'; + @autobind class TxForm extends React.Component { @@ -16,7 +20,7 @@ class TxForm extends React.Component { // 2. Take the data from the form and create an object var tx = { id : this.refs.id.value, - amount : this.refs.amount.value, + amount : this.parseEquation(this.refs.amount.value), currency : this.refs.currency.value, date : this.refs.date.value, account : this.refs.account.value, @@ -28,6 +32,22 @@ class TxForm extends React.Component { this.refs.txForm.reset(); } + parseEquation(string) { + try { + var Parser = parser.Parser; + string = Parser.evaluate(string); + } catch (e) { + // I guess we just don't care + } finally { + return string; + } + } + + handleAmountChange(evt) { + var result = evt.target.value; + this.handleChange(evt) + } + handleChange(evt) { var currTx = this.state.tx; currTx[evt.target.name] = evt.target.value; @@ -45,6 +65,14 @@ class TxForm extends React.Component { this.setState({tx: this.defaultTxState()}); } + deleteItem() { + var tx = { + id : +this.refs.id.value + } + this.props.deleteTx(tx); + this.refs.txForm.reset(); + } + render() { this.state = this.state || {}; if (this.state.updated) { @@ -56,16 +84,44 @@ class TxForm extends React.Component { if (Object.keys(this.state.tx).length == 0) this.state.tx = this.defaultTxState(); + var hasItem = ( (this.state.tx.id) ? true : false ); + var delDisabledClassName = cx({ + 'hollow': true, 'alert': true, 'button': true, tiny: true, + 'disabled': !hasItem, hide: !hasItem, + }); + var hasDiffHomeValue = false; + var homeValue = this.parseEquation(this.state.tx.amount); + if ( ( this.state.tx.amount ) && ( this.state.tx.amount != homeValue ) ) { + hasDiffHomeValue = true; + this.state.homeValue = homeValue; + } + var homeValueBoxClassName = cx({ + 'grid-block': true, + 'hide': !hasDiffHomeValue, + }) + return (
+ name="amount" value={this.state.tx.amount} + onChange={this.handleAmountChange} />
+ name="currency" value={this.state.tx.currency} + onChange={this.handleChange} /> +
+
+
+
+ +
+
+
@@ -78,7 +134,8 @@ class TxForm extends React.Component { {this.props.accounts.map((account) => { var opts = { value: account.id }; return ( - + ) })} @@ -95,6 +152,7 @@ class TxForm extends React.Component { +
@@ -104,6 +162,7 @@ class TxForm extends React.Component { TxForm.propTypes = { txFormHandler : React.PropTypes.func.isRequired, + deleteTx : React.PropTypes.func.isRequired, accounts : React.PropTypes.array.isRequired, tx : React.PropTypes.object, } diff --git a/src/constants/AccountConstants.js b/src/constants/AccountConstants.js index 14aedac..f594ae7 100644 --- a/src/constants/AccountConstants.js +++ b/src/constants/AccountConstants.js @@ -3,5 +3,8 @@ export default { BASE_URL: BASE_URL, ACCOUNT_URL: BASE_URL + 'account/', ACCOUNT_GET: 'ACCOUNT_GET', - ALL_ACCOUNTS_GET: 'ALL_ACCOUNTS_GET' + ALL_ACCOUNTS_GET: 'ALL_ACCOUNTS_GET', + ACCOUNT_NEW: 'ACCOUNT_NEW', + ACCOUNT_UPDATE: 'ACCOUNT_UPDATE', + ACCOUNT_DELETE: 'ACCOUNT_DELETE', } diff --git a/src/constants/TxConstants.js b/src/constants/TxConstants.js index d8bab23..b9cf462 100644 --- a/src/constants/TxConstants.js +++ b/src/constants/TxConstants.js @@ -7,4 +7,5 @@ export default { TX_GET: 'TX_GET', TX_NEW: 'TX_NEW', TX_UPDATE: 'TX_UPDATE', + TX_DELETE: 'TX_DELETE', } diff --git a/src/libs/parser.js b/src/libs/parser.js new file mode 100644 index 0000000..83d0f40 --- /dev/null +++ b/src/libs/parser.js @@ -0,0 +1,1077 @@ +/*! + Based on ndef.parser, by Raphael Graf(r@undefined.ch) + http://www.undefined.ch/mparser/index.html + + Ported to JavaScript and modified by Matthew Crumley (email@matthewcrumley.com, http://silentmatt.com/) + + You are free to use and modify this code in anyway you find useful. Please leave this comment in the code + to acknowledge its original source. If you feel like it, I enjoy hearing about projects that use my code, + but don't feel like you have to let me know or ask permission. +*/ + +// Added by stlsmiths 6/13/2011 +// re-define Array.indexOf, because IE doesn't know it ... +// +// from http://stellapower.net/content/javascript-support-and-arrayindexof-ie + if (!Array.indexOf) { + Array.prototype.indexOf = function (obj, start) { + for (var i = (start || 0); i < this.length; i++) { + if (this[i] === obj) { + return i; + } + } + return -1; + } + } + +var Parser = (function (scope) { + function object(o) { + function F() {} + F.prototype = o; + return new F(); + } + + var TNUMBER = 0; + var TOP1 = 1; + var TOP2 = 2; + var TVAR = 3; + var TFUNCALL = 4; + + function Token(type_, index_, prio_, number_) { + this.type_ = type_; + this.index_ = index_ || 0; + this.prio_ = prio_ || 0; + this.number_ = (number_ !== undefined && number_ !== null) ? number_ : 0; + this.toString = function () { + switch (this.type_) { + case TNUMBER: + return this.number_; + case TOP1: + case TOP2: + case TVAR: + return this.index_; + case TFUNCALL: + return "CALL"; + default: + return "Invalid Token"; + } + }; + } + + function Expression(tokens, ops1, ops2, functions) { + this.tokens = tokens; + this.ops1 = ops1; + this.ops2 = ops2; + this.functions = functions; + } + + // Based on http://www.json.org/json2.js + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + "'" : "\\'", + '\\': '\\\\' + }; + + function escapeValue(v) { + if (typeof v === "string") { + escapable.lastIndex = 0; + return escapable.test(v) ? + "'" + v.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + "'" : + "'" + v + "'"; + } + return v; + } + + Expression.prototype = { + simplify: function (values) { + values = values || {}; + var nstack = []; + var newexpression = []; + var n1; + var n2; + var f; + var L = this.tokens.length; + var item; + var i = 0; + for (i = 0; i < L; i++) { + item = this.tokens[i]; + var type_ = item.type_; + if (type_ === TNUMBER) { + nstack.push(item); + } + else if (type_ === TVAR && (item.index_ in values)) { + item = new Token(TNUMBER, 0, 0, values[item.index_]); + nstack.push(item); + } + else if (type_ === TOP2 && nstack.length > 1) { + n2 = nstack.pop(); + n1 = nstack.pop(); + f = this.ops2[item.index_]; + item = new Token(TNUMBER, 0, 0, f(n1.number_, n2.number_)); + nstack.push(item); + } + else if (type_ === TOP1 && nstack.length > 0) { + n1 = nstack.pop(); + f = this.ops1[item.index_]; + item = new Token(TNUMBER, 0, 0, f(n1.number_)); + nstack.push(item); + } + else { + while (nstack.length > 0) { + newexpression.push(nstack.shift()); + } + newexpression.push(item); + } + } + while (nstack.length > 0) { + newexpression.push(nstack.shift()); + } + + return new Expression(newexpression, object(this.ops1), object(this.ops2), object(this.functions)); + }, + + substitute: function (variable, expr) { + if (!(expr instanceof Expression)) { + expr = new Parser().parse(String(expr)); + } + var newexpression = []; + var L = this.tokens.length; + var item; + var i = 0; + for (i = 0; i < L; i++) { + item = this.tokens[i]; + var type_ = item.type_; + if (type_ === TVAR && item.index_ === variable) { + for (var j = 0; j < expr.tokens.length; j++) { + var expritem = expr.tokens[j]; + var replitem = new Token(expritem.type_, expritem.index_, expritem.prio_, expritem.number_); + newexpression.push(replitem); + } + } + else { + newexpression.push(item); + } + } + + var ret = new Expression(newexpression, object(this.ops1), object(this.ops2), object(this.functions)); + return ret; + }, + + evaluate: function (values) { + values = values || {}; + var nstack = []; + var n1; + var n2; + var f; + var L = this.tokens.length; + var item; + var i = 0; + for (i = 0; i < L; i++) { + item = this.tokens[i]; + var type_ = item.type_; + if (type_ === TNUMBER) { + nstack.push(item.number_); + } + else if (type_ === TOP2) { + n2 = nstack.pop(); + n1 = nstack.pop(); + f = this.ops2[item.index_]; + nstack.push(f(n1, n2)); + } + else if (type_ === TVAR) { + if (item.index_ in values) { + nstack.push(values[item.index_]); + } + else if (item.index_ in this.functions) { + nstack.push(this.functions[item.index_]); + } + else { + throw new Error("undefined variable: " + item.index_); + } + } + else if (type_ === TOP1) { + n1 = nstack.pop(); + f = this.ops1[item.index_]; + nstack.push(f(n1)); + } + else if (type_ === TFUNCALL) { + n1 = nstack.pop(); + f = nstack.pop(); + if (f.apply && f.call) { + if (Object.prototype.toString.call(n1) == "[object Array]") { + nstack.push(f.apply(undefined, n1)); + } + else { + nstack.push(f.call(undefined, n1)); + } + } + else { + throw new Error(f + " is not a function"); + } + } + else { + throw new Error("invalid Expression"); + } + } + if (nstack.length > 1) { + throw new Error("invalid Expression (parity)"); + } + return nstack[0]; + }, + + toString: function (toJS) { + var nstack = []; + var n1; + var n2; + var f; + var L = this.tokens.length; + var item; + var i = 0; + for (i = 0; i < L; i++) { + item = this.tokens[i]; + var type_ = item.type_; + if (type_ === TNUMBER) { + nstack.push(escapeValue(item.number_)); + } + else if (type_ === TOP2) { + n2 = nstack.pop(); + n1 = nstack.pop(); + f = item.index_; + if (toJS && f == "^") { + nstack.push("Math.pow(" + n1 + "," + n2 + ")"); + } + else { + nstack.push("(" + n1 + f + n2 + ")"); + } + } + else if (type_ === TVAR) { + nstack.push(item.index_); + } + else if (type_ === TOP1) { + n1 = nstack.pop(); + f = item.index_; + if (f === "-") { + nstack.push("(" + f + n1 + ")"); + } + else { + nstack.push(f + "(" + n1 + ")"); + } + } + else if (type_ === TFUNCALL) { + n1 = nstack.pop(); + f = nstack.pop(); + nstack.push(f + "(" + n1 + ")"); + } + else { + throw new Error("invalid Expression"); + } + } + if (nstack.length > 1) { + throw new Error("invalid Expression (parity)"); + } + return nstack[0]; + }, + + variables: function () { + var L = this.tokens.length; + var vars = []; + for (var i = 0; i < L; i++) { + var item = this.tokens[i]; + if (item.type_ === TVAR && (vars.indexOf(item.index_) == -1)) { + vars.push(item.index_); + } + } + + return vars; + }, + + toJSFunction: function (param, variables) { + var f = new Function(param, "with(Parser.values) { return " + this.simplify(variables).toString(true) + "; }"); + return f; + } + }; + + function add(a, b) { + return Number(a) + Number(b); + } + function sub(a, b) { + return a - b; + } + function mul(a, b) { + return a * b; + } + function div(a, b) { + return a / b; + } + function mod(a, b) { + return a % b; + } + function concat(a, b) { + return "" + a + b; + } + function equal(a, b) { + return a == b; + } + function notEqual(a, b) { + return a != b; + } + function greaterThan(a, b) { + return a > b; + } + function lessThan(a, b) { + return a < b; + } + function greaterThanEqual(a, b) { + return a >= b; + } + function lessThanEqual(a, b) { + return a <= b; + } + function andOperator(a, b) { + return Boolean(a && b); + } + function orOperator(a, b) { + return Boolean(a || b); + } + function sinh(a) { + return Math.sinh ? Math.sinh(a) : ((Math.exp(a) - Math.exp(-a)) / 2); + } + function cosh(a) { + return Math.cosh ? Math.cosh(a) : ((Math.exp(a) + Math.exp(-a)) / 2); + } + function tanh(a) { + if (Math.tanh) return Math.tanh(a); + if(a === Infinity) return 1; + if(a === -Infinity) return -1; + return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a)); + } + function asinh(a) { + if (Math.asinh) return Math.asinh(a); + if(a === -Infinity) return a; + return Math.log(a + Math.sqrt(a * a + 1)); + } + function acosh(a) { + return Math.acosh ? Math.acosh(a) : Math.log(a + Math.sqrt(a * a - 1)); + } + function atanh(a) { + return Math.atanh ? Math.atanh(a) : (Math.log((1+a)/(1-a)) / 2); + } + function log10(a) { + return Math.log(a) * Math.LOG10E; + } + function neg(a) { + return -a; + } + function trunc(a) { + if(Math.trunc) return Math.trunc(a); + else return x < 0 ? Math.ceil(x) : Math.floor(x); + } + function random(a) { + return Math.random() * (a || 1); + } + function fac(a) { //a! + a = Math.floor(a); + var b = a; + while (a > 1) { + b = b * (--a); + } + return b; + } + + // TODO: use hypot that doesn't overflow + function hypot() { + if(Math.hypot) return Math.hypot.apply(this, arguments); + var y = 0; + var length = arguments.length; + for (var i = 0; i < length; i++) { + if (arguments[i] === Infinity || arguments[i] === -Infinity) { + return Infinity; + } + y += arguments[i] * arguments[i]; + } + return Math.sqrt(y); + } + + function condition(cond, yep, nope) { + return cond ? yep : nope; + } + + function append(a, b) { + if (Object.prototype.toString.call(a) != "[object Array]") { + return [a, b]; + } + a = a.slice(); + a.push(b); + return a; + } + + function Parser() { + this.success = false; + this.errormsg = ""; + this.expression = ""; + + this.pos = 0; + + this.tokennumber = 0; + this.tokenprio = 0; + this.tokenindex = 0; + this.tmpprio = 0; + + this.ops1 = { + "sin": Math.sin, + "cos": Math.cos, + "tan": Math.tan, + "asin": Math.asin, + "acos": Math.acos, + "atan": Math.atan, + "sinh": sinh, + "cosh": cosh, + "tanh": tanh, + "asinh": asinh, + "acosh": acosh, + "atanh": atanh, + "sqrt": Math.sqrt, + "log": Math.log, + "lg" : log10, + "log10" : log10, + "abs": Math.abs, + "ceil": Math.ceil, + "floor": Math.floor, + "round": Math.round, + "trunc": trunc, + "-": neg, + "exp": Math.exp + }; + + this.ops2 = { + "+": add, + "-": sub, + "*": mul, + "/": div, + "%": mod, + "^": Math.pow, + ",": append, + "||": concat, + "==": equal, + "!=": notEqual, + ">": greaterThan, + "<": lessThan, + ">=": greaterThanEqual, + "<=": lessThanEqual, + "and": andOperator, + "or": orOperator + }; + + this.functions = { + "random": random, + "fac": fac, + "min": Math.min, + "max": Math.max, + "hypot": hypot, + "pyt": hypot, // backward compat + "pow": Math.pow, + "atan2": Math.atan2, + "if": condition + }; + + this.consts = { + "E": Math.E, + "PI": Math.PI + }; + } + + Parser.parse = function (expr) { + return new Parser().parse(expr); + }; + + Parser.evaluate = function (expr, variables) { + return Parser.parse(expr).evaluate(variables); + }; + + Parser.Expression = Expression; + + Parser.values = { + sin: Math.sin, + cos: Math.cos, + tan: Math.tan, + asin: Math.asin, + acos: Math.acos, + atan: Math.atan, + sinh: sinh, + cosh: cosh, + tanh: tanh, + asinh: asinh, + acosh: acosh, + atanh: atanh, + sqrt: Math.sqrt, + log: Math.log, + lg: log10, + log10: log10, + abs: Math.abs, + ceil: Math.ceil, + floor: Math.floor, + round: Math.round, + trunc: trunc, + random: random, + fac: fac, + exp: Math.exp, + min: Math.min, + max: Math.max, + hypot: hypot, + pyt: hypot, // backward compat + pow: Math.pow, + atan2: Math.atan2, + if: condition, + E: Math.E, + PI: Math.PI + }; + + var PRIMARY = 1 << 0; + var OPERATOR = 1 << 1; + var FUNCTION = 1 << 2; + var LPAREN = 1 << 3; + var RPAREN = 1 << 4; + var COMMA = 1 << 5; + var SIGN = 1 << 6; + var CALL = 1 << 7; + var NULLARY_CALL = 1 << 8; + + Parser.prototype = { + parse: function (expr) { + this.errormsg = ""; + this.success = true; + var operstack = []; + var tokenstack = []; + this.tmpprio = 0; + var expected = (PRIMARY | LPAREN | FUNCTION | SIGN); + var noperators = 0; + this.expression = expr; + this.pos = 0; + + while (this.pos < this.expression.length) { + if (this.isOperator()) { + if (this.isSign() && (expected & SIGN)) { + if (this.isNegativeSign()) { + this.tokenprio = 2; + this.tokenindex = "-"; + noperators++; + this.addfunc(tokenstack, operstack, TOP1); + } + expected = (PRIMARY | LPAREN | FUNCTION | SIGN); + } + else if (this.isComment()) { + + } + else { + if ((expected & OPERATOR) === 0) { + this.error_parsing(this.pos, "unexpected operator"); + } + noperators += 2; + this.addfunc(tokenstack, operstack, TOP2); + expected = (PRIMARY | LPAREN | FUNCTION | SIGN); + } + } + else if (this.isNumber()) { + if ((expected & PRIMARY) === 0) { + this.error_parsing(this.pos, "unexpected number"); + } + var token = new Token(TNUMBER, 0, 0, this.tokennumber); + tokenstack.push(token); + + expected = (OPERATOR | RPAREN | COMMA); + } + else if (this.isString()) { + if ((expected & PRIMARY) === 0) { + this.error_parsing(this.pos, "unexpected string"); + } + var token = new Token(TNUMBER, 0, 0, this.tokennumber); + tokenstack.push(token); + + expected = (OPERATOR | RPAREN | COMMA); + } + else if (this.isLeftParenth()) { + if ((expected & LPAREN) === 0) { + this.error_parsing(this.pos, "unexpected \"(\""); + } + + if (expected & CALL) { + noperators += 2; + this.tokenprio = -2; + this.tokenindex = -1; + this.addfunc(tokenstack, operstack, TFUNCALL); + } + + expected = (PRIMARY | LPAREN | FUNCTION | SIGN | NULLARY_CALL); + } + else if (this.isRightParenth()) { + if (expected & NULLARY_CALL) { + var token = new Token(TNUMBER, 0, 0, []); + tokenstack.push(token); + } + else if ((expected & RPAREN) === 0) { + this.error_parsing(this.pos, "unexpected \")\""); + } + + expected = (OPERATOR | RPAREN | COMMA | LPAREN | CALL); + } + else if (this.isComma()) { + if ((expected & COMMA) === 0) { + this.error_parsing(this.pos, "unexpected \",\""); + } + this.addfunc(tokenstack, operstack, TOP2); + noperators += 2; + expected = (PRIMARY | LPAREN | FUNCTION | SIGN); + } + else if (this.isConst()) { + if ((expected & PRIMARY) === 0) { + this.error_parsing(this.pos, "unexpected constant"); + } + var consttoken = new Token(TNUMBER, 0, 0, this.tokennumber); + tokenstack.push(consttoken); + expected = (OPERATOR | RPAREN | COMMA); + } + else if (this.isOp2()) { + if ((expected & FUNCTION) === 0) { + this.error_parsing(this.pos, "unexpected function"); + } + this.addfunc(tokenstack, operstack, TOP2); + noperators += 2; + expected = (LPAREN); + } + else if (this.isOp1()) { + if ((expected & FUNCTION) === 0) { + this.error_parsing(this.pos, "unexpected function"); + } + this.addfunc(tokenstack, operstack, TOP1); + noperators++; + expected = (LPAREN); + } + else if (this.isVar()) { + if ((expected & PRIMARY) === 0) { + this.error_parsing(this.pos, "unexpected variable"); + } + var vartoken = new Token(TVAR, this.tokenindex, 0, 0); + tokenstack.push(vartoken); + + expected = (OPERATOR | RPAREN | COMMA | LPAREN | CALL); + } + else if (this.isWhite()) { + } + else { + if (this.errormsg === "") { + this.error_parsing(this.pos, "unknown character"); + } + else { + this.error_parsing(this.pos, this.errormsg); + } + } + } + if (this.tmpprio < 0 || this.tmpprio >= 10) { + this.error_parsing(this.pos, "unmatched \"()\""); + } + while (operstack.length > 0) { + var tmp = operstack.pop(); + tokenstack.push(tmp); + } + if (noperators + 1 !== tokenstack.length) { + //print(noperators + 1); + //print(tokenstack); + this.error_parsing(this.pos, "parity"); + } + + return new Expression(tokenstack, object(this.ops1), object(this.ops2), object(this.functions)); + }, + + evaluate: function (expr, variables) { + return this.parse(expr).evaluate(variables); + }, + + error_parsing: function (column, msg) { + this.success = false; + this.errormsg = "parse error [column " + (column) + "]: " + msg; + this.column = column; + throw new Error(this.errormsg); + }, + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ + + addfunc: function (tokenstack, operstack, type_) { + var operator = new Token(type_, this.tokenindex, this.tokenprio + this.tmpprio, 0); + while (operstack.length > 0) { + if (operator.prio_ <= operstack[operstack.length - 1].prio_) { + tokenstack.push(operstack.pop()); + } + else { + break; + } + } + operstack.push(operator); + }, + + isNumber: function () { + var r = false; + var str = ""; + while (this.pos < this.expression.length) { + var code = this.expression.charCodeAt(this.pos); + if ((code >= 48 && code <= 57) || code === 46) { + str += this.expression.charAt(this.pos); + this.pos++; + this.tokennumber = parseFloat(str); + r = true; + } + else { + break; + } + } + return r; + }, + + // Ported from the yajjl JSON parser at http://code.google.com/p/yajjl/ + unescape: function(v, pos) { + var buffer = []; + var escaping = false; + + for (var i = 0; i < v.length; i++) { + var c = v.charAt(i); + + if (escaping) { + switch (c) { + case "'": + buffer.push("'"); + break; + case '\\': + buffer.push('\\'); + break; + case '/': + buffer.push('/'); + break; + case 'b': + buffer.push('\b'); + break; + case 'f': + buffer.push('\f'); + break; + case 'n': + buffer.push('\n'); + break; + case 'r': + buffer.push('\r'); + break; + case 't': + buffer.push('\t'); + break; + case 'u': + // interpret the following 4 characters as the hex of the unicode code point + var codePoint = parseInt(v.substring(i + 1, i + 5), 16); + buffer.push(String.fromCharCode(codePoint)); + i += 4; + break; + default: + throw this.error_parsing(pos + i, "Illegal escape sequence: '\\" + c + "'"); + } + escaping = false; + } else { + if (c == '\\') { + escaping = true; + } else { + buffer.push(c); + } + } + } + + return buffer.join(''); + }, + + isString: function () { + var r = false; + var str = ""; + var startpos = this.pos; + if (this.pos < this.expression.length && this.expression.charAt(this.pos) == "'") { + this.pos++; + while (this.pos < this.expression.length) { + var code = this.expression.charAt(this.pos); + if (code != "'" || str.slice(-1) == "\\") { + str += this.expression.charAt(this.pos); + this.pos++; + } + else { + this.pos++; + this.tokennumber = this.unescape(str, startpos); + r = true; + break; + } + } + } + return r; + }, + + isConst: function () { + var str; + for (var i in this.consts) { + if (true) { + var L = i.length; + str = this.expression.substr(this.pos, L); + if (i === str) { + this.tokennumber = this.consts[i]; + this.pos += L; + return true; + } + } + } + return false; + }, + + isOperator: function () { + var code = this.expression.charCodeAt(this.pos); + if (code === 43) { // + + this.tokenprio = 2; + this.tokenindex = "+"; + } + else if (code === 45) { // - + this.tokenprio = 2; + this.tokenindex = "-"; + } + else if (code === 62) { // > + if (this.expression.charCodeAt(this.pos + 1) === 61) { + this.pos++; + this.tokenprio = 1; + this.tokenindex = ">="; + } else { + this.tokenprio = 1; + this.tokenindex = ">"; + } + } + else if (code === 60) { // < + if (this.expression.charCodeAt(this.pos + 1) === 61) { + this.pos++; + this.tokenprio = 1; + this.tokenindex = "<="; + } else { + this.tokenprio = 1; + this.tokenindex = "<"; + } + } + else if (code === 124) { // | + if (this.expression.charCodeAt(this.pos + 1) === 124) { + this.pos++; + this.tokenprio = 1; + this.tokenindex = "||"; + } + else { + return false; + } + } + else if (code === 61) { // = + if (this.expression.charCodeAt(this.pos + 1) === 61) { + this.pos++; + this.tokenprio = 1; + this.tokenindex = "=="; + } + else { + return false; + } + } + else if (code === 33) { // ! + if (this.expression.charCodeAt(this.pos + 1) === 61) { + this.pos++; + this.tokenprio = 1; + this.tokenindex = "!="; + } + else { + return false; + } + } + else if (code === 97) { // a + if (this.expression.charCodeAt(this.pos + 1) === 110 && this.expression.charCodeAt(this.pos + 2) === 100) { // n && d + this.pos++; + this.pos++; + this.tokenprio = 0; + this.tokenindex = "and"; + } + else { + return false; + } + } + else if (code === 111) { // o + if (this.expression.charCodeAt(this.pos + 1) === 114) { // r + this.pos++; + this.tokenprio = 0; + this.tokenindex = "or"; + } + else { + return false; + } + } + else if (code === 42 || code === 8729 || code === 8226) { // * or ∙ or • + this.tokenprio = 3; + this.tokenindex = "*"; + } + else if (code === 47) { // / + this.tokenprio = 4; + this.tokenindex = "/"; + } + else if (code === 37) { // % + this.tokenprio = 4; + this.tokenindex = "%"; + } + else if (code === 94) { // ^ + this.tokenprio = 5; + this.tokenindex = "^"; + } + else { + return false; + } + this.pos++; + return true; + }, + + isSign: function () { + var code = this.expression.charCodeAt(this.pos - 1); + if (code === 45 || code === 43) { // - + return true; + } + return false; + }, + + isPositiveSign: function () { + var code = this.expression.charCodeAt(this.pos - 1); + if (code === 43) { // + + return true; + } + return false; + }, + + isNegativeSign: function () { + var code = this.expression.charCodeAt(this.pos - 1); + if (code === 45) { // - + return true; + } + return false; + }, + + isLeftParenth: function () { + var code = this.expression.charCodeAt(this.pos); + if (code === 40) { // ( + this.pos++; + this.tmpprio += 10; + return true; + } + return false; + }, + + isRightParenth: function () { + var code = this.expression.charCodeAt(this.pos); + if (code === 41) { // ) + this.pos++; + this.tmpprio -= 10; + return true; + } + return false; + }, + + isComma: function () { + var code = this.expression.charCodeAt(this.pos); + if (code === 44) { // , + this.pos++; + this.tokenprio = -1; + this.tokenindex = ","; + return true; + } + return false; + }, + + isWhite: function () { + var code = this.expression.charCodeAt(this.pos); + if (code === 32 || code === 9 || code === 10 || code === 13) { + this.pos++; + return true; + } + return false; + }, + + isOp1: function () { + var str = ""; + for (var i = this.pos; i < this.expression.length; i++) { + var c = this.expression.charAt(i); + if (c.toUpperCase() === c.toLowerCase()) { + if (i === this.pos || (c != '_' && (c < '0' || c > '9'))) { + break; + } + } + str += c; + } + if (str.length > 0 && (str in this.ops1)) { + this.tokenindex = str; + this.tokenprio = 5; + this.pos += str.length; + return true; + } + return false; + }, + + isOp2: function () { + var str = ""; + for (var i = this.pos; i < this.expression.length; i++) { + var c = this.expression.charAt(i); + if (c.toUpperCase() === c.toLowerCase()) { + if (i === this.pos || (c != '_' && (c < '0' || c > '9'))) { + break; + } + } + str += c; + } + if (str.length > 0 && (str in this.ops2)) { + this.tokenindex = str; + this.tokenprio = 5; + this.pos += str.length; + return true; + } + return false; + }, + + isVar: function () { + var str = ""; + for (var i = this.pos; i < this.expression.length; i++) { + var c = this.expression.charAt(i); + if (c.toUpperCase() === c.toLowerCase()) { + if (i === this.pos || (c != '_' && (c < '0' || c > '9'))) { + break; + } + } + str += c; + } + if (str.length > 0) { + this.tokenindex = str; + this.tokenprio = 4; + this.pos += str.length; + return true; + } + return false; + }, + + isComment: function () { + var code = this.expression.charCodeAt(this.pos - 1); + if (code === 47 && this.expression.charCodeAt(this.pos) === 42) { + this.pos = this.expression.indexOf("*/", this.pos) + 2; + if (this.pos === 1) { + this.pos = this.expression.length; + } + return true; + } + return false; + } + }; + + scope.Parser = Parser; + return Parser +})(typeof exports === 'undefined' ? {} : exports); diff --git a/src/services/AccountService.js b/src/services/AccountService.js index 28951aa..6392560 100644 --- a/src/services/AccountService.js +++ b/src/services/AccountService.js @@ -32,6 +32,52 @@ class AccountService { }); } + newAccount(account) { + return when(request({ + url: ACCOUNT_URL, + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + LoginStore.jwt + }, + data: account + }).then(function(response) { + AccountActions.newAccount(response); + return true; + }) + ) + } + + updateAccount(account) { + return when(request({ + url: ACCOUNT_URL + account.id + '/', + method: 'PUT', + type: 'json', + headers: { + 'Authorization': 'Bearer ' + LoginStore.jwt, + }, + data: account + }).then(function(response) { + AccountActions.updateAccount(response); + return true; + }) + ) + } + + deleteAccount(account) { + return when(request({ + url: ACCOUNT_URL + account.id + '/', + method: 'DELETE', + type: 'json', + headers: { + 'Authorization': 'Bearer ' + LoginStore.jwt, + }, + }).then(function(response) { + AccountActions.deleteAccount(account); + return true; + }) + ) + } + } export default new AccountService() diff --git a/src/services/AuthService.js b/src/services/AuthService.js index 6e819eb..a9a7ddb 100644 --- a/src/services/AuthService.js +++ b/src/services/AuthService.js @@ -3,6 +3,7 @@ import when from 'when'; import {LOGIN_URL, SIGNUP_URL, SOCIAL_LOGIN_URL} from '../constants/LoginConstants'; import LoginActions from '../actions/LoginActions'; + class AuthService { login(username, password) { diff --git a/src/services/TxService.js b/src/services/TxService.js index bc98737..8b0fe0c 100644 --- a/src/services/TxService.js +++ b/src/services/TxService.js @@ -5,7 +5,7 @@ import {TX_URL, TX_LIST_URL_SUFFIX} from '../constants/TxConstants'; import TxActions from '../actions/TxActions'; import LoginStore from '../stores/LoginStore'; -class AccountService { +class TxService { getTxs(accountId) { request({ @@ -51,14 +51,21 @@ class AccountService { ) } - handlePromise(txPromise) { - return txPromise - .then(function(response) { - TxActions.newTx(response); + deleteTx(tx) { + return when(request({ + url: TX_URL + tx.id + '/', + method: 'DELETE', + type: 'json', + headers: { + 'Authorization': 'Bearer ' + LoginStore.jwt, + }, + }).then(function(response) { + TxActions.deleteTx(tx); return true; - }); + }) + ) } } -export default new AccountService() +export default new TxService() diff --git a/src/stores/AccountStore.js b/src/stores/AccountStore.js index 7e34731..29c21e8 100644 --- a/src/stores/AccountStore.js +++ b/src/stores/AccountStore.js @@ -1,4 +1,5 @@ -import {ACCOUNT_GET, ALL_ACCOUNTS_GET} from '../constants/AccountConstants'; +import {ACCOUNT_GET, ALL_ACCOUNTS_GET, ACCOUNT_NEW, + ACCOUNT_UPDATE, ACCOUNT_DELETE} from '../constants/AccountConstants'; import {LOGOUT_USER} from '../constants/LoginConstants'; import BaseStore from './BaseStore'; @@ -21,6 +22,34 @@ class AccountStore extends BaseStore { this._account = action.account; this.emitChange(); break; + case ACCOUNT_NEW: + this._accounts.push(action.account); + this.emitChange(); + break; + case ACCOUNT_UPDATE: + var updated = false; + for (var i=0; i