This commit is contained in:
Tony Garnock-Jones 2016-08-25 13:13:44 +01:00
parent 70112027c6
commit 325655cd3b
20 changed files with 940 additions and 1003 deletions

14
dist/syndicate.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,14 +2,12 @@
new Syndicate.Ground(function () {
Syndicate.UI.spawnUIDriver();
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.declareField(this, "counter", 0);
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
var ui = new Syndicate.UI.Anchor();
(function () {
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#button-label', '' + this.counter), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#counter', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#counter', 'click', _), metalevel: 0 }; }), (function() {
this.counter++;
})).completeBuild(); }).call(this);
});
Syndicate.Actor.declareField(this, "counter", 0);
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#button-label', '' + this.counter), 0); }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#counter', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#counter', 'click', _), metalevel: 0 }; }), (function() {
this.counter++;
}));
} }).bind(this)); });
}).startStepping();

View File

@ -2,13 +2,11 @@ ground dataspace {
Syndicate.UI.spawnUIDriver();
actor {
field this.counter = 0;
var ui = new Syndicate.UI.Anchor();
react {
assert ui.html('#button-label', '' + this.counter);
on message Syndicate.UI.globalEvent('#counter', 'click', _) {
this.counter++;
}
field this.counter = 0;
assert ui.html('#button-label', '' + this.counter);
on message Syndicate.UI.globalEvent('#counter', 'click', _) {
this.counter++;
}
}
}

View File

@ -19,37 +19,36 @@ function spawnChatApp() {
var ui = new Syndicate.UI.Anchor();
field this.nym;
field this.status;
react {
on asserted inputValue('#nym', $v) { this.nym = v; }
on asserted inputValue('#status', $v) { this.status = v; }
on asserted brokerConnected($url) { outputState('connected to ' + url); }
on retracted brokerConnected($url) { outputState('disconnected from ' + url); }
on asserted inputValue('#nym', $v) { this.nym = v; }
on asserted inputValue('#status', $v) { this.status = v; }
during inputValue('#wsurl', $url) {
assert brokerConnection(url);
on asserted brokerConnected($url) { outputState('connected to ' + url); }
on retracted brokerConnected($url) { outputState('disconnected from ' + url); }
on message Syndicate.WakeDetector.wakeEvent() {
:: forceBrokerDisconnect(url);
}
during inputValue('#wsurl', $url) {
assert brokerConnection(url);
assert toBroker(url, present(this.nym, this.status));
during fromBroker(url, present($who, $status)) {
assert ui.context(who, status)
.html('#nymlist',
Mustache.render($('#nym_template').html(), { who: who, status: status }));
}
on message Syndicate.WakeDetector.wakeEvent() {
:: forceBrokerDisconnect(url);
}
on message Syndicate.UI.globalEvent('#send_chat', 'click', _) {
var inp = $("#chat_input");
var utterance = inp.val();
inp.val("");
if (utterance) :: toBroker(url, says(this.nym, utterance));
}
assert toBroker(url, present(this.nym, this.status));
during fromBroker(url, present($who, $status)) {
assert ui.context(who, status)
.html('#nymlist',
Mustache.render($('#nym_template').html(), { who: who, status: status }));
}
on message fromBroker(url, says($who, $what)) {
outputUtterance(who, what);
}
on message Syndicate.UI.globalEvent('#send_chat', 'click', _) {
var inp = $("#chat_input");
var utterance = inp.val();
inp.val("");
if (utterance) :: toBroker(url, says(this.nym, utterance));
}
on message fromBroker(url, says($who, $what)) {
outputUtterance(who, what);
}
}
}
@ -84,13 +83,11 @@ assertion type inputValue(selector, value);
function spawnInputChangeMonitor() {
actor {
react {
during Syndicate.observe(inputValue($selector, _)) actor {
field this.value = $(selector).val();
assert inputValue(selector, this.value);
on message Syndicate.UI.globalEvent(selector, 'change', $e) {
this.value = e.target.value;
}
during Syndicate.observe(inputValue($selector, _)) actor {
field this.value = $(selector).val();
assert inputValue(selector, this.value);
on message Syndicate.UI.globalEvent(selector, 'change', $e) {
this.value = e.target.value;
}
}
}

View File

@ -11,10 +11,8 @@ assertion type componentPresent(name);
function spawnTV() {
actor {
var ui = new Syndicate.UI.Anchor();
react {
during tvAlert($text) {
assert ui.context(text).html('#tv', Mustache.render($('#alert_template').html(), { text: text }));
}
during tvAlert($text) {
assert ui.context(text).html('#tv', Mustache.render($('#alert_template').html(), { text: text }));
}
}
}
@ -24,11 +22,9 @@ function spawnTV() {
function spawnRemoteControl() {
actor {
react {
assert componentPresent('remote control');
on message Syndicate.UI.globalEvent('#remote-control', 'click', _) {
:: remoteClick();
}
assert componentPresent('remote control');
on message Syndicate.UI.globalEvent('#remote-control', 'click', _) {
:: remoteClick();
}
}
}
@ -41,15 +37,13 @@ function spawnRemoteListener() {
// state, if we've been clicked, turn it off. We don't do this
// here, for simplicity.
react {
on asserted powerDraw($watts) {
this.stoveIsOn = watts > 0;
}
on asserted powerDraw($watts) {
this.stoveIsOn = watts > 0;
}
on message remoteClick() {
if (this.stoveIsOn) {
:: switchAction(false);
}
on message remoteClick() {
if (this.stoveIsOn) {
:: switchAction(false);
}
}
}
@ -62,24 +56,23 @@ function spawnStoveSwitch() {
actor {
field this.powerOn = false;
this.ui = new Syndicate.UI.Anchor();
react {
assert componentPresent('stove switch');
assert switchState(this.powerOn);
assert this.ui.html('#stove-switch',
Mustache.render($('#stove_element_template').html(),
{ imgurl: ("img/stove-coil-element-" +
(this.powerOn ? "hot" : "cold") + ".jpg") }));
assert componentPresent('stove switch');
assert switchState(this.powerOn);
on message Syndicate.UI.globalEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
on message Syndicate.UI.globalEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
assert this.ui.html('#stove-switch',
Mustache.render($('#stove_element_template').html(),
{ imgurl: ("img/stove-coil-element-" +
(this.powerOn ? "hot" : "cold") + ".jpg") }));
on message switchAction($newState) {
this.powerOn = newState;
}
} until {
case message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
on message Syndicate.UI.globalEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
on message Syndicate.UI.globalEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
on message switchAction($newState) {
this.powerOn = newState;
}
stop on message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
}
}
@ -87,19 +80,18 @@ function spawnPowerDrawMonitor() {
actor {
field this.watts = 0;
this.ui = new Syndicate.UI.Anchor();
react {
assert componentPresent('power draw monitor');
assert powerDraw(this.watts);
assert this.ui.html('#power-draw-meter',
Mustache.render($('#power_draw_template').html(), { watts: this.watts }));
assert componentPresent('power draw monitor');
assert powerDraw(this.watts);
on asserted switchState($on) {
this.watts = on ? 1500 : 0;
}
} until {
case message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
assert this.ui.html('#power-draw-meter',
Mustache.render($('#power_draw_template').html(), { watts: this.watts }));
on asserted switchState($on) {
this.watts = on ? 1500 : 0;
}
stop on message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
}
}
@ -108,18 +100,16 @@ function spawnPowerDrawMonitor() {
function spawnTimeoutListener() {
actor {
react {
during powerDraw($watts) {
do {
if (watts > 0) {
var powerOnTime = Date.now();
react {
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
react { assert tvAlert('Stove on too long?'); }
}
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 10000) {
$("img.flames").show();
}
during powerDraw($watts) {
on start {
if (watts > 0) {
var powerOnTime = Date.now();
react {
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
react { assert tvAlert('Stove on too long?'); }
}
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 10000) {
$("img.flames").show();
}
}
}
@ -130,17 +120,14 @@ function spawnTimeoutListener() {
// function spawnTimeoutListener() {
// actor {
// react {
// on asserted powerDraw($watts) {
// if (watts > 0) {
// var powerOnTime = Date.now();
// react {
// on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
// react { assert tvAlert('Stove on too long?'); }
// }
// } until {
// case asserted powerDraw(0); // alt: on retracted powerDraw(watts);
// on asserted powerDraw($watts) {
// if (watts > 0) {
// var powerOnTime = Date.now();
// react {
// on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
// react { assert tvAlert('Stove on too long?'); }
// }
// stop on asserted powerDraw(0); // alt: on retracted powerDraw(watts);
// }
// }
// }
@ -151,16 +138,14 @@ function spawnTimeoutListener() {
// actor {
// this.mostRecentTime = 0;
// this.powerOnTime = null;
// react {
// on asserted powerDraw($watts) {
// this.powerOnTime = (watts > 0) ? this.mostRecentTime : null;
// }
// on message Syndicate.Timer.periodicTick(200) {
// this.mostRecentTime = Date.now();
// }
// assert tvAlert('Stove on too long?')
// when (this.powerOnTime !== null && this.mostRecentTime - this.powerOnTime > 3000);
// on asserted powerDraw($watts) {
// this.powerOnTime = (watts > 0) ? this.mostRecentTime : null;
// }
// on message Syndicate.Timer.periodicTick(200) {
// this.mostRecentTime = Date.now();
// }
// assert tvAlert('Stove on too long?')
// when (this.powerOnTime !== null && this.mostRecentTime - this.powerOnTime > 3000);
// }
// }
@ -169,13 +154,10 @@ function spawnTimeoutListener() {
function spawnFailureMonitor() {
actor {
react {
on retracted componentPresent($who) {
react {
assert tvAlert('FAILURE: ' + who);
} until {
case asserted componentPresent(who);
}
on retracted componentPresent($who) {
react {
assert tvAlert('FAILURE: ' + who);
stop on asserted componentPresent(who);
}
}
}
@ -185,7 +167,7 @@ function spawnFailureMonitor() {
// Chaos Monkey
function spawnChaosMonkey() {
actor {
actor* {
monitorComponent('power draw monitor',
'#spawn-power-draw-monitor',
'#kill-power-draw-monitor',
@ -201,11 +183,11 @@ function spawnChaosMonkey() {
var jKillButtons = $(killButtonSelector);
react {
during componentPresent(name) {
do {
on start {
jSpawnButtons.prop('disabled', true);
jKillButtons.prop('disabled', false);
}
finally {
on stop {
jSpawnButtons.prop('disabled', false);
jKillButtons.prop('disabled', true);
}

View File

@ -11,7 +11,7 @@ var G = new Syndicate.Ground(function () {
Syndicate.Timer.spawnTimerDriver();
Syndicate.Broker.spawnBrokerClientDriver();
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
var id = Syndicate.RandomID.randomId(4, true);
var email_element = document.getElementById('my_email');
@ -62,76 +62,89 @@ var G = new Syndicate.Ground(function () {
timeout: 15000
}));
(function () { Syndicate.Actor.declareField(this, "currentLocation", null); var selectedMarker = null;
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(brokerConnection(this.wsurl), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (this.currentLocation) ? Syndicate.Patch.assert(toBroker(this.wsurl, this.currentLocation), 0) : Syndicate.Patch.emptyPatch; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#my_email', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#my_email', 'change', _), metalevel: 0 }; }), (function() {
var v = email_element.value.trim();
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#group', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#group', 'change', _), metalevel: 0 }; }), (function() {
localStorage.group = group_element.value.trim();
this.wsurl = wsurl_base + group_element.value.trim();
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#findMarker', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#findMarker', 'click', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(findMarker(document.getElementById('markerList').value));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#markerList', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#markerList', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(findMarker(document.getElementById('markerList').value));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub((locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: ((Syndicate._$("loc",locationRecord(_, _, _, _, _)))), metalevel: 0 }; }), (function(loc) {
this.currentLocation = loc;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(this.wsurl, locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(this.wsurl, locationRecord((Syndicate._$("id")), (Syndicate._$("email")), _, _, _)), metalevel: 0 }; }), (function(id, email) { var ui = new Syndicate.UI.Anchor(); var marker = new google.maps.Marker({
map: map,
clickable: true,
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
}); var latestTimestamp = null; var latestPosition = null; function selectMarker() {
selectedMarker = marker;
updateInfoWindow();
infoWindow.open(map, marker);
} function updateInfoWindow() {
if (selectedMarker === marker && latestPosition && latestTimestamp) {
geocoder.geocode({'location': latestPosition}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK && results[0]) {
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
email: email,
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
address: results[0].formatted_address
}));
}
});
}
Syndicate.Actor.declareField(this, "currentLocation", null);
var selectedMarker = null;
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(brokerConnection(this.wsurl), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return (this.currentLocation) ? Syndicate.Patch.assert(toBroker(this.wsurl, this.currentLocation), 0) : Syndicate.Patch.emptyPatch; }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#my_email', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#my_email', 'change', _), metalevel: 0 }; }), (function() {
var v = email_element.value.trim();
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v;
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#group', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#group', 'change', _), metalevel: 0 }; }), (function() {
localStorage.group = group_element.value.trim();
this.wsurl = wsurl_base + group_element.value.trim();
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#findMarker', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#findMarker', 'click', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(findMarker(document.getElementById('markerList').value));
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('#markerList', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('#markerList', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(findMarker(document.getElementById('markerList').value));
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub((locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: ((Syndicate._$("loc",locationRecord(_, _, _, _, _)))), metalevel: 0 }; }), (function(loc) {
this.currentLocation = loc;
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(this.wsurl, locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(this.wsurl, locationRecord((Syndicate._$("id")), (Syndicate._$("email")), _, _, _)), metalevel: 0 }; }), (function(id, email) {
var _cachedAssertion1472127196930_0 = (function() { var _ = Syndicate.__; return fromBroker(this.wsurl, locationRecord(id, email, _, _, _)); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
var ui = new Syndicate.UI.Anchor();
var marker = new google.maps.Marker({
map: map,
clickable: true,
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
});
var latestTimestamp = null;
var latestPosition = null;
function selectMarker() {
selectedMarker = marker;
updateInfoWindow();
infoWindow.open(map, marker);
}
function updateInfoWindow() {
if (selectedMarker === marker && latestPosition && latestTimestamp) {
geocoder.geocode({'location': latestPosition}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK && results[0]) {
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
email: email,
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
address: results[0].formatted_address
}));
}
});
}
var _cachedAssertion1470624652650_0 = (function() { var _ = Syndicate.__; return fromBroker(this.wsurl, locationRecord(id, email, _, _, _)); }).call(this);
Syndicate.Actor.createFacet()
.addInitBlock((function() {
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
selectMarker();
}));
}))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#markerList',
Mustache.render(document.getElementById('markerList-option').innerHTML, {
id: id,
email: email
})), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(findMarker(id), 0); }), (function() { var _ = Syndicate.__; return { assertion: findMarker(id), metalevel: 0 }; }), (function() {
}
Syndicate.Actor.Facet.current.addInitBlock((function() {
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
selectMarker();
if (latestPosition) map.panTo(latestPosition);
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(this.wsurl, locationRecord(id, email, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(this.wsurl, locationRecord(id, email, (Syndicate._$("timestamp")), (Syndicate._$("lat")), (Syndicate._$("lng")))), metalevel: 0 }; }), (function(timestamp, lat, lng) {
latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition);
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
updateInfoWindow();
}))
.addDoneBlock((function() {
marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624652650_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624652650_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
});
}));
}));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#markerList',
Mustache.render(document.getElementById('markerList-option').innerHTML, {
id: id,
email: email
})), 0); }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(findMarker(id), 0); }), (function() { var _ = Syndicate.__; return { assertion: findMarker(id), metalevel: 0 }; }), (function() {
selectMarker();
if (latestPosition) map.panTo(latestPosition);
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(this.wsurl, locationRecord(id, email, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(this.wsurl, locationRecord(id, email, (Syndicate._$("timestamp")), (Syndicate._$("lat")), (Syndicate._$("lng")))), metalevel: 0 }; }), (function(timestamp, lat, lng) {
latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition);
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
updateInfoWindow();
}));
Syndicate.Actor.Facet.current.addDoneBlock((function() {
marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null;
}));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127196930_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127196930_0, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
} }).bind(this)); });
}).startStepping();

View File

@ -61,87 +61,85 @@ ground dataspace G {
timeout: 15000
}));
react {
field this.currentLocation = null;
var selectedMarker = null;
field this.currentLocation = null;
var selectedMarker = null;
assert brokerConnection(this.wsurl);
assert toBroker(this.wsurl, this.currentLocation) when (this.currentLocation);
assert brokerConnection(this.wsurl);
assert toBroker(this.wsurl, this.currentLocation) when (this.currentLocation);
on message Syndicate.UI.globalEvent('#my_email', 'change', _) {
var v = email_element.value.trim();
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v;
on message Syndicate.UI.globalEvent('#my_email', 'change', _) {
var v = email_element.value.trim();
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v;
}
on message Syndicate.UI.globalEvent('#group', 'change', _) {
localStorage.group = group_element.value.trim();
this.wsurl = wsurl_base + group_element.value.trim();
}
on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) {
:: findMarker(document.getElementById('markerList').value);
}
on message Syndicate.UI.globalEvent('#markerList', 'change', $e) {
:: findMarker(document.getElementById('markerList').value);
}
on message ($loc = locationRecord(_, _, _, _, _)) {
this.currentLocation = loc;
}
during fromBroker(this.wsurl, locationRecord($id, $email, _, _, _)) {
var ui = new Syndicate.UI.Anchor();
var marker = new google.maps.Marker({
map: map,
clickable: true,
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
});
var latestTimestamp = null;
var latestPosition = null;
function selectMarker() {
selectedMarker = marker;
updateInfoWindow();
infoWindow.open(map, marker);
}
on message Syndicate.UI.globalEvent('#group', 'change', _) {
localStorage.group = group_element.value.trim();
this.wsurl = wsurl_base + group_element.value.trim();
}
on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) {
:: findMarker(document.getElementById('markerList').value);
}
on message Syndicate.UI.globalEvent('#markerList', 'change', $e) {
:: findMarker(document.getElementById('markerList').value);
}
on message ($loc = locationRecord(_, _, _, _, _)) {
this.currentLocation = loc;
}
during fromBroker(this.wsurl, locationRecord($id, $email, _, _, _)) {
var ui = new Syndicate.UI.Anchor();
var marker = new google.maps.Marker({
map: map,
clickable: true,
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
});
var latestTimestamp = null;
var latestPosition = null;
function selectMarker() {
selectedMarker = marker;
updateInfoWindow();
infoWindow.open(map, marker);
function updateInfoWindow() {
if (selectedMarker === marker && latestPosition && latestTimestamp) {
geocoder.geocode({'location': latestPosition}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK && results[0]) {
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
email: email,
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
address: results[0].formatted_address
}));
}
});
}
function updateInfoWindow() {
if (selectedMarker === marker && latestPosition && latestTimestamp) {
geocoder.geocode({'location': latestPosition}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK && results[0]) {
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
email: email,
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
address: results[0].formatted_address
}));
}
});
}
}
do {
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
selectMarker();
}));
}
assert ui.html('#markerList',
Mustache.render(document.getElementById('markerList-option').innerHTML, {
id: id,
email: email
}));
on message findMarker(id) {
}
on start {
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
selectMarker();
if (latestPosition) map.panTo(latestPosition);
}
on asserted fromBroker(this.wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) {
latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition);
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
updateInfoWindow();
}
finally {
marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null;
}
}));
}
assert ui.html('#markerList',
Mustache.render(document.getElementById('markerList-option').innerHTML, {
id: id,
email: email
}));
on message findMarker(id) {
selectMarker();
if (latestPosition) map.panTo(latestPosition);
}
on asserted fromBroker(this.wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) {
latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition);
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
updateInfoWindow();
}
on stop {
marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null;
}
}
}

