This commit is contained in:
Tony Garnock-Jones 2016-08-07 15:41:10 -04:00
parent 6a5f786b6b
commit d6306ae41c
22 changed files with 1032 additions and 797 deletions

412
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

1
examples/button/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.expanded.js

7
examples/button/Makefile Normal file
View File

@ -0,0 +1,7 @@
all: index.expanded.js
%.expanded.js: %.js
../../bin/syndicatec $< > $@ || (rm -f $@; false)
clean:
rm -f *.expanded.js

View File

@ -2,13 +2,14 @@
new Syndicate.Ground(function () { new Syndicate.Ground(function () {
Syndicate.UI.spawnUIDriver(); Syndicate.UI.spawnUIDriver();
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
var counter = 0; Syndicate.Actor.declareField(this, "counter", 0);
var ui = new Syndicate.UI.Anchor(); var ui = new Syndicate.UI.Anchor();
Syndicate.Actor.createFacet() (function () {
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#button-label',''+counter), 0); })) Syndicate.Actor.createFacet()
.onEvent(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() { .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(ui.html('#button-label', '' + this.counter), 0); }))
counter++; .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() {
})).completeBuild(); this.counter++;
})).completeBuild(); }).call(this);
}); });
}).startStepping(); }).startStepping();

View File

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

View File

