diff --git a/coffee/components-manager.coffee b/coffee/components-manager.coffee index 92f08bc..6d1c260 100644 --- a/coffee/components-manager.coffee +++ b/coffee/components-manager.coffee @@ -229,6 +229,8 @@ storeRule = ( user, oPayload, callback ) => event_interval: oPayload.event_interval conditions: oPayload.conditions actions: oPayload.actions + if oPayload.event_start + rule.timestamp = (new Date()).toISOString() strRule = JSON.stringify rule # store the rule db.storeRule rule.id, strRule diff --git a/coffee/engine.coffee b/coffee/engine.coffee index 4fd9404..062e0da 100644 --- a/coffee/engine.coffee +++ b/coffee/engine.coffee @@ -181,6 +181,14 @@ pollQueue = () -> processEvent obj setTimeout pollQueue, 20 * numExecutingFunctions #FIXME right way to adapt to load? +oOperators = + '<': ( x, y ) -> x < y + '<=': ( x, y ) -> x <= y + '>': ( x, y ) -> x > y + '>=': ( x, y ) -> x >= y + '==': ( x, y ) -> x is y + 'instr': ( x, y ) -> x.indexOf( y ) > -1 + ### Checks whether all conditions of the rule are met by the event. @@ -188,11 +196,33 @@ Checks whether all conditions of the rule are met by the event. @param {Object} evt @param {Object} rule ### -validConditions = ( evt, rule ) -> +validConditions = ( evt, rule, userId, ruleId ) -> if rule.conditions.length is 0 return true - for prop in rule.conditions - return false if jsonQuery( evt, prop ).nodes().length is 0 + for cond in rule.conditions + selectedProperty = jsonQuery( evt, cond.selector ).nodes() + if selectedProperty.length is 0 + db.appendLog userId, ruleId, 'Condition', "Node not found in event: #{ cond.selector }" + return false + + op = oOperators[ cond.operator ] + if not op + db.appendLog userId, ruleId, 'Condition', "Unknown operator: #{ cond.operator }. + Use one of #{ Object.keys( oOperators ).join ', ' }" + return false + + try + if cond.type is 'string' + val = selectedProperty[ 0 ] + else if cond.type is 'value' + val = parseFloat( selectedProperty[ 0 ] ) || 0 + + if not op val, cond.compare + return false + catch err + db.appendLog userId, ruleId, 'Condition', "Error: Selector '#{ cond.selector }', + Operator #{ cond.operator }, Compare: #{ cond.compare }" + return true ### @@ -213,10 +243,18 @@ processEvent = ( evt ) => arrArgs = [] if node.funcArgs[ funcName ] for oArg in node.funcArgs[ funcName ] - if oArg.jsselector - arrArgs.push jsonQuery( evt.payload, oArg.value ).nodes()[ 0 ] - else - arrArgs.push oArg.value + arrSelectors = oArg.value.match /#\{(.*?)\}/g + argument = oArg.value + for sel in arrSelectors + selector = sel.substring 2, sel.length - 1 + data = jsonQuery( evt.payload, selector ).nodes()[ 0 ] + argument = argument.replace sel, data + if oArg.value is sel + argument = data # if the user wants to pass an object, we allow him to do so + # if oArg.jsselector + arrArgs.push argument #jsonQuery( evt.payload, oArg.value ).nodes()[ 0 ] + # else + # arrArgs.push oArg.value else @log.warn "EN | Weird! arguments not loaded for function '#{ funcName }'!" node.module[ funcName ].apply null, arrArgs @@ -232,7 +270,10 @@ processEvent = ( evt ) => @log.info 'EN | processing event: ' + evt.event + '(' + evt.eventid + ')' for userName, oUser of listUserRules for ruleName, oMyRule of oUser - if evt.event is oMyRule.rule.event and validConditions evt, oMyRule.rule + ruleEvent = oMyRule.rule.event + if oMyRule.rule.timestamp + ruleEvent += '_created:' + oMyRule.rule.timestamp + if evt.event is ruleEvent and validConditions evt, oMyRule.rule, userName, ruleName @log.info 'EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName for action in oMyRule.rule.actions arr = action.split ' -> ' diff --git a/coffee/event-poller.coffee b/coffee/event-poller.coffee index 5756ec4..18acf1d 100644 --- a/coffee/event-poller.coffee +++ b/coffee/event-poller.coffee @@ -35,10 +35,12 @@ log.info 'EP | Event Poller starts up' db logger: log dynmod logger: log + +db.selectDatabase parseInt( process.argv[ 7 ] ) || 0 encryption logger: log - keygen: process.argv[ 7 ] + keygen: process.argv[ 8 ] # Initialize module local variables and listUserModules = {} @@ -94,34 +96,37 @@ fLoadModule = ( msg ) -> listUserModules[msg.user] = {} oUser = listUserModules[msg.user] - ts = new Date() # We open up a new object for the rule it oUser[msg.rule.id] = id: msg.rule.event + timestamp: msg.rule.timestamp pollfunc: arrName[1] funcArgs: result.funcArgs event_interval: msg.rule.event_interval * 60 * 1000 module: result.module logger: result.logger - timestamp: ts oUser[msg.rule.id].module.pushEvent = fPushEvent msg.user, msg.rule.id, oUser[msg.rule.id] start = new Date msg.rule.event_start nd = new Date() + now = new Date() if start < nd # If the engine restarts start could be from last year even - start.setYear nd.getYear() - start.setMonth nd.getMonth() - start.setDate nd.getDate() + nd.setMilliseconds 0 + nd.setSeconds 0 + nd.setMinutes start.getMinutes() + nd.setHours start.getHours() # if it's still smaller we add one day - if start < nd - start.setDate nd.getDate() + 1 + if nd < now + nd.setDate nd.getDate() + 1 + else + nd = start log.info "EP | New event module '#{ arrName[0] }' loaded for user #{ msg.user }, - in rule #{ msg.rule.id }, registered at UTC|#{ ts.toISOString() }, - starting at UTC|#{ start.toISOString() } ( which is in #{ ( start - nd ) / 1000 / 60 } minutes ) + in rule #{ msg.rule.id }, registered at UTC|#{ msg.rule.timestamp }, + starting at UTC|#{ start.toISOString() } ( which is in #{ ( nd - now ) / 1000 / 60 } minutes ) and polling every #{ msg.rule.event_interval } minutes" - setTimeout fCheckAndRun( msg.user, msg.rule.id, ts ), start - nd + setTimeout fCheckAndRun( msg.user, msg.rule.id, msg.rule.timestamp ), nd - now if msg.event is 'new' or not listUserModules[msg.user] or @@ -130,11 +135,10 @@ fLoadModule = ( msg ) -> fPushEvent = ( userId, ruleId, oRule ) -> ( obj ) -> - db.pushEvent - event: oRule.id - eventid: "polled #{ oRule.id } #{ userId }_UTC|#{ ( new Date() ).toISOString() }" - payload: obj - + db.pushEvent + event: oRule.id + '_created:' + oRule.timestamp + eventid: "polled #{ oRule.id } #{ userId }_UTC|#{ ( new Date() ).toISOString() }" + payload: obj fCheckAndRun = ( userId, ruleId, timestamp ) -> () -> log.info "EP | Check and run user #{ userId }, rule #{ ruleId }" @@ -148,20 +152,21 @@ fCheckAndRun = ( userId, ruleId, timestamp ) -> setTimeout fCheckAndRun( userId, ruleId, timestamp ), oRule.event_interval else log.info "EP | We found a newer polling interval and discontinue this one which - was created at UTC|#{ timestamp.toISOString() }" + was created at UTC|#{ timestamp }" # We have to register the poll function in belows anonymous function # because we're fast iterating through the listUserModules and references will # eventually not be what they are expected to be fCallFunction = ( userId, ruleId, oRule ) -> try - arrArgs = [] - if oRule.funcArgs + arrArgs = [] + if oRule.funcArgs and oRule.funcArgs[oRule.pollfunc] for oArg in oRule.funcArgs[oRule.pollfunc] arrArgs.push oArg.value oRule.module[oRule.pollfunc].apply null, arrArgs catch err log.info "EP | ERROR in module when polled: #{ oRule.id } #{ userId }: #{err.message}" + throw err oRule.logger err.message ### This function will loop infinitely every 10 seconds until isRunning is set to false diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 3165e5d..d433636 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -255,6 +255,7 @@ class IndexedModules getModule: ( userId, mId, cb ) => @log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ userId }, #{ mId } )" + @log.info "hgetall user:#{ userId }:#{ @setname }:#{ mId }" @db.hgetall "user:#{ userId }:#{ @setname }:#{ mId }", cb getModuleField: ( userId, mId, field, cb ) => diff --git a/coffee/webapi-eca.coffee b/coffee/webapi-eca.coffee index 19dd2fc..4296cfc 100644 --- a/coffee/webapi-eca.coffee +++ b/coffee/webapi-eca.coffee @@ -187,6 +187,8 @@ init = => args.logconf[ 'file-path' ] # - whether a log file shall be written at all [true|false] args.logconf[ 'nolog' ] + # - The selected database + args[ 'db-select' ] # - The keygen phrase, this has to be handled differently in the future! args[ 'keygen' ] ] diff --git a/js/components-manager.js b/js/components-manager.js index 0a20ce2..3cc3bd5 100644 --- a/js/components-manager.js +++ b/js/components-manager.js @@ -319,6 +319,9 @@ Components Manager conditions: oPayload.conditions, actions: oPayload.actions }; + if (oPayload.event_start) { + rule.timestamp = (new Date()).toISOString(); + } strRule = JSON.stringify(rule); db.storeRule(rule.id, strRule); db.linkRule(rule.id, user.username); diff --git a/js/engine.js b/js/engine.js index 76130cb..a0c28bd 100644 --- a/js/engine.js +++ b/js/engine.js @@ -10,7 +10,7 @@ Engine */ (function() { - var db, dynmod, exports, isRunning, jsonQuery, listUserRules, numExecutingFunctions, pollQueue, processEvent, updateActionModules, validConditions; + var db, dynmod, exports, isRunning, jsonQuery, listUserRules, numExecutingFunctions, oOperators, pollQueue, processEvent, updateActionModules, validConditions; db = require('./persistence'); @@ -219,6 +219,27 @@ Engine } }; + oOperators = { + '<': function(x, y) { + return x < y; + }, + '<=': function(x, y) { + return x <= y; + }, + '>': function(x, y) { + return x > y; + }, + '>=': function(x, y) { + return x >= y; + }, + '==': function(x, y) { + return x === y; + }, + 'instr': function(x, y) { + return x.indexOf(y) > -1; + } + }; + /* Checks whether all conditions of the rule are met by the event. @@ -228,17 +249,37 @@ Engine @param {Object} rule */ - validConditions = function(evt, rule) { - var prop, _i, _len, _ref; + validConditions = function(evt, rule, userId, ruleId) { + var cond, err, op, selectedProperty, val, _i, _len, _ref; if (rule.conditions.length === 0) { return true; } _ref = rule.conditions; for (_i = 0, _len = _ref.length; _i < _len; _i++) { - prop = _ref[_i]; - if (jsonQuery(evt, prop).nodes().length === 0) { + cond = _ref[_i]; + selectedProperty = jsonQuery(evt, cond.selector).nodes(); + if (selectedProperty.length === 0) { + db.appendLog(userId, ruleId, 'Condition', "Node not found in event: " + cond.selector); return false; } + op = oOperators[cond.operator]; + if (!op) { + db.appendLog(userId, ruleId, 'Condition', "Unknown operator: " + cond.operator + ". Use one of " + (Object.keys(oOperators).join(', '))); + return false; + } + try { + if (cond.type === 'string') { + val = selectedProperty[0]; + } else if (cond.type === 'value') { + val = parseFloat(selectedProperty[0]) || 0; + } + if (!op(val, cond.compare)) { + return false; + } + } catch (_error) { + err = _error; + db.appendLog(userId, ruleId, 'Condition', "Error: Selector '" + cond.selector + "', Operator " + cond.operator + ", Compare: " + cond.compare); + } } return true; }; @@ -253,9 +294,9 @@ Engine processEvent = (function(_this) { return function(evt) { - var action, arr, fSearchAndInvokeAction, oMyRule, oUser, ruleName, userName, _results; + var action, arr, fSearchAndInvokeAction, oMyRule, oUser, ruleEvent, ruleName, userName, _results; fSearchAndInvokeAction = function(node, arrPath, funcName, evt, depth) { - var arrArgs, err, oArg, _i, _len, _ref; + var argument, arrArgs, arrSelectors, data, err, oArg, sel, selector, _i, _j, _len, _len1, _ref; if (!node) { _this.log.error("EN | Didn't find property in user rule list: " + arrPath.join(', ') + " at depth " + depth); return; @@ -269,11 +310,18 @@ Engine _ref = node.funcArgs[funcName]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { oArg = _ref[_i]; - if (oArg.jsselector) { - arrArgs.push(jsonQuery(evt.payload, oArg.value).nodes()[0]); - } else { - arrArgs.push(oArg.value); + arrSelectors = oArg.value.match(/#\{(.*?)\}/g); + argument = oArg.value; + for (_j = 0, _len1 = arrSelectors.length; _j < _len1; _j++) { + sel = arrSelectors[_j]; + selector = sel.substring(2, sel.length - 1); + data = jsonQuery(evt.payload, selector).nodes()[0]; + argument = argument.replace(sel, data); + if (oArg.value === sel) { + argument = data; + } } + arrArgs.push(argument); } } else { _this.log.warn("EN | Weird! arguments not loaded for function '" + funcName + "'!"); @@ -301,7 +349,11 @@ Engine _results1 = []; for (ruleName in oUser) { oMyRule = oUser[ruleName]; - if (evt.event === oMyRule.rule.event && validConditions(evt, oMyRule.rule)) { + ruleEvent = oMyRule.rule.event; + if (oMyRule.rule.timestamp) { + ruleEvent += '_created:' + oMyRule.rule.timestamp; + } + if (evt.event === ruleEvent && validConditions(evt, oMyRule.rule, userName, ruleName)) { this.log.info('EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName); _results1.push((function() { var _i, _len, _ref, _results2; diff --git a/js/event-poller.js b/js/event-poller.js index 7959356..5c6f452 100644 --- a/js/event-poller.js +++ b/js/event-poller.js @@ -47,9 +47,11 @@ Dynamic Modules logger: log }); + db.selectDatabase(parseInt(process.argv[7]) || 0); + encryption({ logger: log, - keygen: process.argv[7] + keygen: process.argv[8] }); listUserModules = {}; @@ -84,7 +86,7 @@ Dynamic Modules return log.warn("EP | Strange... no module retrieved: " + arrName[0]); } else { return dynmod.compileString(obj.data, msg.user, msg.rule.id, arrName[0], obj.lang, db.eventPollers, function(result) { - var nd, oUser, start, ts; + var nd, now, oUser, start; if (!result.answ === 200) { log.error("EP | Compilation of code failed! " + msg.user + ", " + msg.rule.id + ", " + arrName[0]); } @@ -92,29 +94,32 @@ Dynamic Modules listUserModules[msg.user] = {}; } oUser = listUserModules[msg.user]; - ts = new Date(); oUser[msg.rule.id] = { id: msg.rule.event, + timestamp: msg.rule.timestamp, pollfunc: arrName[1], funcArgs: result.funcArgs, event_interval: msg.rule.event_interval * 60 * 1000, module: result.module, - logger: result.logger, - timestamp: ts + logger: result.logger }; oUser[msg.rule.id].module.pushEvent = fPushEvent(msg.user, msg.rule.id, oUser[msg.rule.id]); start = new Date(msg.rule.event_start); nd = new Date(); + now = new Date(); if (start < nd) { - start.setYear(nd.getYear()); - start.setMonth(nd.getMonth()); - start.setDate(nd.getDate()); - if (start < nd) { - start.setDate(nd.getDate() + 1); + nd.setMilliseconds(0); + nd.setSeconds(0); + nd.setMinutes(start.getMinutes()); + nd.setHours(start.getHours()); + if (nd < now) { + nd.setDate(nd.getDate() + 1); } + } else { + nd = start; } - log.info("EP | New event module '" + arrName[0] + "' loaded for user " + msg.user + ", in rule " + msg.rule.id + ", registered at UTC|" + (ts.toISOString()) + ", starting at UTC|" + (start.toISOString()) + " ( which is in " + ((start - nd) / 1000 / 60) + " minutes ) and polling every " + msg.rule.event_interval + " minutes"); - return setTimeout(fCheckAndRun(msg.user, msg.rule.id, ts), start - nd); + log.info("EP | New event module '" + arrName[0] + "' loaded for user " + msg.user + ", in rule " + msg.rule.id + ", registered at UTC|" + msg.rule.timestamp + ", starting at UTC|" + (start.toISOString()) + " ( which is in " + ((nd - now) / 1000 / 60) + " minutes ) and polling every " + msg.rule.event_interval + " minutes"); + return setTimeout(fCheckAndRun(msg.user, msg.rule.id, msg.rule.timestamp), nd - now); }); } }); @@ -127,7 +132,7 @@ Dynamic Modules fPushEvent = function(userId, ruleId, oRule) { return function(obj) { return db.pushEvent({ - event: oRule.id, + event: oRule.id + '_created:' + oRule.timestamp, eventid: "polled " + oRule.id + " " + userId + "_UTC|" + ((new Date()).toISOString()), payload: obj }); @@ -144,7 +149,7 @@ Dynamic Modules fCallFunction(userId, ruleId, oRule); return setTimeout(fCheckAndRun(userId, ruleId, timestamp), oRule.event_interval); } else { - return log.info("EP | We found a newer polling interval and discontinue this one which was created at UTC|" + (timestamp.toISOString())); + return log.info("EP | We found a newer polling interval and discontinue this one which was created at UTC|" + timestamp); } } }; @@ -154,7 +159,7 @@ Dynamic Modules var arrArgs, err, oArg, _i, _len, _ref; try { arrArgs = []; - if (oRule.funcArgs) { + if (oRule.funcArgs && oRule.funcArgs[oRule.pollfunc]) { _ref = oRule.funcArgs[oRule.pollfunc]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { oArg = _ref[_i]; @@ -165,6 +170,7 @@ Dynamic Modules } catch (_error) { err = _error; log.info("EP | ERROR in module when polled: " + oRule.id + " " + userId + ": " + err.message); + throw err; return oRule.logger(err.message); } }; diff --git a/js/persistence.js b/js/persistence.js index f6d2364..70f9823 100644 --- a/js/persistence.js +++ b/js/persistence.js @@ -301,6 +301,7 @@ Persistence IndexedModules.prototype.getModule = function(userId, mId, cb) { this.log.info("DB | (IdxedMods) " + this.setname + ".getModule( " + userId + ", " + mId + " )"); + this.log.info("hgetall user:" + userId + ":" + this.setname + ":" + mId); return this.db.hgetall("user:" + userId + ":" + this.setname + ":" + mId, cb); }; diff --git a/js/webapi-eca.js b/js/webapi-eca.js index 95d97ce..68a9a21 100644 --- a/js/webapi-eca.js +++ b/js/webapi-eca.js @@ -167,7 +167,7 @@ WebAPI-ECA Engine _this.log.info('RS | Initialzing engine'); engine(args); _this.log.info('RS | Forking a child process for the event poller'); - cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog'], args['keygen']]; + cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog'], args['db-select'], args['keygen']]; poller = cp.fork(path.resolve(__dirname, nameEP), cliArgs); _this.log.info('RS | Initialzing module manager'); cm(args); diff --git a/testing/files/testObjects.json b/testing/files/testObjects.json index 3f75f77..1d27a5d 100644 --- a/testing/files/testObjects.json +++ b/testing/files/testObjects.json @@ -81,13 +81,21 @@ "id": "ruleReal", "event": "test_1", "event_interval": 1, - "conditions": [".more:val(\"really nested\")"], + "conditions": + [ + { + "selector": ".more", + "type": "string", + "operator": "instr", + "compare": "really nested" + } + ], "actions": ["aiOne -> printToLog"], "action_functions": { "aiOne -> printToLog": [ { "argument": "evt", - "value": "*", + "value": "#{*}", "jsselector": true } ] diff --git a/webpages/handlers/coffee/forge_rule.coffee b/webpages/handlers/coffee/forge_rule.coffee index 7f4cce6..9b3c501 100644 --- a/webpages/handlers/coffee/forge_rule.coffee +++ b/webpages/handlers/coffee/forge_rule.coffee @@ -175,7 +175,7 @@ fOnLoad = () -> tr = $( "tr", par ).filter () -> $( '.funcarg', this ).text() is "#{ oFunc.argument }" $( "input[type=text]", tr ).val oFunc.value - $( "input[type=checkbox]", tr ).prop 'checked', oFunc.jsselector + # $( "input[type=checkbox]", tr ).prop 'checked', oFunc.jsselector # ACTIONS obj = @@ -265,9 +265,9 @@ fOnLoad = () -> td = $( '' ).appendTo tr td.append $( '' ).attr 'type', 'text' tr.append td - td = $( '' ).appendTo tr - td.append $( '' ).attr( 'type', 'checkbox' ) - .attr 'title', 'js-select expression to be resolved on event?' + # td = $( '' ).appendTo tr + # td.append $( '' ).attr( 'type', 'checkbox' ) + # .attr 'title', 'js-select expression to be resolved on event?' .fail fFailedRequest 'Error fetching action invoker function params' fFillActionFunction = ( name ) -> @@ -307,7 +307,7 @@ fOnLoad = () -> tr = $( "tr", par ).filter () -> $( '.funcarg', this ).text() is "#{ oFunc.argument }" $( "input[type=text]", tr ).val oFunc.value - $( "input[type=checkbox]", tr ).prop 'checked', oFunc.jsselector + # $( "input[type=checkbox]", tr ).prop 'checked', oFunc.jsselector $( '#select_actions' ).on 'change', () -> opt = $ 'option:selected', this @@ -413,7 +413,7 @@ fOnLoad = () -> actFuncs[ actionName ].push argument: $( 'div.funcarg', this ).text() value: $( 'input[type=text]', this ).val() - jsselector: $( 'input[type=checkbox]', this ).is( ':checked' ) + # jsselector: $( 'input[type=checkbox]', this ).is( ':checked' ) try conds = JSON.parse editor.getValue() @@ -429,7 +429,6 @@ fOnLoad = () -> if not txtStart start.setHours 12 start.setMinutes 0 - console.log 'setting to 12:00: ' + start.toString() else arrInp = txtStart.split ':' # There's only one string entered: hour @@ -443,7 +442,7 @@ fOnLoad = () -> start.setMinutes m intHour = parseInt( txtHr ) || 12 - h = Math.max 0, Math.min intHour, 12 + h = Math.max 0, Math.min intHour, 24 start.setHours h start.setSeconds 0 diff --git a/webpages/handlers/js/forge_rule.js b/webpages/handlers/js/forge_rule.js index 27c6224..82a80ff 100644 --- a/webpages/handlers/js/forge_rule.js +++ b/webpages/handlers/js/forge_rule.js @@ -241,8 +241,7 @@ tr = $("tr", par).filter(function() { return $('.funcarg', this).text() === ("" + oFunc.argument); }); - $("input[type=text]", tr).val(oFunc.value); - _results1.push($("input[type=checkbox]", tr).prop('checked', oFunc.jsselector)); + _results1.push($("input[type=text]", tr).val(oFunc.value)); } return _results1; })()); @@ -370,9 +369,7 @@ tr.append(td); td = $('').appendTo(tr); td.append($('').attr('type', 'text')); - tr.append(td); - td = $('').appendTo(tr); - _results.push(td.append($('').attr('type', 'checkbox')).attr('title', 'js-select expression to be resolved on event?')); + _results.push(tr.append(td)); } return _results; } @@ -435,8 +432,7 @@ tr = $("tr", par).filter(function() { return $('.funcarg', this).text() === ("" + oFunc.argument); }); - $("input[type=text]", tr).val(oFunc.value); - _results1.push($("input[type=checkbox]", tr).prop('checked', oFunc.jsselector)); + _results1.push($("input[type=text]", tr).val(oFunc.value)); } return _results1; })()); @@ -554,8 +550,7 @@ return $('.funcMappings tr', par).each(function() { return actFuncs[actionName].push({ argument: $('div.funcarg', this).text(), - value: $('input[type=text]', this).val(), - jsselector: $('input[type=checkbox]', this).is(':checked') + value: $('input[type=text]', this).val() }); }); }); @@ -573,7 +568,6 @@ if (!txtStart) { start.setHours(12); start.setMinutes(0); - console.log('setting to 12:00: ' + start.toString()); } else { arrInp = txtStart.split(':'); if (arrInp.length === 1) { @@ -587,7 +581,7 @@ } } intHour = parseInt(txtHr) || 12; - h = Math.max(0, Math.min(intHour, 12)); + h = Math.max(0, Math.min(intHour, 24)); start.setHours(h); start.setSeconds(0); start.setMilliseconds(0); diff --git a/webpages/handlers/templates/forge_rule.html b/webpages/handlers/templates/forge_rule.html index d67d444..29f9a41 100644 --- a/webpages/handlers/templates/forge_rule.html +++ b/webpages/handlers/templates/forge_rule.html @@ -12,7 +12,12 @@ Refer to [ - ".nested_property:val(\"has this value\")" + { + "selector": ".nested_property", + "type": "string", + "operator": "<=", + "compare": "has this value" + } ] diff --git a/webpages/public/style.css b/webpages/public/style.css index fe613c4..0cb537d 100644 --- a/webpages/public/style.css +++ b/webpages/public/style.css @@ -108,7 +108,7 @@ input[type=password]:focus { float: left; border: 1px solid lightgray; margin: auto; - height: 100px; + height: 150px; width: 400px; }