View File

@ -23,32 +23,31 @@ ground dataspace G {
}
var wsurl = 'wss://demo-broker.syndicate-lang.org:8443/';
react {
assert brokerConnection(wsurl);
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
assert brokerConnection(wsurl);
assert toBroker(wsurl, point(color, this.publishedX, this.publishedY));
on message Syndicate.Timer.periodicTick(100) {
this.publishedX = x;
this.publishedY = y;
}
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
on message Syndicate.UI.windowEvent('deviceorientation', $e) {
var scale = 0.5;
x = clamp(e.gamma * scale);
y = clamp((e.beta - 40) * scale);
}
assert toBroker(wsurl, point(color, this.publishedX, this.publishedY));
on message Syndicate.Timer.periodicTick(100) {
this.publishedX = x;
this.publishedY = y;
}
during fromBroker(wsurl, point($oc, $ox, $oy)) {
assert ui.context(oc)
.html('#container',
Mustache.render(document.getElementById('circle-template').innerHTML, {
color: oc,
x: ox,
y: oy
}));
}
on message Syndicate.UI.windowEvent('deviceorientation', $e) {
var scale = 0.5;
x = clamp(e.gamma * scale);
y = clamp((e.beta - 40) * scale);
}
during fromBroker(wsurl, point($oc, $ox, $oy)) {
assert ui.context(oc)
.html('#container',
Mustache.render(document.getElementById('circle-template').innerHTML, {
color: oc,
x: ox,
y: oy
}));
}
}
}