@ -17,6 +17,8 @@ function spawnChatApp() {
actor { actor {
var ui = new Syndicate.UI.Anchor(); var ui = new Syndicate.UI.Anchor();
field this.nym;
field this.status;
react { react {
on asserted inputValue('#nym', $v) { this.nym = v; } on asserted inputValue('#nym', $v) { this.nym = v; }
on asserted inputValue('#status', $v) { this.status = v; } on asserted inputValue('#status', $v) { this.status = v; }
@ -83,17 +85,11 @@ assertion type inputValue(selector, value);
function spawnInputChangeMonitor() { function spawnInputChangeMonitor() {
actor { actor {
react { react {
on asserted Syndicate.observe(inputValue($selector, _)) { during Syndicate.observe(inputValue($selector, _)) actor {
actor { field this.value = $(selector).val();
this.value = $(selector).val(); assert inputValue(selector, this.value);
react { on message Syndicate.UI.globalEvent(selector, 'change', $e) {
assert inputValue(selector, this.value); this.value = e.target.value;
on message Syndicate.UI.globalEvent(selector, 'change', $e) {
this.value = e.target.value;
}
} until {
case retracted Syndicate.observe(inputValue(selector, _));
}
} }
} }
} }

View File

@ -60,7 +60,7 @@ function spawnRemoteListener() {
function spawnStoveSwitch() { function spawnStoveSwitch() {
actor { actor {
this.powerOn = false; field this.powerOn = false;
this.ui = new Syndicate.UI.Anchor(); this.ui = new Syndicate.UI.Anchor();
react { react {
assert componentPresent('stove switch'); assert componentPresent('stove switch');
@ -85,7 +85,7 @@ function spawnStoveSwitch() {
function spawnPowerDrawMonitor() { function spawnPowerDrawMonitor() {
actor { actor {
this.watts = 0; field this.watts = 0;
this.ui = new Syndicate.UI.Anchor(); this.ui = new Syndicate.UI.Anchor();
react { react {
assert componentPresent('power draw monitor'); assert componentPresent('power draw monitor');

View File

@ -11,7 +11,7 @@ var G = new Syndicate.Ground(function () {
Syndicate.Timer.spawnTimerDriver(); Syndicate.Timer.spawnTimerDriver();
Syndicate.Broker.spawnBrokerClientDriver(); Syndicate.Broker.spawnBrokerClientDriver();
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
var id = Syndicate.RandomID.randomId(4, true); var id = Syndicate.RandomID.randomId(4, true);
var email_element = document.getElementById('my_email'); var email_element = document.getElementById('my_email');
@ -41,7 +41,7 @@ var G = new Syndicate.Ground(function () {
var geocoder = new google.maps.Geocoder(); var geocoder = new google.maps.Geocoder();
var wsurl_base = 'wss://demo-broker.syndicate-lang.org:8443/location/'; var wsurl_base = 'wss://demo-broker.syndicate-lang.org:8443/location/';
var wsurl = wsurl_base + group_element.value.trim(); Syndicate.Actor.declareField(this, "wsurl", wsurl_base + group_element.value.trim());
var watchId = ('geolocation' in navigator) var watchId = ('geolocation' in navigator)
&& navigator.geolocation.watchPosition(Syndicate.Dataspace.wrap(function (pos) { && navigator.geolocation.watchPosition(Syndicate.Dataspace.wrap(function (pos) {
@ -62,29 +62,29 @@ var G = new Syndicate.Ground(function () {
timeout: 15000 timeout: 15000
})); }));
(function () { var currentLocation = null; var selectedMarker = null; (function () { Syndicate.Actor.declareField(this, "currentLocation", null); var selectedMarker = null;
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(brokerConnection(wsurl), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(brokerConnection(this.wsurl), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (currentLocation) ? Syndicate.Patch.assert(toBroker(wsurl, currentLocation), 0) : Syndicate.Patch.emptyPatch; })) .addAssertion((function() { var _ = Syndicate.__; return (this.currentLocation) ? Syndicate.Patch.assert(toBroker(this.wsurl, this.currentLocation), 0) : Syndicate.Patch.emptyPatch; }))
.onEvent(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() { .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(); var v = email_element.value.trim();
if (currentLocation) currentLocation[1] = v; if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v; localStorage.my_email = v;
})) }))
.onEvent(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() { .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(); localStorage.group = group_element.value.trim();
wsurl = wsurl_base + group_element.value.trim(); this.wsurl = wsurl_base + group_element.value.trim();
})) }))
.onEvent(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) { .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.Dataspace.send(findMarker(document.getElementById('markerList').value));
})) }))
.onEvent(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) { .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.Dataspace.send(findMarker(document.getElementById('markerList').value));
})) }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub((locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: ((Syndicate._$("loc",locationRecord(_, _, _, _, _)))), metalevel: 0 }; }), (function(loc) { .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) {
currentLocation = loc; this.currentLocation = loc;
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(wsurl, locationRecord(_, _, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(wsurl, locationRecord((Syndicate._$("id")), (Syndicate._$("email")), _, _, _)), metalevel: 0 }; }), (function(id, email) { var ui = new Syndicate.UI.Anchor(); var marker = new google.maps.Marker({ .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, map: map,
clickable: true, clickable: true,
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro' icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
@ -105,7 +105,7 @@ Syndicate.Actor.createFacet()
}); });
} }
} }
var _cachedAssertion1470084347961_0 = (function() { var _ = Syndicate.__; return fromBroker(wsurl, locationRecord(id, email, _, _, _)); })(); var _cachedAssertion1470598812190_0 = (function() { var _ = Syndicate.__; return fromBroker(this.wsurl, locationRecord(id, email, _, _, _)); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { .addInitBlock((function() {
marker.addListener('click', Syndicate.Dataspace.wrap(function () { marker.addListener('click', Syndicate.Dataspace.wrap(function () {
@ -117,11 +117,11 @@ Syndicate.Actor.createFacet()
id: id, id: id,
email: email email: email
})), 0); })) })), 0); }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(findMarker(id), 0); }), (function() { var _ = Syndicate.__; return { assertion: findMarker(id), metalevel: 0 }; }), (function() { .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(); selectMarker();
if (latestPosition) map.panTo(latestPosition); if (latestPosition) map.panTo(latestPosition);
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(fromBroker(wsurl, locationRecord(id, email, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: fromBroker(wsurl, locationRecord(id, email, (Syndicate._$("timestamp")), (Syndicate._$("lat")), (Syndicate._$("lng")))), metalevel: 0 }; }), (function(timestamp, lat, lng) { .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); latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng}; latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition); marker.setPosition(latestPosition);
@ -132,6 +132,6 @@ Syndicate.Actor.createFacet()
marker.setMap(null); marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null; if (selectedMarker === marker) selectedMarker = null;
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084347961_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084347961_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598812190_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598812190_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
}); });
}).startStepping(); }).startStepping();

View File

@ -40,7 +40,7 @@ ground dataspace G {
var geocoder = new google.maps.Geocoder(); var geocoder = new google.maps.Geocoder();
var wsurl_base = 'wss://demo-broker.syndicate-lang.org:8443/location/'; var wsurl_base = 'wss://demo-broker.syndicate-lang.org:8443/location/';
var wsurl = wsurl_base + group_element.value.trim(); field this.wsurl = wsurl_base + group_element.value.trim();
var watchId = ('geolocation' in navigator) var watchId = ('geolocation' in navigator)
&& navigator.geolocation.watchPosition(Syndicate.Dataspace.wrap(function (pos) { && navigator.geolocation.watchPosition(Syndicate.Dataspace.wrap(function (pos) {
@ -62,21 +62,21 @@ ground dataspace G {
})); }));
react { react {
var currentLocation = null; field this.currentLocation = null;
var selectedMarker = null; var selectedMarker = null;
assert brokerConnection(wsurl); assert brokerConnection(this.wsurl);
assert toBroker(wsurl, currentLocation) when (currentLocation); assert toBroker(this.wsurl, this.currentLocation) when (this.currentLocation);
on message Syndicate.UI.globalEvent('#my_email', 'change', _) { on message Syndicate.UI.globalEvent('#my_email', 'change', _) {
var v = email_element.value.trim(); var v = email_element.value.trim();
if (currentLocation) currentLocation[1] = v; if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
localStorage.my_email = v; localStorage.my_email = v;
} }
on message Syndicate.UI.globalEvent('#group', 'change', _) { on message Syndicate.UI.globalEvent('#group', 'change', _) {
localStorage.group = group_element.value.trim(); localStorage.group = group_element.value.trim();
wsurl = wsurl_base + group_element.value.trim(); this.wsurl = wsurl_base + group_element.value.trim();
} }
on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) { on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) {
@ -87,10 +87,10 @@ ground dataspace G {
} }
on message ($loc = locationRecord(_, _, _, _, _)) { on message ($loc = locationRecord(_, _, _, _, _)) {
currentLocation = loc; this.currentLocation = loc;
} }
during fromBroker(wsurl, locationRecord($id, $email, _, _, _)) { during fromBroker(this.wsurl, locationRecord($id, $email, _, _, _)) {
var ui = new Syndicate.UI.Anchor(); var ui = new Syndicate.UI.Anchor();
var marker = new google.maps.Marker({ var marker = new google.maps.Marker({
map: map, map: map,
@ -131,7 +131,7 @@ ground dataspace G {
selectMarker(); selectMarker();
if (latestPosition) map.panTo(latestPosition); if (latestPosition) map.panTo(latestPosition);
} }
on asserted fromBroker(wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) { on asserted fromBroker(this.wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) {
latestTimestamp = new Date(timestamp); latestTimestamp = new Date(timestamp);
latestPosition = {lat: lat, lng: lng}; latestPosition = {lat: lat, lng: lng};
marker.setPosition(latestPosition); marker.setPosition(latestPosition);

View File

@ -14,8 +14,8 @@ ground dataspace G {
var color = tinycolor('hsl ' + (Math.random() * 360 | 0) + ' 100% 50%').toHexString(); var color = tinycolor('hsl ' + (Math.random() * 360 | 0) + ' 100% 50%').toHexString();
var x = 0; var x = 0;
var y = 0; var y = 0;
var publishedX = x; field this.publishedX = x;
var publishedY = y; field this.publishedY = y;
function clamp(v) { function clamp(v) {
var limit = 9.8; var limit = 9.8;
@ -28,10 +28,10 @@ ground dataspace G {
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color); assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
assert toBroker(wsurl, point(color, publishedX, publishedY)); assert toBroker(wsurl, point(color, this.publishedX, this.publishedY));
on message Syndicate.Timer.periodicTick(100) { on message Syndicate.Timer.periodicTick(100) {
publishedX = x; this.publishedX = x;
publishedY = y; this.publishedY = y;
} }
on message Syndicate.UI.windowEvent('deviceorientation', $e) { on message Syndicate.UI.windowEvent('deviceorientation', $e) {

View File

@ -6,16 +6,16 @@ ground dataspace {
actor { actor {
react until { react until {
case asserted Syndicate.observe(beep(_)) { case asserted Syndicate.observe(beep(_)) {
var counter = 0; field this.counter = 0;
react { react {
do { do {
:: beep(counter++); :: beep(this.counter++);
} }
on message beep(_) { on message beep(_) {
:: beep(counter++); :: beep(this.counter++);
} }
} until { } until {
case (counter >= 10); case (this.counter > 10);
} }
} }
} }

View File

@ -4,6 +4,10 @@ ground dataspace G {
actor { actor {
var ui = new Syndicate.UI.Anchor(); var ui = new Syndicate.UI.Anchor();
field this.angle;
field this.handX;
field this.handY;
react { react {
assert ui.html('#clock', assert ui.html('#clock',
'<svg width="300px" viewBox="0 0 100 100">'+ '<svg width="300px" viewBox="0 0 100 100">'+

View File

@ -20,7 +20,7 @@ function spawnModel() {
function spawnView() { function spawnView() {
actor named 'view' { actor named 'view' {
var ui = new Syndicate.UI.Anchor(); var ui = new Syndicate.UI.Anchor();
var orderColumn = 2; field this.orderColumn = 2;
function cell(text) { function cell(text) {
// Should escape text in a real application. // Should escape text in a real application.
@ -28,13 +28,13 @@ function spawnView() {
} }
react { react {
on message setSortColumn($c) { orderColumn = c; } on message setSortColumn($c) { this.orderColumn = c; }
during person($id, $firstName, $lastName, $address, $age) { during person($id, $firstName, $lastName, $address, $age) {
assert ui.context(id) assert ui.context(id)
.html('table#the-table tbody', .html('table#the-table tbody',
'<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>', '<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>',
[id, firstName, lastName, address, age][orderColumn]); [id, firstName, lastName, address, age][this.orderColumn]);
} }
} }
} }

View File

@ -26,24 +26,24 @@ function piece(text, pos, lo, hi, cls) {
function spawnGui() { function spawnGui() {
actor { actor {
this.text = '';
this.pos = 0;
this.highlightState = false;
this.updateDisplay = function () {
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");
};
react { react {
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");
}
on message globalEvent("#inputRow", "+keydown", $event) { on message globalEvent("#inputRow", "+keydown", $event) {
switch (event.keyCode) { switch (event.keyCode) {
case 37 /* left */: :: fieldCommand("cursorLeft"); break; case 37 /* left */: :: fieldCommand("cursorLeft"); break;
@ -67,12 +67,10 @@ function spawnGui() {
on asserted fieldContents($text, $pos) { on asserted fieldContents($text, $pos) {
this.text = text; this.text = text;
this.pos = pos; this.pos = pos;
this.updateDisplay();
} }
on asserted highlight($state) { on asserted highlight($state) {
this.highlightState = state; this.highlightState = state;
this.updateDisplay();
} }
} }
} }
@ -83,10 +81,10 @@ function spawnGui() {
function spawnModel() { function spawnModel() {
actor { actor {
this.fieldValue = "initial";
this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
react { react {
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") { on message fieldCommand("cursorLeft") {
@ -126,29 +124,28 @@ function spawnModel() {
function spawnSearch() { function spawnSearch() {
actor { actor {
this.fieldValue = "";
this.highlight = false;
this.search = function () {
var searchtext = document.getElementById("searchBox").value;
if (searchtext) {
var pos = this.fieldValue.indexOf(searchtext);
this.highlight = (pos !== -1) && [pos, pos + searchtext.length];
} else {
this.highlight = false;
}
};
react { react {
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;
}
}
on message globalEvent("#searchBox", "input", $event) { on message globalEvent("#searchBox", "input", $event) {
this.search(); this.searchtext = document.getElementById("searchBox").value;
} }
on asserted fieldContents($text, _) { on asserted fieldContents($text, _) {
this.fieldValue = text; this.fieldValue = text;
this.search();
} }
} }
} }

View File

@ -20,21 +20,17 @@ var show = Syndicate.Struct.makeConstructor("show", ["completed"]);
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
function todoListItemModel(initialId, initialTitle, initialCompleted) { function todoListItemModel(initialId, initialTitle, initialCompleted) {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
this.id = initialId; (function () { Syndicate.Actor.declareField(this, "id", initialId); Syndicate.Actor.declareField(this, "title", initialTitle); Syndicate.Actor.declareField(this, "completed", initialCompleted);
this.title = initialTitle;
this.completed = initialCompleted;
(function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(todo(this.id, this.title, this.completed), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(todo(this.id, this.title, this.completed), 0); }))
.onEvent(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(setCompleted(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setCompleted(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }))
.onEvent(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(setAllCompleted(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: setAllCompleted((Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.completed = v; }))
.onEvent(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(setTitle(this.id, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: setTitle(this.id, (Syndicate._$("v"))), metalevel: 0 }; }), (function(v) { this.title = v; }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(clearCompletedTodos(), 0); }), (function() { var _ = Syndicate.__; return { assertion: clearCompletedTodos(), metalevel: 0 }; }), (function() { .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)); if (this.completed) Syndicate.Dataspace.send(deleteTodo(this.id));
})) }))
.onEvent(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(); })(); .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);
}); });
} }
@ -48,16 +44,15 @@ function getTemplate(id) {
} }
function todoListItemView(id) { function todoListItemView(id) {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
this.ui = new Syndicate.UI.Anchor(); this.ui = new Syndicate.UI.Anchor();
this.editing = false; (function () { Syndicate.Actor.declareField(this, "editing", false);
(function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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 _cachedAssertion1470084349188_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })(); var _cachedAssertion1470598813428_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(show(completed), 0); }), (function() { var _ = Syndicate.__; return { assertion: show(completed), metalevel: 0 }; }), (function() { .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 _cachedAssertion1470084349188_1 = (function() { var _ = Syndicate.__; return show(completed); })(); var _cachedAssertion1470598813428_1 = (function() { var _ = Syndicate.__; return show(completed); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list', .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing Mustache.render(getTemplate(this.editing
@ -70,31 +65,31 @@ Syndicate.Actor.createFacet()
checked: completed ? "checked" : "", checked: completed ? "checked" : "",
}), }),
id), 0); })) id), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_1, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_1, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_0, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_0, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(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) { .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.Dataspace.send(setCompleted(id, e.target.checked));
})) }))
.onEvent(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() { .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.Dataspace.send(deleteTodo(id));
})) }))
.onEvent(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() { .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; this.editing = true;
})) }))
.onEvent(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) { .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) { if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
this.editing = false; this.editing = false;
} }
})) }))
.onEvent(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) { .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; this.editing = false;
})) }))
.onEvent(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) { .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(); var newTitle = e.target.value.trim();
Syndicate.Dataspace.send((newTitle ? setTitle(id, newTitle) : deleteTodo(id))); Syndicate.Dataspace.send((newTitle ? setTitle(id, newTitle) : deleteTodo(id)));
this.editing = false; this.editing = false;
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, _, _), metalevel: 0 }; }), (function() {})).completeBuild(); })(); .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);
}); });
} }
@ -103,96 +98,94 @@ Syndicate.Actor.createFacet()
var G = new Syndicate.Ground(function () { var G = new Syndicate.Ground(function () {
Syndicate.UI.spawnUIDriver(); Syndicate.UI.spawnUIDriver();
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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(); var newTitle = e.target.value.trim();
if (newTitle) Syndicate.Dataspace.send(createTodo(newTitle)); if (newTitle) Syndicate.Dataspace.send(createTodo(newTitle));
e.target.value = ""; e.target.value = "";
})).completeBuild(); })(); })).completeBuild(); }).call(this);
}); });
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
this.ui = new Syndicate.UI.Anchor(); this.ui = new Syndicate.UI.Anchor();
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(activeTodoCount(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: activeTodoCount((Syndicate._$("count"))), metalevel: 0 }; }), (function(count) { .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 _cachedAssertion1470084349188_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); })(); var _cachedAssertion1470598813428_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); }).call(this);
Syndicate.Actor.createFacet() 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 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; })) .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(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_2, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_2, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(totalTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: totalTodoCount(0), metalevel: 0 }; }), (function() { .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 _cachedAssertion1470084349188_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); })(); var _cachedAssertion1470598813428_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); }).call(this);
Syndicate.Actor.createFacet() 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('section.main', 'class', 'hidden'), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_3, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_3, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(completedTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: completedTodoCount(0), metalevel: 0 }; }), (function() { .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 _cachedAssertion1470084349188_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); })(); var _cachedAssertion1470598813428_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_4, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_4, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(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() { .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.Dataspace.send(clearCompletedTodos());
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(allCompleted(), 0); }), (function() { var _ = Syndicate.__; return { assertion: allCompleted(), metalevel: 0 }; }), (function() { .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 _cachedAssertion1470084349188_5 = (function() { var _ = Syndicate.__; return allCompleted(); })(); var _cachedAssertion1470598813428_5 = (function() { var _ = Syndicate.__; return allCompleted(); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); })) .addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); }))
.addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); })) .addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_5, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_5, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(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) { .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.Dataspace.send(setAllCompleted(e.target.checked));
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) { .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); todoListItemView(id);
})).completeBuild(); })(); })).completeBuild(); }).call(this);
}); });
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
var completedCount = 0; (function () { Syndicate.Actor.declareField(this, "completedCount", 0); Syndicate.Actor.declareField(this, "activeCount", 0);
var activeCount = 0;
(function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("completed"))), metalevel: 0 }; }), (function(id, completed) { if (completed) completedCount++; else activeCount++; })) .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(false, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, (Syndicate._$("completed"))), metalevel: 0 }; }), (function(id, completed) { if (completed) completedCount--; else 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(activeCount), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(activeTodoCount(this.activeCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(completedTodoCount(completedCount), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(completedTodoCount(this.completedCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(totalTodoCount(activeCount + completedCount), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(totalTodoCount(this.activeCount + this.completedCount), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (completedCount > 0 && activeCount === 0) ? Syndicate.Patch.assert(allCompleted(), 0) : Syndicate.Patch.emptyPatch; })).completeBuild(); })(); .addAssertion((function() { var _ = Syndicate.__; return (this.completedCount > 0 && this.activeCount === 0) ? Syndicate.Patch.assert(allCompleted(), 0) : Syndicate.Patch.emptyPatch; })).completeBuild(); }).call(this);
}); });
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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 _cachedAssertion1470084349188_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); })(); var _cachedAssertion1470598813428_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]', .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected'), 0); })) 'class', 'selected'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_6, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_6, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/'), metalevel: 0 }; }), (function() { .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 _cachedAssertion1470084349188_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); })(); var _cachedAssertion1470598813428_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_7, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_7, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(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() { .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 _cachedAssertion1470084349188_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); })(); var _cachedAssertion1470598813428_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_8, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_8, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(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() { .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 _cachedAssertion1470084349188_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); })(); var _cachedAssertion1470598813428_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_9, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_9, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
}); });
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
var db; var db;
if ('todos-syndicate' in localStorage) { if ('todos-syndicate' in localStorage) {
@ -205,33 +198,33 @@ Syndicate.Actor.createFacet()
db = {nextId: 0, todos: {}}; db = {nextId: 0, todos: {}};
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(createTodo(_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(createTodo(_)), metalevel: 0 }; }), (function() { .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 milk'));
Syndicate.Dataspace.send(createTodo('Buy bread')); Syndicate.Dataspace.send(createTodo('Buy bread'));
Syndicate.Dataspace.send(createTodo('Finish PhD')); Syndicate.Dataspace.send(createTodo('Finish PhD'));
})).completeBuild(); })(); })).completeBuild(); }).call(this);
} }
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(createTodo(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: createTodo((Syndicate._$("title"))), metalevel: 0 }; }), (function(title) { .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); todoListItemModel(db.nextId++, title, false);
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) { .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 _cachedAssertion1470084349188_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); })(); var _cachedAssertion1470598813428_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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 _cachedAssertion1470084349188_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })(); var _cachedAssertion1470598813428_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { .addInitBlock((function() {
db.todos[id] = {id: id, title: title, completed: completed}; db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db); localStorage['todos-syndicate'] = JSON.stringify(db);
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_11, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_11, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.addDoneBlock((function() { .addDoneBlock((function() {
delete db.todos[id]; delete db.todos[id];
localStorage['todos-syndicate'] = JSON.stringify(db); localStorage['todos-syndicate'] = JSON.stringify(db);
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084349188_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084349188_10, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598813428_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598813428_10, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
}); });
}).startStepping(); }).startStepping();

View File

@ -25,11 +25,11 @@ assertion type show(completed);
function todoListItemModel(initialId, initialTitle, initialCompleted) { function todoListItemModel(initialId, initialTitle, initialCompleted) {
actor { actor {
this.id = initialId;
this.title = initialTitle;
this.completed = initialCompleted;
react { react {
field this.id = initialId;
field this.title = initialTitle;
field this.completed = initialCompleted;
assert todo(this.id, this.title, this.completed); assert todo(this.id, this.title, this.completed);
on message setCompleted(this.id, $v) { this.completed = v; } on message setCompleted(this.id, $v) { this.completed = v; }
@ -58,8 +58,9 @@ function getTemplate(id) {
function todoListItemView(id) { function todoListItemView(id) {
actor { actor {
this.ui = new Syndicate.UI.Anchor(); this.ui = new Syndicate.UI.Anchor();
this.editing = false;
react { react {
field this.editing = false;
during todo(id, $title, $completed) { during todo(id, $title, $completed) {
during show(completed) { during show(completed) {
assert this.ui.html('.todo-list', assert this.ui.html('.todo-list',
@ -158,15 +159,15 @@ ground dataspace G {
} }
actor { actor {
var completedCount = 0;
var activeCount = 0;
react { react {
on asserted todo($id, _, $completed) { if (completed) completedCount++; else activeCount++; } field this.completedCount = 0;
on retracted todo($id, _, $completed) { if (completed) completedCount--; else activeCount--; } field this.activeCount = 0;
assert activeTodoCount(activeCount); on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
assert completedTodoCount(completedCount); on retracted todo($id, _, $c) { if (c) this.completedCount--; else this.activeCount--; }
assert totalTodoCount(activeCount + completedCount); assert activeTodoCount(this.activeCount);
assert allCompleted() when (completedCount > 0 && activeCount === 0); assert completedTodoCount(this.completedCount);
assert totalTodoCount(this.activeCount + this.completedCount);
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
} }
} }

View File

@ -75,30 +75,38 @@ function whileRelevantAssert(P) {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(P, 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(P, 0); }))
.onEvent(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(); })(); .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);
} }
/// ### Implementation: SELLER /// ### Implementation: SELLER
function seller() { function seller() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
/// We give our actor two state variables: a dictionary recording our /// We give our actor two state variables: a dictionary recording our
/// inventory of books (mapping title to price), and a counter /// inventory of books (mapping title to price), and a counter
/// tracking the next order ID to be allocated. /// tracking the next order ID to be allocated.
///
/// We mark each property (entry) in the `books` table as a *field* so
/// that dependency-tracking on a per-book basis is enabled. As a result,
/// when a book is sold, any client still interested in its price will
/// learn that the book is no longer available.
///
/// We do not enable dependency-tracking for either the `books` table
/// itself or the `nextOrderId` field: nothing depends on tracking
/// changes in their values.
this.books = { this.books = {};
"The Wind in the Willows": 3.95, Syndicate.Actor.declareField(this.books, "The Wind in the Willows", 3.95);
"Catch 22": 2.22, Syndicate.Actor.declareField(this.books, "Catch 22", 2.22);
"Candide": 34.95 Syndicate.Actor.declareField(this.books, "Candide", 34.95);
};
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
/// Looking up a price yields `false` if no such book is in our /// Looking up a price yields `false` if no such book is in our
/// inventory. /// inventory.
this.priceOf = function (title) { this.priceOf = function (title) {
return (title in this.books) && this.books[title]; return (title in this.books) && Syndicate.Actor.referenceField(this.books, title);
}; };
/// The seller responds to interest in bookQuotes by asserting a /// The seller responds to interest in bookQuotes by asserting a
@ -106,17 +114,17 @@ function seller() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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 _cachedAssertion1470084350531_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); })(); var _cachedAssertion1470598814704_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); }).call(this);
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, this.priceOf(title)), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, this.priceOf(title)), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470084350531_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470084350531_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(Syndicate.Actor.PRIORITY_NORMAL, true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1470598814704_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1470598814704_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); }).call(this);
/// It also responds to order requests. /// It also responds to order requests.
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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 /// We cannot sell a book we do not have, and we will not sell for
/// less than our asking price. /// less than our asking price.
@ -131,21 +139,21 @@ Syndicate.Actor.createFacet()
/// replying to the orderer. /// replying to the orderer.
var orderId = this.nextOrderId++; var orderId = this.nextOrderId++;
delete this.books[title]; Syndicate.Actor.deleteField(this.books, title);
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
whileRelevantAssert( whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th")); order(title, offerPrice, orderId, "March 9th"));
}); });
} }
})).completeBuild(); })(); })).completeBuild(); }).call(this);
}); });
} }
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor /// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() { function buyerA() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
var self = this; var self = this;
/// Our actor remembers which books remain on its shopping list, and /// Our actor remembers which books remain on its shopping list, and
@ -174,7 +182,7 @@ function buyerA() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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) { .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) { if (price === false) {
console.log("A learns that "+title+" is out-of-stock."); console.log("A learns that "+title+" is out-of-stock.");
buyBooks(); buyBooks();
@ -189,7 +197,7 @@ Syndicate.Actor.createFacet()
trySplit(title, price, price / 2); trySplit(title, price, price / 2);
} }
})).completeBuild(); })(); })).completeBuild(); }).call(this);
} }
function trySplit(title, price, contribution) { function trySplit(title, price, contribution) {
@ -210,18 +218,18 @@ Syndicate.Actor.createFacet()
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(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() { .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 "+ console.log("A learns that the split-proposal for "+
title+" was accepted"); title+" was accepted");
buyBooks(); buyBooks();
})) }))
.onEvent(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() { .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 "+ console.log("A learns that the split-proposal for "+
title+" was rejected"); title+" was rejected");
trySplit(title, trySplit(title,
price, price,
contribution + ((price - contribution) / 2)); contribution + ((price - contribution) / 2));
})).completeBuild(); })(); })).completeBuild(); }).call(this);
} }
} }
}); });
@ -230,7 +238,7 @@ Syndicate.Actor.createFacet()
/// ### Implementation: SPLIT-DISPOSER and BUYER /// ### Implementation: SPLIT-DISPOSER and BUYER
function buyerB() { function buyerB() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
/// This actor maintains a record of the amount of money it has left /// This actor maintains a record of the amount of money it has left
/// to spend. /// to spend.
@ -242,7 +250,7 @@ function buyerB() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(splitProposal(_, .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")), _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(splitProposal((Syndicate._$("title")),
@ -271,20 +279,20 @@ Syndicate.Actor.createFacet()
remainingFunds+" remaining funds"); remainingFunds+" remaining funds");
this.funds = remainingFunds; this.funds = remainingFunds;
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(function() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title, .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title,
price, price,
theirContribution, theirContribution,
true), 0); })) true), 0); }))
.onEvent(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) { .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+ console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date); ", and will be delivered on "+date);
})).completeBuild(); })(); })).completeBuild(); }).call(this);
}); });
} }
})).completeBuild(); })(); })).completeBuild(); }).call(this);
}); });
} }

