<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!DOCTYPE html><html lang='en' class=''>
<head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-079c09a0e3b9ff743e39ee2d5637b9216b3545af0de366d4b9aad9dc87e26bfd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-73716630c22bbc8cff4bd0f07b135f00a0bdc5d14629260c3ec49e5606f98fdd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-2c0dc5167d60a5af3ee189d570b1835129687ea2a61bee3513dee3a50c115a77.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="https://codepen.io/bernesto/pen/ybzbKW?depth=everything&order=popularity&page=48&q=Builder&show_forks=false" />
<link rel='stylesheet prefetch' href='https://static.neoreef.com/common/fonts/fontawesome/4.7.0/css/font-awesome.min.css'>
<style class="cp-pen-styles">#program{
font-family: sans-serif;
font-size: 14px;
background-color:#ededed;
border-radius: 0.5em;
padding: 0.5em 1em;
margin: 0.5em 0px;
}
#statements, #objects{
padding-left: 0;
}
#program .fa{
font-size: 1em;
}
#statements, #objects{
line-height: 2em
}
.statement{
background-color:rgba(0,0,0,0.2);
border: 1px solid transparent;
border-radius: 0.5em;
padding: 0.5em 1em;
margin: 0.5em 0px;
display: block;
transition: border 1s, box-shadow 1s;
}
.group{
background-color:rgba(0,255,0,0.2);
padding: 1px 9px;
margin: 1px;
border-radius: 4px;
display: inline-block;
}
.segment{
background-color:rgba(0,0,255,0.2);
padding: 1px 9px;
margin: 1px;
border-radius: 4px;
display: inline-block;
}
.condition{
background-color:white;
padding: 0 6px;
margin: 1px;
border-radius: 4px;
display: inline-block;
line-height: 1.7em;
}
#statements input, #statements textarea, #objects input{
border: 1px solid transparent;
padding: 3px;
}
#statements button{
border: 1px solid transparent;
padding: 3px 5px;
border-radius: 4px;
background-color: #ededed;
}
#statements li{
list-style-type: none;
}
#statements .error{
border: 1px solid red;
}
.nowrap{
whitespace: nowrap;
}
.evaluated{
border: 1px solid rgb(0,100,250);
box-shadow: 0px 0px 10px rgb(0,100,250);
}
</style></head><body>
<div id="program">
<script type="text/html" id="group">
<select data-bind="
visible: (($index() > 0 && $parent.groups) || ($parent.conditions && $parent.conditions().length > 0)),
options: booleanTypes(),
optionsText: 'label',
optionsValue: 'value',
value: boolean, valueAllowUnset: true
"></select>
<span class="group">
(
<span data-bind="template: {if: conditions, name: 'condition', foreach: conditions}"></span>
<span data-bind="template: {if: groups, name: 'group', foreach: groups}"></span>
<button data-bind="click: addCondition,
css: {
error: (conditions().length == 0 && groups().length == 0)
},
visible: (groups().length == 0)
"><i class="fa fa-plus-square"></i> Condition</button>
<button data-bind="
click: addGroup,
css: {
error: (conditions().length == 0 && (groups().length == 0))
},
visible: (conditions().length == 0)
"><i class="fa fa-plus-square-o"></i> Group</button>
)
<button data-bind="
visible: $parent.conditions,
click: $parent.removeGroup
"><i class="fa fa-trash"></i></button>
</span>
</script>
<script type="text/html" id="condition">
<select data-bind="visible: ($index() > 0), options: booleanTypes(), optionsText: 'label', optionsValue: 'value', value: boolean, valueAllowUnset: true"></select>
<span class="condition nowrap">
<input data-bind="datalist: {
options: $root.objects(1),
optionsText: 'name'
},
value: value1,
valueUpdate: 'afterkeydown'" placeholder="empty" size="10" type="text" list="value1List">
<select data-bind="options: conditionTypes(), optionsText: 'label', optionsValue: 'value', value: conditionType"></select>
<input data-bind="datalist: {
options: $root.objects(1),
optionsText: 'name'
},
value: value2,
valueUpdate: 'afterkeydown'" placeholder="empty" size="10" type="text" list="value1List">
<button data-bind="click: $parent.removeCondition" class="fa fa-trash"></button>
</span>
</script>
<script type="text/html" id="event">
<span class="group"><select data-bind="options: formEvents, optionsText: 'name', value: eventObject, valueAllowUnset: true, optionsCaption: 'Choose...', css: {error: !eventObject()}, disable: disabled"></select>
<span data-bind="with: eventObject">
<select data-bind="options: events, value: event, valueAllowUnset: true, optionsCaption: 'Choose...', css: {error: !event}, disable: $parent.disabled"></select>
</span>
</span>
<span class="segment">Then</span>
<ul data-bind="template: {if: statements, name: 'statement-template', foreach: statements }"></ul>
<ul>
<li><button data-bind="click: addStatement, css: {error: statements().length == 0}"><i class="fa fa-plus"></i> Statement</button></li>
</ul>
<span class="segment">End Event</span>
</script>
<script type="text/html" id="if">
<span data-bind="template: {if: expression, name: 'group', data: expression}"></span>
<span class="segment">Then</span>
<ul data-bind="template: {if: statements, name: 'statement-template', foreach: statements }"></ul>
<ul>
<li><button data-bind="click: addStatement, css: {error: statements().length == 0}"><i class="fa fa-plus"></i> Statement</button></li>
</ul>
<span class="segment">End If</span>
</script>
<script type="text/html" id="ifelse">
<span data-bind="template: {if: expression, name: 'group', data: expression}"></span>
<span class="segment">Then</span>
<ul data-bind="template: {if: statements, name: 'statement-template', foreach: statements }"></ul>
<ul>
<li><button data-bind="click: addStatement, css: {error: !statements() || statements().length == 0}"><i class="fa fa-plus"></i> Statement</button></li>
</ul>
<span class="segment">Else</span>
<ul data-bind="template: {if: elseStatements, name: 'else-statement-template', foreach: elseStatements }"></ul>
<ul>
<li><button data-bind="click: addElseStatement, css: {error: !elseStatements() || elseStatements().length == 0}"><i class="fa fa-plus"></i> Statement</button></li>
</ul>
<span class="segment">End If-Else</span>
</script>
<script type="text/html" id="variable">
<span class="group"><input data-bind="datalist: {
options: $root.objects(2),
optionsText: 'name'
},
value: variableName,
valueUpdate: 'afterkeydown', css: {error: variableName() == ''}" placeholder="name" size="10" type="text" list="nameList">
=
<input data-bind="datalist: {
options: $root.objects(1),
optionsText: 'name'
},
value: variableValue,
valueUpdate: 'afterkeydown'" placeholder="empty" size="10" type="text" list="valueList"></span>
</script>
<script type="text/html" id="stop">
<span class="group">Stop Processing</span>
</script>
<script type="text/html" id="action">
<span class="group"><select data-bind="options: actionTypes(), optionsText: 'label', optionsValue: 'value', value: actionType, valueAllowUnset: true, optionsCaption: 'Choose...', css: {error: !actionType()}"></select></span>
<span data-bind='template: {if: actionType, name: actionType}'></span>
</script>
<script type="text/html" id="email">
<div>
<input data-bind="
value: $data.actionData().from,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().from && $data.actionData().from() == '')}
" placeholder="from" style="width: 25%">
<input data-bind="
value: $data.actionData().to,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().to && $data.actionData().to() == '')}
" placeholder="to" style="width: 25%">
</div>
<input data-bind="
value: $data.actionData().subject,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().subject && $data.actionData().subject() == '')}
" placeholder="subject" style="width: 99%">
<textarea data-bind="
value: $data.actionData().message,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().message && $data.actionData().message() == '')}
" placeholder="message" style="width: 99%" rows="5"></textarea>
</script>
<script type="text/html" id="message">
<textarea data-bind="
value: $data.actionData().message,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().message && $data.actionData().message() == '')}
" placeholder="message" style="width: 99%" rows="5"></textarea>
</script>
<script type="text/html" id="post">
<input data-bind="
value: $data.actionData().url,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().url && $data.actionData().url() == '')}
" placeholder="url" style="width: 99%">
<textarea data-bind="
value: $data.actionData().body,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().body && $data.actionData().body() == '')}
" placeholder="body" style="width: 99%" rows="5"></textarea>
</script>
<script type="text/html" id="redirect">
<input data-bind="
value: $data.actionData().url,
valueUpdate: 'afterkeydown',
css: {error: ($data.actionData().url && $data.actionData().url() == '')}
" placeholder="url" style="width: 99%">
</script>
<script type="text/html" id="submit">
<!-- Do nothing -->
</script>
<script type="text/html" id="click">
<input data-bind="datalist: {
options: $root.objects(3),
optionsText: 'name'
},
value: $data.eventData().name,
valueUpdate: 'afterkeydown', css: {error: $data.eventData().name == ''}" placeholder="event name" size="10" type="text" list="nameList">
</script>
<script type="text/html" id="change">
<input data-bind="datalist: {
options: $root.objects(4),
optionsText: 'name'
},
enabled: $data.enabled,
value: $data.eventData().name,
valueUpdate: 'afterkeydown', css: {error: $data.eventData().name == ''}" placeholder="event name" size="10" type="text" list="nameList">
</script>
<script type="text/html" id="statement-template">
<li class="statement" data-bind="css: {evaluated: evaluated}">
<div>
<button data-bind="click: $parent.removeStatement, visible: !disabled()" class="fa fa-trash"></button>
<button data-bind="visible: ($index() > 0), click: $parent.moveUpStatement" class="fa fa-angle-up"></button>
<button data-bind="visible: ($index() < $parent.statements().length - 1), click: $parent.moveDownStatement" class="fa fa-angle-down"></button>
</div>
<span class="segment"><select data-bind="options: statementTypes(), optionsText: 'label', optionsValue: 'value', value: statementType, valueAllowUnset: true, optionsCaption: 'Choose...', css: {error: !statementType()}, disable: disabled"></select></span>
<span data-bind="template: {if: statementType, name: statementType}"></span>
</li>
</script>
<script type="text/html" id="else-statement-template">
<li class="statement" data-bind="css: {evaluated: evaluated}">
<div>
<button data-bind="click: $parent.removeElseStatement" class="fa fa-trash"></button>
<button data-bind="visible: ($index() > 0), click: $parent.moveUpElseStatement" class="fa fa-angle-up"></button>
<button data-bind="visible: ($index() < $parent.elseStatements().length - 1), click: $parent.moveDownElseStatement" class="fa fa-angle-down"></button>
</div>
<select data-bind="options: statementTypes(), optionsText: 'label', optionsValue: 'value', value: statementType"></select>
<span data-bind='template: {if: statementType, name: statementType}'></span>
</li>
</script>
<div id="program-ui">
<div><button style="float: right" data-bind="click: evaluate, visible: statements().length > 0"><i class="fa fa-check-circle"></i> Evaluate Logic</button><h2>Form Logic</h2></div>
<h4>Fields</h4>
<ul id="objects" data-bind="foreach: objects(0)">
<li class="statement"><span class="group"><input data-bind="value: name" disabled>=<input placeholder="empty" data-bind="value: value"></span></li>
</ul>
<h4>Events</h4>
<ul id="statements" data-bind="template: {if: statements, name: 'statement-template', foreach: statements }"></ul>
<div style="text-align: center">
<button data-bind="click: addStatement"><i class="fa fa-plus"></i> Statement</button>
</div>
</div>
<fieldset data-bind="visible: output"><legend>Evaluation Results</legend>
<div style="padding: 0em 5em" data-bind="html: output"></div>
</fieldset>
<textarea data-bind="value: ko.toJSON($rawData, null, 2)"></textarea>
</div>
<script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-b2a7b3fe212eaa732349046d8416e00a9dec26eb7fd347590fbced3ab38af52e.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script><script src='https://static.neoreef.com/common/js/libs/knockout/3.2.0/knockout-3.2.0.min.js'></script>
<script >$(function(){
if(console) console.clear();
ko.bindingHandlers.datalist = (function () {
var uid = 0;
function createId() {
return "ko-datalist-" + (++uid);
}
function getVal(rawItem, prop) {
var item = ko.unwrap(rawItem);
return item && prop ? ko.unwrap(item[prop]) : item;
}
function findItem(options, prop, ref) {
return ko.utils.arrayFirst(options, function (item) {
return ref === getVal(item, prop);
});
}
return {
after: ['value'],
init: function (element, valueAccessor, allBindingsAccessor) {
var setup = valueAccessor(),
textProperty = ko.unwrap(setup.optionsText),
valueProperty = ko.unwrap(setup.optionsValue),
dataItems = ko.unwrap(setup.options),
myValue = setup.value,
datalist = document.createElement("DATALIST"),
shouldSet = false;
// create an associated <datalist> element
var id = createId();
element.setAttribute("list", id);
datalist.id = id;
if (element.parentNode) {
element.parentNode.appendChild(datalist);
} else {
document.body.appendChild(datalist);
}
// when the value is changed, write to the associated myValue observable
function updateModel() {
if (!shouldSet) {
return;
}
var newVal = element.value,
dataItems = ko.unwrap(setup.options),
selectedItem = findItem(dataItems, textProperty, newVal),
newValue = selectedItem ? getVal(selectedItem, valueProperty) : newVal;
if (ko.isWriteableObservable(myValue)) {
myValue(newValue);
}
}
function updateView() {
var modelValue = ko.unwrap(myValue),
dataItems = ko.unwrap(setup.options),
selectedItem = findItem(dataItems, valueProperty, modelValue),
newValue = selectedItem ? getVal(selectedItem, textProperty) : undefined;
element.value = newValue || element.value;
}
// The first responds to changes in the value and to element changes
ko.dependentObservable(updateModel, null, { disposeWhenNodeIsRemoved: element });
ko.utils.registerEventHandler(element, "change", updateModel);
// The second responds to changes in the model value (the one associated with the checked binding)
ko.dependentObservable(updateView, null, { disposeWhenNodeIsRemoved: element });
shouldSet = true;
},
update: function (element, valueAccessor) {
var setup = valueAccessor(),
datalist = element.list,
dataItems = ko.unwrap(setup.options),
textProperty = ko.unwrap(setup.optionsText),
valueProperty = ko.unwrap(setup.optionsValue),
descriptionProperty = ko.unwrap(setup.optionsDescription);
// rebuild list of options when an underlying observable changes
datalist.innerHTML = "";
ko.utils.arrayForEach(dataItems, function (item) {
var option = document.createElement("OPTION");
option.value = getVal(item, textProperty);
if (descriptionProperty) {
option.innerText = getVal(item, descriptionProperty);
}
datalist.appendChild(option);
});
ko.utils.triggerEvent(element, "change");
}
};
})();
ko.observableArray.fn.move = function (from, to) {
if (from !== to &&
0 <= from && from <= this().length &&
0 <= to && to <= this().length) {
this.splice(to, 0, this.splice(from, 1)[0]);
}
};
var dataModel = function(init){
var self = this;
init = init||[];
for(var i = 0; i < init.length; i++){if (window.CP.shouldStopExecution(1)){break;}
if(Array.isArray(init[i].value)){
self[init[i].property] = ko.observableArray(init[i].value)
}else{
self[init[i].property] = ko.observable(init[i].value)
}
}
window.CP.exitedLoop(1);
}
var groupModel = function(init, scope){
var self = this;
init=init||{};
self.booleanTypes = function(){ return [
{"label":"AND", "value":"and"},
{"label":"OR", "value":"or"}
]};
self.boolean = ko.observable(init.boolean);
self.conditions = ko.observableArray((function(data){
var ar = [];
if(data){
for(var i = 0; i < data.length; i++){if (window.CP.shouldStopExecution(2)){break;}
ar.push(new conditionModel(data[i], scope));
}
window.CP.exitedLoop(2);
}
return ar;
})(init.conditions));
self.groups = ko.observableArray((function(data){
var ar = [];
if(data){
for(var i = 0; i < data.length; i++){if (window.CP.shouldStopExecution(3)){break;}
ar.push(new groupModel(data[i], scope));
}
window.CP.exitedLoop(3);
}
return ar;
})(init.groups));
self.addCondition = function(){
self.conditions.push(new conditionModel({}, scope));
};
self.removeCondition = function(){
self.conditions.remove(this);
};
self.addGroup = function(){
self.groups.push(new groupModel({}, scope));
};
self.removeGroup = function(){
self.groups.remove(this);
};
self.evaluate = function(){
var boolean = ""
var result = true;
$.each(self.conditions(), function(index, condition){
boolean = condition.boolean();
if(boolean == "and"){
result = (result && condition.evaluate());
}else{
result = (result || condition.evaluate());
}
});
$.each(self.groups(), function(index, group){
boolean = group.boolean();
if(boolean == "and"){
result = (result && group.evaluate());
}else{
result = (result || group.evaluate());
}
});
return result;
}
};
var conditionModel = function(init, scope){
var self = this;
init=init||{};
self.booleanTypes = function(){ return [
{"label":"AND", "value":"and"},
{"label":"OR", "value":"or"}
]};
self.boolean = ko.observable(init.boolean);
self.value1 = ko.observable(init.value1||"");
self.conditionTypes = function(){ return [
{"label":"==", "value":"=="},
{"label":"<>", "value":"<>"},
{"label":">=", "value":">="},
{"label":"<=", "value":"<="},
{"label":">", "value":">"},
{"label":"<", "value":"<"},
{"label":"In", "value":"in"}
]};
self.conditionType = ko.observable(init.conditionType||"==");
self.value2 = ko.observable(init.value2||"");
self.evaluate = function(){
var result = false;
var v1, v2;
if(scope.variables[self.value1()] != undefined){
v1 = scope.variables[self.value1()];
}else{
v1 = self.value1();
}
if(scope.variables[self.value2()] != undefined){
v2 = scope.variables[self.value2()];
}else{
v2 = self.value2();
}
switch(self.conditionType()){
case "==":
result = v1 == v2;
break;
case "<>":
result = v1 != v2;
break;
case ">=":
result = v1 >= v2;
break;
case "<=":
result = v1 <= v2;
break;
case ">":
result = v1 > v2;
break;
case "<":
result = v1 < v2;
break;
case "in":
result = v1.indexOf(v2) > 0;
break;
}
return result;
}
};
var statementModel = function(init, scope){
var self = this;
init=init||{};
// Setup statements
self.statementTypes = function(){return [
{"label":"Action", "value":"action"},
{"label":"On Event", "value":"event"},
{"label":"If", "value":"if"},
{"label":"If-Else", "value":"ifelse"},
{"label":"Set Variable", "value":"variable"},
{"label":"Stop", "value":"stop"}
]};
self.statementType = ko.observable();
self.disabled = ko.observable(init.disabled||false);
// Set up actions
self.actionTypes = function(){ return [
{"label":"Display Message", "value":"message"},
{"label":"Send Email", "value":"email"},
{"label":"Redirect", "value":"redirect"},
{"label":"Post Values", "value":"post"}
]};
self.actionType = ko.observable();
self.actionData = ko.observable();
var actionConfig = function(val, data){
data = data||{};
switch(val){
case "message":
return new dataModel([
{"property":"message", "value": data.message||""}
]);
case "email":
return new dataModel([
{"property":"to", "value": data.to||""},
{"property":"from", "value": data.from||""},
{"property":"subject", "value": data.subject||""},
{"property":"message", "value": data.message||""}
]);
case "post":
return new dataModel([
{"property":"url", "value": data.url||""},
{"property":"body", "value": data.body||""}
]);
case "redirect":
return new dataModel([
{"property":"url", "value": data.url||""}
]);
default:
return {};
}
}
// Set up events
self.eventObject = ko.observable();
self.formEvents = ko.observableArray(scope.objects(3)());
for(i=0;i<self.formEvents().length;i++){if (window.CP.shouldStopExecution(5)){break;}
if(init.statementType == "event"){
var evo = self.formEvents()[i]
var evs = evo.events()
if(evs){
for(p=0;p<evs.length;p++){if (window.CP.shouldStopExecution(4)){break;}
if(init.eventObject.id == evo.id && init.eventObject.event == evs[p]){
evo.event(evs[p]);
self.eventObject(evo);
}
}
window.CP.exitedLoop(4);
}
}
}
window.CP.exitedLoop(5);
// Setup conditional expression
self.expression = ko.observable(new groupModel(init.expression, scope));
// Setup statements
self.statements = ko.observableArray((function(data){
var ar = [];
if(data){
for(i=0;i<data.length; i++){if (window.CP.shouldStopExecution(6)){break;}
ar.push(new statementModel(data[i], scope));
}
window.CP.exitedLoop(6);
}
return ar;
})(init.statements));
self.addStatement = function(){
self.statements.push(new statementModel({}, scope));
scope.reset();
};
self.removeStatement = function(val){
self.statements.remove(this);
scope.reset();
};
self.moveUpStatement = function(){
var from = self.statements.indexOf(this);
self.statements.move(from, from - 1);
scope.reset();
};
self.moveDownStatement = function(){
var from = self.statements.indexOf(this);
self.statements.move(from, from + 1);
scope.reset();
};
// Setup else statements
self.elseStatements = ko.observableArray((function(data){
var ar = [];
if(data){
for(var i = 0; i < data.length; i++){if (window.CP.shouldStopExecution(7)){break;}
ar.push(new statementModel(data[i], scope));
}
window.CP.exitedLoop(7);
}
return ar;
})(init.elseStatements));
self.addElseStatement = function(){
self.elseStatements.push(new statementModel({}, scope));
scope.reset();
};
self.removeElseStatement = function(val){
self.elseStatements.remove(this);
scope.reset();
};
self.moveUpElseStatement = function(){
var from = self.elseStatements.indexOf(this);
self.elseStatements.move(from, from - 1);
scope.reset();
};
self.moveDownElseStatement = function(){
var from = self.elseStatements.indexOf(this);
self.elseStatements.move(from, from + 1);
scope.reset();
};
// Setup variable statements
self.variableName = ko.observable(init.variableName);
self.variableValue = ko.observable(init.variableValue);
self.actionType.subscribe(function(val){
self.actionData(actionConfig(val));
});
self.statementType.subscribe(function(val){
switch(val){
case "action":
self.expression(undefined);
self.actionType(undefined);
self.statements(undefined);
self.elseStatements(undefined);
self.variableName(undefined);
self.variableName(undefined);
self.variableValue(undefined);
break;
case "event":
self.expression(undefined);
if(!self.statements())
self.statements([]);
self.actionType(undefined);
self.actionData(undefined);
self.elseStatements(undefined);
self.variableName(undefined);
self.variableValue(undefined);
break;
case "if":
if(!self.expression())
self.expression(new groupModel(init.expression, scope));
if(!self.statements())
self.statements([]);
self.actionType(undefined);
self.actionData(undefined);
self.elseStatements(undefined);
self.variableName(undefined);
self.variableValue(undefined);
break;
case "ifelse":
if(!self.expression())
self.expression(new groupModel(init.expression, scope));
if(!self.statements())
self.statements([]);
if(!self.elseStatements())
self.elseStatements([]);
self.actionType(undefined);
self.actionData(undefined);
self.variableName(undefined);
self.variableValue(undefined);
break;
case "stop":
self.actionType(undefined);
self.actionData(undefined);
self.expression(undefined);
self.statements(undefined);
self.elseStatements(undefined);
self.variableName(undefined);
self.variableValue(undefined);
break;
case "variable":
self.actionType(undefined);
self.actionData(undefined);
self.expression(undefined);
self.statements(undefined);
self.elseStatements(undefined);
break;
default:
self.expression(undefined);
self.actionType(undefined);
self.actionData(undefined);
self.statements(undefined);
self.elseStatements(undefined);
self.variableName(undefined);
self.variableName(undefined);
self.variableValue(undefined);
}
});
self.statementType(init.statementType);
self.actionType(init.actionType);
self.actionData(actionConfig(init.actionType, init.actionData));
self.evaluated = ko.observable(false)
self.reset = function(){
self.evaluated(false);
$.each(self.statements(), function(index, statement){
statement.reset();
});
$.each(self.elseStatements(), function(index, statement){
statement.reset();
});
}
self.evaluate = function(indent){
indent = indent||0;
indent++;
// Reset eval on children
self.reset();
self.evaluated(true);
setTimeout(function(){self.reset();}, 2000);
switch(self.statementType()){
case "action":
scope.log(indent, "Perform action: " + self.actionType());
return true;
break;
case "event":
scope.log(indent, "On event: " + self.eventObject().name + "." + self.eventObject().event());
for(i=0; i<self.statements().length; i++)
{if (window.CP.shouldStopExecution(8)){break;}
var statement = self.statements()[i];
if(!statement.evaluate(indent)){
return false;
}
}
window.CP.exitedLoop(8);
return true;
break;
case "if":
if(self.expression().evaluate()){
scope.log(indent, "If evaluation: true");
for(i=0; i<self.statements().length; i++)
{if (window.CP.shouldStopExecution(9)){break;}
var statement = self.statements()[i];
if(!statement.evaluate(indent)){
return false;
}
}
window.CP.exitedLoop(9);
}
return true;
break;
case "ifelse":
if(self.expression().evaluate()){
scope.log(indent, "If evaluation: true");
for(i=0; i<self.statements().length; i++)
{if (window.CP.shouldStopExecution(10)){break;}
var statement = self.statements()[i];
if(!statement.evaluate(indent)){
return false;
}
}
window.CP.exitedLoop(10);
}else{
scope.log(indent, "Else evaluation: true");
for(i=0; i<self.elseStatements().length; i++)
{if (window.CP.shouldStopExecution(11)){break;}
var statement = self.elseStatements()[i];
if(!statement.evaluate(indent)){
return false;
}
}
window.CP.exitedLoop(11);
}
return true;
break;
case "stop":
scope.log(indent, "Stop processing");
return false;
break;
case "variable":
var vname = self.variableName()||"";
if (vname.match(/^[a-z][a-z0-9]*/i)) {
if(scope.variables)
scope.variables[vname] = self.variableValue();
scope.log(indent, "Set variable: " + vname + "=" + self.variableValue());
return true;
}else{
if(!vname)
vname = "[Empty string]";
alert("Invalid variable name:" + vname)
return false;
}
break;
}
self.reset();
}
};
var mainModel = function(init){
var self = this;
init=init||{};
self.objects = function(ter){
return (ko.computed(function(){
// Reset variables
if(self.variables)
self.variables = {};
var objs = jQuery.extend(true, [], init.objects);
var fields = [];
var fieldsWithEvents = [];
$.each(objs, function(index, obj){
$.each(obj.properties, function(index, prop){
if(Array.isArray(prop.value)){
obj[prop.property] = ko.observableArray(prop.value);
}else{
obj[prop.property] = ko.observable(prop.value);
}
});
if(obj.type == "field"){
obj.label = "[" + obj.name + "]";
fields.push(obj);
}
if(obj.events){
obj.event = ko.observable();
fieldsWithEvents.push(obj);
}
delete obj.properties;
})
var ar;
// Objects only
if(!ter || ter == 0){
return ko.observableArray(fields);
}else if(ter == 1){
// Objects and variables
ar = ko.observableArray(objs);
}else if(ter == 2){
// Variables only
ar = ko.observableArray([]);
}else if(ter == 3){
// Objets with events only
return ko.observableArray(fieldsWithEvents);
}
// Variables only
ar = ko.observableArray([]);
var findVars = function(statement){
if(statement.statementType() == "variable"){
var vname = statement.variableName()||"";
if (vname.match(/^[a-z][a-z0-9]*/i)) {
if(!self.variables)
self.variables = {};
self.variables[vname] = statement.variableValue();
ar.push({
type: "variable",
name: vname,
properties: {
value: statement.variableValue()
}
});
}
}else{
$.each(statement.statements(), function(index, st){
findVars(st);
});
$.each(statement.elseStatements(), function(index, st){
findVars(st);
});
}
}
$.each(self.statements(), function(index, statement){
findVars(statement);
});
if(self.variables && Object.keys(self.variables).length == 0)
delete self.variables;
return ar;
})
)()
}
self.statements = ko.observableArray((function(data){
var ar = [];
if(data){
for(var i=0; i<data.length; i++){if (window.CP.shouldStopExecution(12)){break;}
ar.push(new statementModel(data[i], self));
}
window.CP.exitedLoop(12);
}
return ar;
})(init.statements));
self.addStatement = function(){
self.statements.push(new statementModel({}, self));
self.reset();
};
self.removeStatement = function(){
self.statements.remove(this);
self.reset();
};
self.moveUpStatement = function(){
var from = self.statements.indexOf(this);
self.statements.move(from, from - 1);
self.reset();
};
self.moveDownStatement = function(){
var from = self.statements.indexOf(this);
self.statements.move(from, from + 1);
self.reset();
};
self.output = ko.observable("");
self.log = function(indent, val){
indent =indent||0;
self.output(self.output() + "<br>" + Array(indent*4).join(' ') + val)
}
self.reset = function(){
if(console) console.log("reset")
self.output("");
for(i=0; i<self.statements().length; i++)
{if (window.CP.shouldStopExecution(13)){break;}
var statement = self.statements()[i];
if(!statement.reset()){
return;
}
}
window.CP.exitedLoop(13);
}
self.evaluate = function(indent){
if(console) console.clear();
self.output("");
for(i=0; i<self.statements().length; i++)
{if (window.CP.shouldStopExecution(14)){break;}
var statement = self.statements()[i];
if(!statement.evaluate(indent)){
return;
}
}
window.CP.exitedLoop(14);
}
};
var main = function(init){
var self = this;
init = init||{};
self.viewModel = new mainModel(init);
ko.applyBindings(self.viewModel, $("#progam")[0]);
}
main(
{
objects:
[
{
type: "event",
name: "Form",
id: "form",
properties: [
{property: "events", value: ["submit","validate"]}
]
},
{
type: "field",
name: "My Dropdown",
id: "123",
properties: [
{property: "controlType", value: "Dropdown"},
{property: "visible", value: "false"},
{property: "value", value: "Sample"},
{property: "events", value: ["Change"]}
]
},
{
type: "field",
name: "My Text Area",
id: "456",
properties: [
{property: "controlType", value: "Text_Area"},
{property: "visible", value: "false"},
{property: "value", value: "Sample"},
{property: "events", value: ["Change"]}
]
},
{
type: "field",
name: "My Text Box",
id: "789",
properties: [
{property: "controlType", value: "Text_Box"},
{property: "value", value: "Sample 2"},
{property: "Validate", value: "true"},
{property: "events", value: ["Change"]}
]
}
],
statements:
[
{
"statementType": "event",
"eventObject": {
"type": "event",
"name": "Form",
"id": "form",
"event": "submit"
},
"disabled": true,
"statements": [
{
"statementType": "variable",
"actionData": {},
"variableName": "Val1",
"variableValue": "123"
},
{
"statementType": "ifelse",
"actionData": {},
"expression": {
"conditions": [
{
"value1": "Val1",
"conditionType": "<>",
"value2": "123"
}
],
"groups": []
},
"statements": [
{
"statementType": "action",
"actionType": "email",
"actionData": {
"to": "jane@email.com",
"from": "joe@email.com",
"subject": "Hello World",
"message": "My Message"
}
},
{
"statementType": "stop",
"actionData": {}
}
],
"elseStatements": [
]
},
{
"statementType": "action",
"actionType": "redirect",
"actionData": {
"url": "http://www.test.com"
}
}
]
}
]
}
);
}
)
/*
var FormLogic = function(){
var self = this;
this.LogicID = 0;
this.FormID = 0;
this.FieldID = 0;
this.ParentID = 0;
this.LogicOrder = 0;
this.Type = "";
this.TypeData = {};
}
var FormAction = function(){
var self = this;
this.ActionID = 0;
this.FormID = 0;
this.FieldID = 0;
this.LogicID = 0;
this.ActionOrder = 0;
this.Type = "";
this.TypeData = {};
}
*/
//# sourceURL=pen.js
</script>
</body></html>