View File

@ -4,28 +4,23 @@ ground dataspace {
console.log('starting ground boot');
actor {
react until {
case asserted Syndicate.observe(beep(_)) {
field this.counter = 0;
react {
do {
:: beep(this.counter++);
}
on message beep(_) {
:: beep(this.counter++);
}
} until {
case (this.counter > 10);
stop on asserted Syndicate.observe(beep(_)) {
field this.counter = 0;
react {
on start {
:: beep(this.counter++);
}
on message beep(_) {
:: beep(this.counter++);
}
stop on (this.counter > 10);
}
}
}
actor {
react {
on message beep($counter) {
console.log("beep!", counter);
}
on message beep($counter) {
console.log("beep!", counter);
}
}
}

View File

@ -8,19 +8,17 @@ ground dataspace G {
field this.handX;
field this.handY;
react {
assert ui.html('#clock',
'<svg width="300px" viewBox="0 0 100 100">'+
'<circle fill="#0B79CE" r=45 cx=50 cy=50 />'+
'<line stroke="#023963" x1=50 y1=50 x2='+this.handX+' y2='+this.handY+' />'+
'</svg>')
assert ui.html('#clock',
'<svg width="300px" viewBox="0 0 100 100">'+
'<circle fill="#0B79CE" r=45 cx=50 cy=50 />'+
'<line stroke="#023963" x1=50 y1=50 x2='+this.handX+' y2='+this.handY+' />'+
'</svg>')
when (typeof this.angle === 'number');
on message Syndicate.Timer.periodicTick(1000) {
this.angle = ((((Date.now() / 1000) % 60) / 60) - 0.25) * 2 * Math.PI;
this.handX = 50 + 40 * Math.cos(this.angle);
this.handY = 50 + 40 * Math.sin(this.angle);
}
on message Syndicate.Timer.periodicTick(1000) {
this.angle = ((((Date.now() / 1000) % 60) / 60) - 0.25) * 2 * Math.PI;
this.handX = 50 + 40 * Math.cos(this.angle);
this.handY = 50 + 40 * Math.sin(this.angle);
}
}
}

View File

@ -3,9 +3,7 @@ message type setSortColumn(number);
function newRow(id, firstName, lastName, address, age) {
actor named ('model' + id) {
react {
assert person(id, firstName, lastName, address, age);
}
assert person(id, firstName, lastName, address, age);
}
}
@ -27,25 +25,21 @@ function spawnView() {
return '<td>' + text + '</td>';
}
react {
on message setSortColumn($c) { this.orderColumn = c; }
on message setSortColumn($c) { this.orderColumn = c; }
during person($id, $firstName, $lastName, $address, $age) {
assert ui.context(id)
.html('table#the-table tbody',
'<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>',
[id, firstName, lastName, address, age][this.orderColumn]);
}
during person($id, $firstName, $lastName, $address, $age) {
assert ui.context(id)
.html('table#the-table tbody',
'<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>',
[id, firstName, lastName, address, age][this.orderColumn]);
}
}
}
function spawnController() {
actor named 'controller' {
react {
on message Syndicate.UI.globalEvent('table#the-table th', 'click', $e) {
:: setSortColumn(JSON.parse(e.target.dataset.column));
}
on message Syndicate.UI.globalEvent('table#the-table th', 'click', $e) {
:: setSortColumn(JSON.parse(e.target.dataset.column));
}
}
}

View File

@ -26,52 +26,50 @@ function piece(text, pos, lo, hi, cls) {
function spawnGui() {
actor {
react {
field this.text = '';
field this.pos = 0;
field this.highlightState = false;
field this.text = '';
field this.pos = 0;
field this.highlightState = false;
dataflow {
var text = this.text;
var pos = this.pos;
var highlight = this.highlightState;
var hLeft = highlight ? highlight[0] : 0;
var hRight = highlight ? highlight[1] : 0;
document.getElementById("fieldContents").innerHTML = highlight
? piece(text, pos, 0, hLeft, "normal") +
piece(text, pos, hLeft, hRight, "highlight") +
piece(text, pos, hRight, text.length + 1, "normal")
: piece(text, pos, 0, text.length + 1, "normal");
}
dataflow {
var text = this.text;
var pos = this.pos;
var highlight = this.highlightState;
var hLeft = highlight ? highlight[0] : 0;
var hRight = highlight ? highlight[1] : 0;
document.getElementById("fieldContents").innerHTML = highlight
? piece(text, pos, 0, hLeft, "normal") +
piece(text, pos, hLeft, hRight, "highlight") +
piece(text, pos, hRight, text.length + 1, "normal")
: piece(text, pos, 0, text.length + 1, "normal");
}
on message globalEvent("#inputRow", "+keydown", $event) {
switch (event.keyCode) {
case 37 /* left */: :: fieldCommand("cursorLeft"); break;
case 39 /* right */: :: fieldCommand("cursorRight"); break;
case 9 /* tab */: /* ignore */ break;
case 8 /* backspace */:
event.preventDefault(); // that this works here is a minor miracle
:: fieldCommand("backspace");
break;
default: break;
}
on message globalEvent("#inputRow", "+keydown", $event) {
switch (event.keyCode) {
case 37 /* left */: :: fieldCommand("cursorLeft"); break;
case 39 /* right */: :: fieldCommand("cursorRight"); break;
case 9 /* tab */: /* ignore */ break;
case 8 /* backspace */:
event.preventDefault(); // that this works here is a minor miracle
:: fieldCommand("backspace");
break;
default: break;
}
}
on message globalEvent("#inputRow", "keypress", $event) {
var character = String.fromCharCode(event.charCode);
if (event.charCode && character) {
:: fieldCommand(["insert", character]);
}
on message globalEvent("#inputRow", "keypress", $event) {
var character = String.fromCharCode(event.charCode);
if (event.charCode && character) {
:: fieldCommand(["insert", character]);
}
}
on asserted fieldContents($text, $pos) {
this.text = text;
this.pos = pos;
}
on asserted fieldContents($text, $pos) {
this.text = text;
this.pos = pos;
}
on asserted highlight($state) {
this.highlightState = state;
}
on asserted highlight($state) {
this.highlightState = state;
}
}
}
@ -81,40 +79,38 @@ function spawnGui() {
function spawnModel() {
actor {
react {
field this.fieldValue = "initial";
field this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
field this.fieldValue = "initial";
field this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
assert fieldContents(this.fieldValue, this.cursorPos);
assert fieldContents(this.fieldValue, this.cursorPos);
on message fieldCommand("cursorLeft") {
this.cursorPos--;
if (this.cursorPos < 0)
this.cursorPos = 0;
on message fieldCommand("cursorLeft") {
this.cursorPos--;
if (this.cursorPos < 0)
this.cursorPos = 0;
}
on message fieldCommand("cursorRight") {
this.cursorPos++;
if (this.cursorPos > this.fieldValue.length)
this.cursorPos = this.fieldValue.length;
}
on message fieldCommand("backspace") {
if (this.cursorPos > 0) {
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos - 1) +
this.fieldValue.substring(this.cursorPos);
this.cursorPos--;
}
}
on message fieldCommand("cursorRight") {
this.cursorPos++;
if (this.cursorPos > this.fieldValue.length)
this.cursorPos = this.fieldValue.length;
}
on message fieldCommand("backspace") {
if (this.cursorPos > 0) {
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos - 1) +
this.fieldValue.substring(this.cursorPos);
this.cursorPos--;
}
}
on message fieldCommand(["insert", $newText]) {
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos) +
newText +
this.fieldValue.substring(this.cursorPos);
this.cursorPos += newText.length;
}
on message fieldCommand(["insert", $newText]) {
this.fieldValue =
this.fieldValue.substring(0, this.cursorPos) +
newText +
this.fieldValue.substring(this.cursorPos);
this.cursorPos += newText.length;
}
}
}
@ -124,29 +120,27 @@ function spawnModel() {
function spawnSearch() {
actor {
react {
field this.searchtext = document.getElementById("searchBox").value;
field this.fieldValue = "";
field this.highlight = false;
field this.searchtext = document.getElementById("searchBox").value;
field this.fieldValue = "";
field this.highlight = false;
assert highlight(this.highlight);
assert highlight(this.highlight);
dataflow {
if (this.searchtext) {
var pos = this.fieldValue.indexOf(this.searchtext);
this.highlight = (pos !== -1) && [pos, pos + this.searchtext.length];
} else {
this.highlight = false;
}
dataflow {
if (this.searchtext) {
var pos = this.fieldValue.indexOf(this.searchtext);
this.highlight = (pos !== -1) && [pos, pos + this.searchtext.length];
} else {
this.highlight = false;
}
}
on message globalEvent("#searchBox", "input", $event) {
this.searchtext = document.getElementById("searchBox").value;
}
on message globalEvent("#searchBox", "input", $event) {
this.searchtext = document.getElementById("searchBox").value;
}
on asserted fieldContents($text, _) {
this.fieldValue = text;
}
on asserted fieldContents($text, _) {
this.fieldValue = text;
}
}
}

View File

@ -20,18 +20,24 @@ var show = Syndicate.Struct.makeConstructor("show", ["completed"]);
//////////////////////////////////////////////////////////////////////////
function todoListItemModel(initialId, initialTitle, initialCompleted) {
Syndicate.Actor.spawnActor(function() {
(function () { Syndicate.Actor.declareField(this, "id", initialId); Syndicate.Actor.declareField(this, "title", initialTitle); Syndicate.Actor.declareField(this, "completed", initialCompleted);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(todo(this.id, this.title, this.completed), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setCompleted(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setCompleted(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setAllCompleted(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: setAllCompleted((Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setTitle(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setTitle(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.title = v; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(clearCompletedTodos(), 0); }), (function() { var _ = Syndicate.__; return { assertion: clearCompletedTodos(), metalevel: 0 }; }), (function() {
if (this.completed) Syndicate.Dataspace.send(deleteTodo(this.id));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(deleteTodo(this.id), 0); }), (function() { var _ = Syndicate.__; return { assertion: deleteTodo(this.id), metalevel: 0 }; }), (function() {})).completeBuild(); }).call(this);
});
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.declareField(this, "id", initialId);
Syndicate.Actor.declareField(this, "title", initialTitle);
Syndicate.Actor.declareField(this, "completed", initialCompleted);
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(deleteTodo(this.id), 0); }), (function() { var _ = Syndicate.__; return { assertion: deleteTodo(this.id), metalevel: 0 }; }), (function() {}));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(todo(this.id, this.title, this.completed), 0); }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setCompleted(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setCompleted(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setAllCompleted(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: setAllCompleted((Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(setTitle(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setTitle(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.title = v; }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(clearCompletedTodos(), 0); }), (function() { var _ = Syndicate.__; return { assertion: clearCompletedTodos(), metalevel: 0 }; }), (function() {
if (this.completed) Syndicate.Dataspace.send(deleteTodo(this.id));
}));
} }).bind(this)); });
}
///////////////////////////////////////////////////////////////////////////
@ -44,53 +50,60 @@ function getTemplate(id) {
}
function todoListItemView(id) {
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, _, _), metalevel: 0 }; }), (function() {}));
this.ui = new Syndicate.UI.Anchor();
(function () { Syndicate.Actor.declareField(this, "editing", false);
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1470624655068_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(show(completed), 0); }), (function() { var _ = Syndicate.__; return { assertion: show(completed), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_1 = (function() { var _ = Syndicate.__; return show(completed); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing
? 'todo-list-item-edit-template'
: 'todo-list-item-view-template'),
{
id: id,
title: title,
completed_class: completed ? "completed" : "",
checked: completed ? "checked" : "",
}),
id), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_1, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_0, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.toggle', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.toggle', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setCompleted(id, e.target.checked));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.destroy', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.destroy', 'click', _), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(deleteTodo(id));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('label', 'dblclick', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('label', 'dblclick', _), metalevel: 0 }; }), (function() {
this.editing = true;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'keyup', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'keyup', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
this.editing = false;
}
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'blur', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'blur', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Actor.declareField(this, "editing", false);
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1472127199197_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(show(completed), 0); }), (function() { var _ = Syndicate.__; return { assertion: show(completed), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_1 = (function() { var _ = Syndicate.__; return show(completed); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing
? 'todo-list-item-edit-template'
: 'todo-list-item-view-template'),
{
id: id,
title: title,
completed_class: completed ? "completed" : "",
checked: completed ? "checked" : "",
}),
id), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_1, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_0, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.toggle', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.toggle', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setCompleted(id, e.target.checked));
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.destroy', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.destroy', 'click', _), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(deleteTodo(id));
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('label', 'dblclick', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('label', 'dblclick', _), metalevel: 0 }; }), (function() {
this.editing = true;
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'keyup', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'keyup', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
this.editing = false;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
var newTitle = e.target.value.trim();
Syndicate.Dataspace.send((newTitle ? setTitle(id, newTitle) : deleteTodo(id)));
this.editing = false;
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, _, _), metalevel: 0 }; }), (function() {})).completeBuild(); }).call(this);
});
}
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'blur', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'blur', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
this.editing = false;
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('input.edit', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('input.edit', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
var newTitle = e.target.value.trim();
Syndicate.Dataspace.send((newTitle ? setTitle(id, newTitle) : deleteTodo(id)));
this.editing = false;
}));
} }).bind(this)); });
}
///////////////////////////////////////////////////////////////////////////
@ -98,94 +111,101 @@ Syndicate.Actor.createFacet()
var G = new Syndicate.Ground(function () {
Syndicate.UI.spawnUIDriver();
Syndicate.Actor.spawnActor(function() {
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.new-todo', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.new-todo', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
var newTitle = e.target.value.trim();
if (newTitle) Syndicate.Dataspace.send(createTodo(newTitle));
e.target.value = "";
})).completeBuild(); }).call(this);
});
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.new-todo', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.new-todo', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
var newTitle = e.target.value.trim();
if (newTitle) Syndicate.Dataspace.send(createTodo(newTitle));
e.target.value = "";
}));
} }).bind(this)); });
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
this.ui = new Syndicate.UI.Anchor();
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(activeTodoCount(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: activeTodoCount((Syndicate._$("count"))), metalevel: 0 }; }), (function(count) {
var _cachedAssertion1470624655068_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.context('count').html('.todo-count strong', '' + count), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (count !== 1) ? Syndicate.Patch.assert(this.ui.context('plural').html('.todo-count span.s', 's'), 0) : Syndicate.Patch.emptyPatch; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_2, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(totalTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: totalTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('section.main', 'class', 'hidden'), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_3, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(completedTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: completedTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_4, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('button.clear-completed', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('button.clear-completed', 'click', _), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(clearCompletedTodos());
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(allCompleted(), 0); }), (function() { var _ = Syndicate.__; return { assertion: allCompleted(), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_5 = (function() { var _ = Syndicate.__; return allCompleted(); }).call(this);
Syndicate.Actor.createFacet()
.addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); }))
.addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_5, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.toggle-all', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.toggle-all', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setAllCompleted(e.target.checked));
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) {
todoListItemView(id);
})).completeBuild(); }).call(this);
});
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(activeTodoCount(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: activeTodoCount((Syndicate._$("count"))), metalevel: 0 }; }), (function(count) {
var _cachedAssertion1472127199197_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.context('count').html('.todo-count strong', '' + count), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return (count !== 1) ? Syndicate.Patch.assert(this.ui.context('plural').html('.todo-count span.s', 's'), 0) : Syndicate.Patch.emptyPatch; }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_2, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.spawnActor(function() {
(function () { Syndicate.Actor.declareField(this, "completedCount", 0); Syndicate.Actor.declareField(this, "activeCount", 0);
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("c"))), metalevel: 0 }; }), (function(id, c) { if (c) this.completedCount++; else this.activeCount++; }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("c"))), metalevel: 0 }; }), (function(id, c) { if (c) this.completedCount--; else this.activeCount--; }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(activeTodoCount(this.activeCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(completedTodoCount(this.completedCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(totalTodoCount(this.activeCount + this.completedCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (this.completedCount > 0 && this.activeCount === 0) ? Syndicate.Patch.assert(allCompleted(), 0) : Syndicate.Patch.emptyPatch; })).completeBuild(); }).call(this);
});
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(totalTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: totalTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('section.main', 'class', 'hidden'), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_3, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.spawnActor(function() {
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash((Syndicate._$("hash"))), metalevel: 0 }; }), (function(hash) {
var _cachedAssertion1470624655068_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected'), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_6, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/'), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_7, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/active'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/active'), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_8, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/completed'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/completed'), metalevel: 0 }; }), (function() {
var _cachedAssertion1470624655068_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_9, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
});
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(completedTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: completedTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_4, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('button.clear-completed', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('button.clear-completed', 'click', _), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(clearCompletedTodos());
}));
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(allCompleted(), 0); }), (function() { var _ = Syndicate.__; return { assertion: allCompleted(), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_5 = (function() { var _ = Syndicate.__; return allCompleted(); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); }));
Syndicate.Actor.Facet.current.addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_5, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.toggle-all', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.toggle-all', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setAllCompleted(e.target.checked));
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) {
todoListItemView(id);
}));
} }).bind(this)); });
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.declareField(this, "completedCount", 0);
Syndicate.Actor.declareField(this, "activeCount", 0);
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("c"))), metalevel: 0 }; }), (function(id, c) { if (c) this.completedCount++; else this.activeCount++; }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("c"))), metalevel: 0 }; }), (function(id, c) { if (c) this.completedCount--; else this.activeCount--; }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(activeTodoCount(this.activeCount), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(completedTodoCount(this.completedCount), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(totalTodoCount(this.activeCount + this.completedCount), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return (this.completedCount > 0 && this.activeCount === 0) ? Syndicate.Patch.assert(allCompleted(), 0) : Syndicate.Patch.emptyPatch; }));
} }).bind(this)); });
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash((Syndicate._$("hash"))), metalevel: 0 }; }), (function(hash) {
var _cachedAssertion1472127199197_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected'), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_6, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/'), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }));
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_7, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/active'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/active'), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_8, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/completed'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/completed'), metalevel: 0 }; }), (function() {
var _cachedAssertion1472127199197_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_9, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
} }).bind(this)); });
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
var db;
if ('todos-syndicate' in localStorage) {
@ -196,35 +216,38 @@ Syndicate.Actor.createFacet()
}
} else {
db = {nextId: 0, todos: {}};
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(createTodo(_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(createTodo(_)), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(createTodo('Buy milk'));
Syndicate.Dataspace.send(createTodo('Buy bread'));
Syndicate.Dataspace.send(createTodo('Finish PhD'));
})).completeBuild(); }).call(this);
Syndicate.Actor.Facet.current.addInitBlock((function() {
(function () { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(createTodo(_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(createTodo(_)), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(createTodo('Buy milk'));
Syndicate.Dataspace.send(createTodo('Buy bread'));
Syndicate.Dataspace.send(createTodo('Finish PhD'));
}));
} }).bind(this)); }).call(this);
}));
}
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(createTodo(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: createTodo((Syndicate._$("title"))), metalevel: 0 }; }), (function(title) {
todoListItemModel(db.nextId++, title, false);
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) {
var _cachedAssertion1470624655068_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); }).call(this);
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1470624655068_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
Syndicate.Actor.createFacet()
.addInitBlock((function() {
db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db);
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_11, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.addDoneBlock((function() {
delete db.todos[id];
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(createTodo(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: createTodo((Syndicate._$("title"))), metalevel: 0 }; }), (function(title) {
todoListItemModel(db.nextId++, title, false);
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) {
var _cachedAssertion1472127199197_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1472127199197_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addInitBlock((function() {
db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db);
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624655068_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624655068_10, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
});
}));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_11, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
Syndicate.Actor.Facet.current.addDoneBlock((function() {
delete db.todos[id];
localStorage['todos-syndicate'] = JSON.stringify(db);
}));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127199197_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127199197_10, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
} }).bind(this)); });
}).startStepping();