View File

@ -91,19 +91,27 @@ function seller() {
/// We give our actor two state variables: a dictionary recording our /// We give our actor two state variables: a dictionary recording our
/// inventory of books (mapping title to price), and a counter /// inventory of books (mapping title to price), and a counter
/// tracking the next order ID to be allocated. /// tracking the next order ID to be allocated.
///
/// We mark each property (entry) in the `books` table as a *field* so
/// that dependency-tracking on a per-book basis is enabled. As a result,
/// when a book is sold, any client still interested in its price will
/// learn that the book is no longer available.
///
/// We do not enable dependency-tracking for either the `books` table
/// itself or the `nextOrderId` field: nothing depends on tracking
/// changes in their values.
this.books = { this.books = {};
"The Wind in the Willows": 3.95, field this.books["The Wind in the Willows"] = 3.95;
"Catch 22": 2.22, field this.books["Catch 22"] = 2.22;
"Candide": 34.95 field this.books["Candide"] = 34.95;
};
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
/// Looking up a price yields `false` if no such book is in our /// Looking up a price yields `false` if no such book is in our
/// inventory. /// inventory.
this.priceOf = function (title) { this.priceOf = function (title) {
return (title in this.books) && this.books[title]; return (title in this.books) && field this.books[title];
}; };
/// The seller responds to interest in bookQuotes by asserting a /// The seller responds to interest in bookQuotes by asserting a
@ -134,7 +142,7 @@ function seller() {
/// replying to the orderer. /// replying to the orderer.
var orderId = this.nextOrderId++; var orderId = this.nextOrderId++;
delete this.books[title]; delete field this.books[title];
actor { actor {
whileRelevantAssert( whileRelevantAssert(

View File

@ -92,18 +92,26 @@ We give our actor two state variables: a dictionary recording our
inventory of books (mapping title to price), and a counter inventory of books (mapping title to price), and a counter
tracking the next order ID to be allocated. tracking the next order ID to be allocated.
this.books = { We mark each property (entry) in the `books` table as a *field* so
"The Wind in the Willows": 3.95, that dependency-tracking on a per-book basis is enabled. As a result,
"Catch 22": 2.22, when a book is sold, any client still interested in its price will
"Candide": 34.95 learn that the book is no longer available.
};
We do not enable dependency-tracking for either the `books` table
itself or the `nextOrderId` field: nothing depends on tracking
changes in their values.
this.books = {};
field this.books["The Wind in the Willows"] = 3.95;
field this.books["Catch 22"] = 2.22;
field this.books["Candide"] = 34.95;
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
Looking up a price yields `false` if no such book is in our Looking up a price yields `false` if no such book is in our
inventory. inventory.
this.priceOf = function (title) { this.priceOf = function (title) {
return (title in this.books) && this.books[title]; return (title in this.books) && field this.books[title];
}; };
The seller responds to interest in bookQuotes by asserting a The seller responds to interest in bookQuotes by asserting a
@ -134,7 +142,7 @@ But if we can sell it, we do so by allocating an order ID and
replying to the orderer. replying to the orderer.
var orderId = this.nextOrderId++; var orderId = this.nextOrderId++;
delete this.books[title]; delete field this.books[title];
actor { actor {
whileRelevantAssert( whileRelevantAssert(