View File

@ -25,23 +25,21 @@ assertion type show(completed);
function todoListItemModel(initialId, initialTitle, initialCompleted) {
actor {
react {
field this.id = initialId;
field this.title = initialTitle;
field this.completed = initialCompleted;
field this.id = initialId;
field this.title = initialTitle;
field this.completed = initialCompleted;
assert todo(this.id, this.title, this.completed);
stop on message deleteTodo(this.id);
on message setCompleted(this.id, $v) { this.completed = v; }
on message setAllCompleted($v) { this.completed = v; }
assert todo(this.id, this.title, this.completed);
on message setTitle(this.id, $v) { this.title = v; }
on message setCompleted(this.id, $v) { this.completed = v; }
on message setAllCompleted($v) { this.completed = v; }
on message clearCompletedTodos() {
if (this.completed) :: deleteTodo(this.id);
}
} until {
case message deleteTodo(this.id);
on message setTitle(this.id, $v) { this.title = v; }
on message clearCompletedTodos() {
if (this.completed) :: deleteTodo(this.id);
}
}
}
@ -57,53 +55,51 @@ function getTemplate(id) {
function todoListItemView(id) {
actor {
stop on retracted todo(id, _, _);
this.ui = new Syndicate.UI.Anchor();
react {
field this.editing = false;
field this.editing = false;
during todo(id, $title, $completed) {
during show(completed) {
assert this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing
? 'todo-list-item-edit-template'
: 'todo-list-item-view-template'),
{
id: id,
title: title,
completed_class: completed ? "completed" : "",
checked: completed ? "checked" : "",
}),
id);
}
during todo(id, $title, $completed) {
during show(completed) {
assert this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing
? 'todo-list-item-edit-template'
: 'todo-list-item-view-template'),
{
id: id,
title: title,
completed_class: completed ? "completed" : "",
checked: completed ? "checked" : "",
}),
id);
}
}
on message this.ui.event('.toggle', 'change', $e) {
:: setCompleted(id, e.target.checked);
}
on message this.ui.event('.toggle', 'change', $e) {
:: setCompleted(id, e.target.checked);
}
on message this.ui.event('.destroy', 'click', _) {
:: deleteTodo(id);
}
on message this.ui.event('.destroy', 'click', _) {
:: deleteTodo(id);
}
on message this.ui.event('label', 'dblclick', _) {
this.editing = true;
}
on message this.ui.event('label', 'dblclick', _) {
this.editing = true;
}
on message this.ui.event('input.edit', 'keyup', $e) {
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
this.editing = false;
}
}
on message this.ui.event('input.edit', 'blur', $e) {
on message this.ui.event('input.edit', 'keyup', $e) {
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
this.editing = false;
}
on message this.ui.event('input.edit', 'change', $e) {
var newTitle = e.target.value.trim();
:: (newTitle ? setTitle(id, newTitle) : deleteTodo(id));
this.editing = false;
}
} until {
case retracted todo(id, _, _);
}
on message this.ui.event('input.edit', 'blur', $e) {
this.editing = false;
}
on message this.ui.event('input.edit', 'change', $e) {
var newTitle = e.target.value.trim();
:: (newTitle ? setTitle(id, newTitle) : deleteTodo(id));
this.editing = false;
}
}
}
@ -114,80 +110,72 @@ ground dataspace G {
Syndicate.UI.spawnUIDriver();
actor {
react {
on message Syndicate.UI.globalEvent('.new-todo', 'change', $e) {
var newTitle = e.target.value.trim();
if (newTitle) :: createTodo(newTitle);
e.target.value = "";
}
on message Syndicate.UI.globalEvent('.new-todo', 'change', $e) {
var newTitle = e.target.value.trim();
if (newTitle) :: createTodo(newTitle);
e.target.value = "";
}
}
actor {
this.ui = new Syndicate.UI.Anchor();
react {
during activeTodoCount($count) {
assert this.ui.context('count').html('.todo-count strong', '' + count);
assert this.ui.context('plural').html('.todo-count span.s', 's') when (count !== 1);
}
during activeTodoCount($count) {
assert this.ui.context('count').html('.todo-count strong', '' + count);
assert this.ui.context('plural').html('.todo-count span.s', 's') when (count !== 1);
}
during totalTodoCount(0) {
assert Syndicate.UI.uiAttribute('section.main', 'class', 'hidden');
assert Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden');
}
during totalTodoCount(0) {
assert Syndicate.UI.uiAttribute('section.main', 'class', 'hidden');
assert Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden');
}
during completedTodoCount(0) {
assert Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden');
}
on message Syndicate.UI.globalEvent('button.clear-completed', 'click', _) {
:: clearCompletedTodos();
}
during completedTodoCount(0) {
assert Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden');
}
on message Syndicate.UI.globalEvent('button.clear-completed', 'click', _) {
:: clearCompletedTodos();
}
during allCompleted() {
do { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
finally { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
}
on message Syndicate.UI.globalEvent('.toggle-all', 'change', $e) {
:: setAllCompleted(e.target.checked);
}
during allCompleted() {
on start { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
on stop { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
}
on message Syndicate.UI.globalEvent('.toggle-all', 'change', $e) {
:: setAllCompleted(e.target.checked);
}
on asserted todo($id, _, _) {
todoListItemView(id);
}
on asserted todo($id, _, _) {
todoListItemView(id);
}
}
actor {
react {
field this.completedCount = 0;
field this.activeCount = 0;
on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
on retracted todo($id, _, $c) { if (c) this.completedCount--; else this.activeCount--; }
assert activeTodoCount(this.activeCount);
assert completedTodoCount(this.completedCount);
assert totalTodoCount(this.activeCount + this.completedCount);
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
}
field this.completedCount = 0;
field this.activeCount = 0;
on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
on retracted todo($id, _, $c) { if (c) this.completedCount--; else this.activeCount--; }
assert activeTodoCount(this.activeCount);
assert completedTodoCount(this.completedCount);
assert totalTodoCount(this.activeCount + this.completedCount);
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
}
actor {
react {
during Syndicate.UI.locationHash($hash) {
assert Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected');
}
during Syndicate.UI.locationHash($hash) {
assert Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected');
}
during Syndicate.UI.locationHash('/') {
assert show(true);
assert show(false);
}
during Syndicate.UI.locationHash('/active') {
assert show(false);
}
during Syndicate.UI.locationHash('/completed') {
assert show(true);
}
during Syndicate.UI.locationHash('/') {
assert show(true);
assert show(false);
}
during Syndicate.UI.locationHash('/active') {
assert show(false);
}
during Syndicate.UI.locationHash('/completed') {
assert show(true);
}
}
@ -202,32 +190,32 @@ ground dataspace G {
}
} else {
db = {nextId: 0, todos: {}};
react until {
case asserted Syndicate.observe(createTodo(_)) {
:: createTodo('Buy milk');
:: createTodo('Buy bread');
:: createTodo('Finish PhD');
on start {
react {
stop on asserted Syndicate.observe(createTodo(_)) {
:: createTodo('Buy milk');
:: createTodo('Buy bread');
:: createTodo('Finish PhD');
}
}
}
}
react {
on message createTodo($title) {
todoListItemModel(db.nextId++, title, false);
}
on message createTodo($title) {
todoListItemModel(db.nextId++, title, false);
}
during todo($id, _, _) {
during todo(id, $title, $completed) {
do {
db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db);
}
}
finally {
delete db.todos[id];
during todo($id, _, _) {
during todo(id, $title, $completed) {
on start {
db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db);
}
}
on stop {
delete db.todos[id];
localStorage['todos-syndicate'] = JSON.stringify(db);
}
}
}
}

View File

@ -72,16 +72,16 @@ var splitProposal = Syndicate.Struct.makeConstructor("splitProposal", ["title","
/// core library.
///
function whileRelevantAssert(P) {
(function () {
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(P, 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(P), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(P), metalevel: 0 }; }), (function() {})).completeBuild(); }).call(this);
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(P, 0); }));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(P), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(P), metalevel: 0 }; }), (function() {}));
} }).bind(this)); });
}
/// ### Implementation: SELLER
function seller() {
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
/// We give our actor two state variables: a dictionary recording our
/// inventory of books (mapping title to price), and a counter
@ -112,42 +112,37 @@ function seller() {
/// The seller responds to interest in bookQuotes by asserting a
/// responsive record, if one exists.
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(bookQuote(_, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(bookQuote((Syndicate._$("title")), _)), metalevel: 0 }; }), (function(title) {
var _cachedAssertion1470624657591_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); }).call(this);
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, this.priceOf(title)), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470624657591_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470624657591_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(bookQuote(_, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(bookQuote((Syndicate._$("title")), _)), metalevel: 0 }; }), (function(title) {
var _cachedAssertion1472127201683_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); }).call(this);
{ Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, this.priceOf(title)), 0); }));
}
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1472127201683_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1472127201683_0, metalevel: 0 }; }), (function() {})); }).bind(this)); }}));
/// It also responds to order requests.
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(order(_, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(order((Syndicate._$("title")), (Syndicate._$("offerPrice")), _, _)), metalevel: 0 }; }), (function(title, offerPrice) {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(order(_, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(order((Syndicate._$("title")), (Syndicate._$("offerPrice")), _, _)), metalevel: 0 }; }), (function(title, offerPrice) {
/// We cannot sell a book we do not have, and we will not sell for
/// less than our asking price.
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
/// But if we can sell it, we do so by allocating an order ID and
/// replying to the orderer.
var orderId = this.nextOrderId++;
Syndicate.Actor.deleteField(this.books, title);
var orderId = this.nextOrderId++;
Syndicate.Actor.deleteField(this.books, title);
Syndicate.Actor.spawnActor(function() {
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
});
}
})).completeBuild(); }).call(this);
});
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}));
} }).bind(this)); });
}
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
@ -180,9 +175,8 @@ function buyerA() {
/// First, retrieve a quote for the title, and analyze the result.
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(bookQuote(title, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: bookQuote(title, (Syndicate._$("price"))), metalevel: 0 }; }), (function(price) {
(function () { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(bookQuote(title, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: bookQuote(title, (Syndicate._$("price"))), metalevel: 0 }; }), (function(price) {
if (price === false) {
console.log("A learns that "+title+" is out-of-stock.");
buyBooks();
@ -197,7 +191,8 @@ Syndicate.Actor.createFacet()
trySplit(title, price, price / 2);
}
})).completeBuild(); }).call(this);
}));
} }).bind(this)); }).call(this);
}
function trySplit(title, price, contribution) {
@ -216,20 +211,21 @@ Syndicate.Actor.createFacet()
/// Make our proposal, and wait for a response.
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, true), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, true), metalevel: 0 }; }), (function() {
(function () { Syndicate.Actor.Facet.build((function () { {
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, true), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, true), metalevel: 0 }; }), (function() {
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks();
}))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, false), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, false), metalevel: 0 }; }), (function() {
}));
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, false), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, false), metalevel: 0 }; }), (function() {
console.log("A learns that the split-proposal for "+
title+" was rejected");
trySplit(title,
price,
contribution + ((price - contribution) / 2));
})).completeBuild(); }).call(this);
}));
} }).bind(this)); }).call(this);
}
}
});
@ -238,7 +234,7 @@ Syndicate.Actor.createFacet()
/// ### Implementation: SPLIT-DISPOSER and BUYER
function buyerB() {
Syndicate.Actor.spawnActor(function() {
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
/// This actor maintains a record of the amount of money it has left
/// to spend.
@ -248,52 +244,55 @@ function buyerB() {
/// It spends its time waiting for a SPLIT-PROPOSER to offer a
/// `splitProposal`.
(function () {
Syndicate.Actor.createFacet()
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(splitProposal(_,
_,
_,
_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(splitProposal((Syndicate._$("title")),
(Syndicate._$("price")),
(Syndicate._$("theirContribution")),
_)), metalevel: 0 }; }), (function(title, price, theirContribution) {
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(splitProposal(_,
_,
_,
_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(splitProposal((Syndicate._$("title")),
(Syndicate._$("price")),
(Syndicate._$("theirContribution")),
_)), metalevel: 0 }; }), (function(title, price, theirContribution) {
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
/// We may not be able to afford contributing this much.
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
/// But if we *can* afford it, update our remaining funds and spawn a
/// small actor to handle the actual purchase now that we have agreed
/// on a split.
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
Syndicate.Actor.spawnActor(function() {
(function () {
Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title,
price,
theirContribution,
true), 0); }))
.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(order(title, price, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: order(title, price, (Syndicate._$("id")), (Syndicate._$("date"))), metalevel: 0 }; }), (function(id, date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
})).completeBuild(); }).call(this);
});
}
})).completeBuild(); }).call(this);
});
Syndicate.Actor.spawnActor(function() { Syndicate.Actor.Facet.build((function () { {
/// While waiting for order confirmation, take the opportunity to
/// signal to our SPLIT-PROPOSER that we accepted their proposal.
Syndicate.Actor.Facet.current.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title,
price,
theirContribution,
true), 0); }));
/// When order confirmation arrives, this purchase is completed.
Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(order(title, price, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: order(title, price, (Syndicate._$("id")), (Syndicate._$("date"))), metalevel: 0 }; }), (function(id, date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}));
} }).bind(this)); });
}
}));
} }).bind(this)); });
}
/// ### Starting Configuration

View File

@ -76,10 +76,9 @@ assertion type splitProposal(title, price, contribution, accepted);
/// core library.
///
function whileRelevantAssert(P) {
react {
actor {
assert P;
} until {
case retracted Syndicate.observe(P);
stop on retracted Syndicate.observe(P);
}
}
@ -117,38 +116,32 @@ function seller() {
/// The seller responds to interest in bookQuotes by asserting a
/// responsive record, if one exists.
react {
during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, this.priceOf(title));
}
during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, this.priceOf(title));
}
/// It also responds to order requests.
react {
on asserted
Syndicate.observe(order($title, $offerPrice, _, _)) {
on asserted
Syndicate.observe(order($title, $offerPrice, _, _)) {
/// We cannot sell a book we do not have, and we will not sell for
/// less than our asking price.
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
/// But if we can sell it, we do so by allocating an order ID and
/// replying to the orderer.
var orderId = this.nextOrderId++;
delete field this.books[title];
var orderId = this.nextOrderId++;
delete field this.books[title];
actor {
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}
}
@ -157,7 +150,7 @@ function seller() {
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() {
actor {
actor* {
var self = this;
/// Our actor remembers which books remain on its shopping list, and
@ -184,8 +177,8 @@ function buyerA() {
/// First, retrieve a quote for the title, and analyze the result.
react until {
case asserted bookQuote(title, $price) {
react {
stop on asserted bookQuote(title, $price) {
if (price === false) {
console.log("A learns that "+title+" is out-of-stock.");
buyBooks();
@ -220,15 +213,15 @@ function buyerA() {
/// Make our proposal, and wait for a response.
react until {
case asserted
react {
stop on asserted
splitProposal(title, price, contribution, true) {
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks();
}
case asserted
stop on asserted
splitProposal(title, price, contribution, false) {
console.log("A learns that the split-proposal for "+
title+" was rejected");
@ -255,55 +248,50 @@ function buyerB() {
/// It spends its time waiting for a SPLIT-PROPOSER to offer a
/// `splitProposal`.
react {
on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
/// We may not be able to afford contributing this much.
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
/// But if we *can* afford it, update our remaining funds and spawn a
/// small actor to handle the actual purchase now that we have agreed
/// on a split.
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
actor {
react {
actor {
/// While waiting for order confirmation, take the opportunity to
/// signal to our SPLIT-PROPOSER that we accepted their proposal.
assert splitProposal(title,
price,
theirContribution,
true);
assert splitProposal(title,
price,
theirContribution,
true);
/// When order confirmation arrives, this purchase is completed.
} until {
case asserted order(title, price, $id, $date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}
stop on asserted order(title, price, $id, $date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}
}
}
}
}

View File

@ -76,10 +76,9 @@ This routine is under consideration for possible addition to the
core library.
function whileRelevantAssert(P) {
react {
actor {
assert P;
} until {
case retracted Syndicate.observe(P);
stop on retracted Syndicate.observe(P);
}
}
@ -117,38 +116,32 @@ inventory.
The seller responds to interest in bookQuotes by asserting a
responsive record, if one exists.
react {
during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, this.priceOf(title));
}
during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, this.priceOf(title));
}
It also responds to order requests.
react {
on asserted
Syndicate.observe(order($title, $offerPrice, _, _)) {
on asserted
Syndicate.observe(order($title, $offerPrice, _, _)) {
We cannot sell a book we do not have, and we will not sell for
less than our asking price.
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(
order(title, offerPrice, false, false));
} else {
But if we can sell it, we do so by allocating an order ID and
replying to the orderer.
var orderId = this.nextOrderId++;
delete field this.books[title];
var orderId = this.nextOrderId++;
delete field this.books[title];
actor {
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}
}
@ -157,7 +150,7 @@ replying to the orderer.
### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() {
actor {
actor* {
var self = this;
Our actor remembers which books remain on its shopping list, and
@ -184,8 +177,8 @@ loop in almost a tail-recursive style, using helper functions
First, retrieve a quote for the title, and analyze the result.
react until {
case asserted bookQuote(title, $price) {
react {
stop on asserted bookQuote(title, $price) {
if (price === false) {
console.log("A learns that "+title+" is out-of-stock.");
buyBooks();
@ -220,15 +213,15 @@ perform the BUYER role here.
Make our proposal, and wait for a response.
react until {
case asserted
react {
stop on asserted
splitProposal(title, price, contribution, true) {
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks();
}
case asserted
stop on asserted
splitProposal(title, price, contribution, false) {
console.log("A learns that the split-proposal for "+
title+" was rejected");
@ -255,55 +248,50 @@ to spend.
It spends its time waiting for a SPLIT-PROPOSER to offer a
`splitProposal`.
react {
on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+
" toward "+title+" at price "+price);
We may not be able to afford contributing this much.
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+
" remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else {
But if we *can* afford it, update our remaining funds and spawn a
small actor to handle the actual purchase now that we have agreed
on a split.
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds;
actor {
react {
actor {
While waiting for order confirmation, take the opportunity to
signal to our SPLIT-PROPOSER that we accepted their proposal.
assert splitProposal(title,
price,
theirContribution,
true);
assert splitProposal(title,
price,
theirContribution,
true);
When order confirmation arrives, this purchase is completed.
} until {
case asserted order(title, price, $id, $date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}
stop on asserted order(title, price, $id, $date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}
}
}
}
}