Update
This commit is contained in:
parent
d31a5fcf58
commit
8abc6b6975
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -124,7 +124,7 @@ var modifiedSourceActions = {
|
|||
var label = maybeLabel.numChildren === 1
|
||||
? maybeLabel.children[0].interval.contents
|
||||
: JSON.stringify(typeName.interval.contents);
|
||||
return 'var ' + typeName.asES5 + ' = Syndicate.Struct.makeStructureConstructor(' +
|
||||
return 'var ' + typeName.asES5 + ' = Syndicate.Struct.makeConstructor(' +
|
||||
label + ', ' + JSON.stringify(formals) + ');';
|
||||
},
|
||||
|
||||
|
@ -295,14 +295,35 @@ semantics.addOperation('buildSubscription(acc,mode)', {
|
|||
v.children[0].buildSubscription(this.args.acc, this.args.mode); // both branches!
|
||||
},
|
||||
|
||||
AssignmentExpression_assignment: function (lhsExpr, _assignmentOperator, rhsExpr) {
|
||||
var i = lhsExpr.interval.contents;
|
||||
if (i[0] === '$' && i.length > 1) {
|
||||
switch (this.args.mode) {
|
||||
case 'pattern': rhsExpr.buildSubscription(this.args.acc, this.args.mode); break;
|
||||
case 'instantiated': lhsExpr.buildSubscription(this.args.acc, this.args.mode); break;
|
||||
case 'projection': {
|
||||
this.args.acc.push('(Syndicate._$(' + JSON.stringify(i.slice(1)) + ',');
|
||||
rhsExpr.buildSubscription(this.args.acc, this.args.mode);
|
||||
this.args.acc.push('))');
|
||||
break;
|
||||
}
|
||||
default: throw new Error('Unexpected buildSubscription mode ' + this.args.mode);
|
||||
}
|
||||
} else {
|
||||
lhsExpr.buildSubscription(this.args.acc, this.args.mode);
|
||||
_assignmentOperator.buildSubscription(this.args.acc, this.args.mode);
|
||||
rhsExpr.buildSubscription(this.args.acc, this.args.mode);
|
||||
}
|
||||
},
|
||||
|
||||
identifier: function(_name) {
|
||||
var i = this.interval.contents;
|
||||
if (i[0] === '$') {
|
||||
if (i[0] === '$' && i.length > 1) {
|
||||
switch (this.args.mode) {
|
||||
case 'pattern': this.args.acc.push('_'); break;
|
||||
case 'instantiated': this.args.acc.push(i.slice(1)); break;
|
||||
case 'projection': this.args.acc.push('(Syndicate._$(' + JSON.stringify(i.slice(1)) + '))'); break;
|
||||
default: throw new Error('Unexpected buildSubscription mode ' + this.args.mode);
|
||||
case 'pattern': this.args.acc.push('_'); break;
|
||||
case 'instantiated': this.args.acc.push(i.slice(1)); break;
|
||||
case 'projection': this.args.acc.push('(Syndicate._$(' + JSON.stringify(i.slice(1)) + '))'); break;
|
||||
default: throw new Error('Unexpected buildSubscription mode ' + this.args.mode);
|
||||
}
|
||||
} else {
|
||||
this.args.acc.push(i);
|
||||
|
@ -330,7 +351,7 @@ semantics.addAttribute('bindings', {
|
|||
semantics.addOperation('pushBindings(accumulator)', {
|
||||
identifier: function(_name) {
|
||||
var i = this.interval.contents;
|
||||
if (i[0] === '$') {
|
||||
if (i[0] === '$' && i.length > 1) {
|
||||
this.args.accumulator.push(i.slice(1));
|
||||
}
|
||||
},
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,237 @@
|
|||
"use strict";
|
||||
// WebSocket-based Syndicate broker client
|
||||
|
||||
var Trie = Syndicate.Trie;
|
||||
var Patch = Syndicate.Patch;
|
||||
var Dataspace = Syndicate.Dataspace;
|
||||
var Struct = Syndicate.Struct;
|
||||
var DemandMatcher = Syndicate.DemandMatcher;
|
||||
var __ = Syndicate.__;
|
||||
var _$ = Syndicate._$;
|
||||
|
||||
var DEFAULT_RECONNECT_DELAY = 100; // ms
|
||||
var MAX_RECONNECT_DELAY = 30000; // ms
|
||||
var DEFAULT_IDLE_TIMEOUT = 300000; // ms; i.e., 5 minutes
|
||||
var DEFAULT_PING_INTERVAL = DEFAULT_IDLE_TIMEOUT - 10000; // ms
|
||||
|
||||
var toBroker = Struct.makeConstructor('toBroker', ['url', 'assertion']);
|
||||
var fromBroker = Struct.makeConstructor('fromBroker', ['url', 'assertion']);
|
||||
var brokerConnection = Struct.makeConstructor('brokerConnection', ['url']);
|
||||
var brokerConnected = Struct.makeConstructor('brokerConnected', ['url']);
|
||||
var forceBrokerDisconnect = Struct.makeConstructor('forceBrokerDisconnect', ['url']);
|
||||
|
||||
function spawnBrokerClientDriver() {
|
||||
var URL = _$('url'); // capture used to extract URL
|
||||
Dataspace.spawn(
|
||||
new Dataspace(function () {
|
||||
Dataspace.spawn(
|
||||
new DemandMatcher([brokerConnection(URL)],
|
||||
[brokerConnection(URL)],
|
||||
{
|
||||
demandMetaLevel: 1,
|
||||
supplyMetaLevel: 0,
|
||||
onDemandIncrease: function (c) {
|
||||
Dataspace.spawn(new BrokerClientConnection(c.url));
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
function BrokerClientConnection(wsurl) {
|
||||
this.wsurl = wsurl;
|
||||
this.sock = null;
|
||||
|
||||
this.sendsAttempted = 0;
|
||||
this.sendsTransmitted = 0;
|
||||
this.receiveCount = 0;
|
||||
this.connectionCount = 0;
|
||||
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.idleTimeout = DEFAULT_IDLE_TIMEOUT;
|
||||
this.pingInterval = DEFAULT_PING_INTERVAL;
|
||||
|
||||
this.localAssertions = Trie.emptyTrie;
|
||||
this.remoteAssertions = Trie.emptyTrie;
|
||||
|
||||
this.activityTimestamp = 0;
|
||||
this.idleTimer = null;
|
||||
this.pingTimer = null;
|
||||
}
|
||||
|
||||
BrokerClientConnection.prototype.clearHeartbeatTimers = function () {
|
||||
if (this.idleTimer) { clearTimeout(this.idleTimer); this.idleTimer = null; }
|
||||
if (this.pingTimer) { clearTimeout(this.pingTimer); this.pingTimer = null; }
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.recordActivity = function () {
|
||||
var self = this;
|
||||
this.activityTimestamp = +(new Date());
|
||||
this.clearHeartbeatTimers();
|
||||
this.idleTimer = setTimeout(function () { self.forceclose(); }, this.idleTimeout);
|
||||
this.pingTimer = setTimeout(function () { self.safeSend(JSON.stringify("ping")) },
|
||||
this.pingInterval);
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.boot = function () {
|
||||
this.reconnect();
|
||||
var initialAssertions =
|
||||
Patch.sub(toBroker(this.wsurl, __), 1) // read assertions to go out
|
||||
.andThen(Patch.sub(Patch.observe(fromBroker(this.wsurl, __)), 1)) // and monitor interests
|
||||
.andThen(Patch.assert(brokerConnection(this.wsurl))) // signal to DemandMatcher that we exist
|
||||
.andThen(Patch.sub(brokerConnection(this.wsurl), 1)) // track demand
|
||||
.andThen(Patch.sub(forceBrokerDisconnect(this.wsurl), 1))
|
||||
;
|
||||
return initialAssertions;
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.trapexit = function () {
|
||||
this.forceclose();
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.isConnected = function () {
|
||||
return this.sock && this.sock.readyState === this.sock.OPEN;
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.safeSend = function (m) {
|
||||
// console.log('safeSend', m);
|
||||
try {
|
||||
this.sendsAttempted++;
|
||||
if (this.isConnected()) {
|
||||
this.sock.send(m);
|
||||
this.sendsTransmitted++;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Trapped exn while sending", e);
|
||||
}
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.sendPatch = function (p) {
|
||||
var j = JSON.stringify(Codec.encodeEvent(Syndicate.stateChange(p)));
|
||||
this.safeSend(j);
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.handleEvent = function (e) {
|
||||
// console.log("BrokerClientConnection.handleEvent", e);
|
||||
switch (e.type) {
|
||||
case "stateChange":
|
||||
if (e.patch.project(Patch.atMeta(brokerConnection(_$))).hasRemoved()) {
|
||||
// console.log("Client is no longer interested in this connection", this.wsurl);
|
||||
Dataspace.exit();
|
||||
}
|
||||
|
||||
var pTo = e.patch.project(Patch.atMeta(toBroker(__, _$)));
|
||||
|
||||
var pObsFrom = e.patch.project(Patch.atMeta(Patch.observe(fromBroker(__, _$))));
|
||||
pObsFrom = new Patch.Patch(
|
||||
Trie.compilePattern(true, Patch.observe(Trie.embeddedTrie(pObsFrom.added))),
|
||||
Trie.compilePattern(true, Patch.observe(Trie.embeddedTrie(pObsFrom.removed))));
|
||||
|
||||
var newLocalAssertions = this.localAssertions;
|
||||
newLocalAssertions = pTo.label(Immutable.Set.of("to")).applyTo(newLocalAssertions);
|
||||
newLocalAssertions = pObsFrom.label(Immutable.Set.of("obsFrom")).applyTo(newLocalAssertions);
|
||||
|
||||
var trueSet = Immutable.Set.of(true);
|
||||
var alwaysTrueSet = function (v) { return trueSet; };
|
||||
var p = Patch.computePatch(Trie.relabel(this.localAssertions, alwaysTrueSet),
|
||||
Trie.relabel(newLocalAssertions, alwaysTrueSet));
|
||||
|
||||
this.localAssertions = newLocalAssertions;
|
||||
// console.log("localAssertions");
|
||||
// console.log(Trie.prettyTrie(this.localAssertions));
|
||||
// console.log(p.pretty());
|
||||
this.sendPatch(p);
|
||||
break;
|
||||
|
||||
case "message":
|
||||
var m = e.message;
|
||||
if (Patch.atMeta.isClassOf(m)) {
|
||||
m = m[0];
|
||||
if (toBroker.isClassOf(m)) {
|
||||
var j = JSON.stringify(Codec.encodeEvent(Syndicate.message(m[1])));
|
||||
this.safeSend(j);
|
||||
} else if (forceBrokerDisconnect.isClassOf(m)) {
|
||||
this.forceclose();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.forceclose = function (keepReconnectDelay) {
|
||||
if (!keepReconnectDelay) {
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
}
|
||||
this.clearHeartbeatTimers();
|
||||
if (this.sock) {
|
||||
console.log("BrokerClientConnection.forceclose called");
|
||||
this.sock.close();
|
||||
this.sock = null;
|
||||
}
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.reconnect = function () {
|
||||
var self = this;
|
||||
this.forceclose(true);
|
||||
this.connectionCount++;
|
||||
this.sock = new WebSocket(this.wsurl);
|
||||
this.sock.onopen = Dataspace.wrap(function (e) { return self.onopen(e); });
|
||||
this.sock.onmessage = Dataspace.wrap(function (e) {
|
||||
self.receiveCount++;
|
||||
return self.onmessage(e);
|
||||
});
|
||||
this.sock.onclose = Dataspace.wrap(function (e) { return self.onclose(e); });
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.onopen = function (e) {
|
||||
console.log("connected to " + this.sock.url);
|
||||
this.recordActivity();
|
||||
Dataspace.stateChange(Patch.assert(brokerConnected(this.wsurl), 1));
|
||||
this.reconnectDelay = DEFAULT_RECONNECT_DELAY;
|
||||
this.sendPatch((new Patch.Patch(this.localAssertions, Trie.emptyTrie)).strip());
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.onmessage = function (wse) {
|
||||
// console.log("onmessage", wse);
|
||||
this.recordActivity();
|
||||
|
||||
var j = JSON.parse(wse.data, Struct.reviver);
|
||||
if (j === "ping") {
|
||||
this.safeSend(JSON.stringify("pong"));
|
||||
return;
|
||||
} else if (j === "pong") {
|
||||
return; // recordActivity already took care of our timers
|
||||
}
|
||||
|
||||
var e = Codec.decodeAction(j);
|
||||
switch (e.type) {
|
||||
case "stateChange": {
|
||||
var added = fromBroker(this.wsurl, Trie.embeddedTrie(e.patch.added));
|
||||
var removed = fromBroker(this.wsurl, Trie.embeddedTrie(e.patch.removed));
|
||||
var p = Patch.assert(added, 1).andThen(Patch.retract(removed, 1));
|
||||
// console.log('incoming stateChange');
|
||||
// console.log(p.pretty());
|
||||
Dataspace.stateChange(p);
|
||||
break;
|
||||
}
|
||||
case "message": {
|
||||
Dataspace.send(fromBroker(this.wsurl, e.message), 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BrokerClientConnection.prototype.onclose = function (e) {
|
||||
var self = this;
|
||||
|
||||
// console.log("onclose", e);
|
||||
Dataspace.stateChange(Patch.retract(brokerConnected(this.wsurl), 1));
|
||||
|
||||
console.log("reconnecting to " + this.wsurl + " in " + this.reconnectDelay + "ms");
|
||||
setTimeout(Dataspace.wrap(function () { self.reconnect(); }), this.reconnectDelay);
|
||||
|
||||
this.reconnectDelay = this.reconnectDelay * 1.618 + (Math.random() * 1000);
|
||||
this.reconnectDelay =
|
||||
this.reconnectDelay > MAX_RECONNECT_DELAY
|
||||
? MAX_RECONNECT_DELAY + (Math.random() * 1000)
|
||||
: this.reconnectDelay;
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
// Wire protocol representation of events and actions
|
||||
|
||||
var Trie = Syndicate.Trie;
|
||||
var Struct = Syndicate.Struct;
|
||||
|
||||
function _encode(e) {
|
||||
switch (e.type) {
|
||||
case "stateChange":
|
||||
return ["patch", e.patch.toJSON()];
|
||||
case "message":
|
||||
return ["message", e.message];
|
||||
}
|
||||
}
|
||||
|
||||
function _decode(what) {
|
||||
return function (j) {
|
||||
switch (j[0]) {
|
||||
case "patch":
|
||||
return Syndicate.stateChange(Patch.fromJSON(j[1]));
|
||||
case "message":
|
||||
return Syndicate.message(j[1]);
|
||||
default:
|
||||
throw new Error("Invalid JSON-encoded " + what + ": " + JSON.stringify(j));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// module.exports.encodeEvent = _encode;
|
||||
// module.exports.decodeEvent = _decode("event");
|
||||
// module.exports.encodeAction = _encode;
|
||||
// module.exports.decodeAction = _decode("action");
|
||||
|
||||
var Codec = {
|
||||
encodeEvent: _encode,
|
||||
decodeEvent: _decode("event"),
|
||||
encodeAction: _encode,
|
||||
decodeAction: _decode("action")
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Syndicate: Chat</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script> <!-- TODO: ??? -->
|
||||
<script src="../../third-party/jquery-2.2.0.min.js"></script>
|
||||
<script src="../../dist/syndicatecompiler.js"></script>
|
||||
<script src="../../dist/syndicate.js"></script>
|
||||
<script src="codec.js"></script>
|
||||
<script src="broker-client.js"></script>
|
||||
<script type="text/syndicate-js" src="index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<form name="nym_form">
|
||||
<fieldset>
|
||||
<label class="control-label" for="wsurl">Server:</label>
|
||||
<input type="text" id="wsurl" name="wsurl" value="ws://localhost:8000/">
|
||||
|
||||
<label class="control-label" for="nym">Nym:</label>
|
||||
<input type="text" id="nym" name="nym" value="">
|
||||
|
||||
<label class="control-label" for="status">Status:</label>
|
||||
<input type="text" id="status" name="status" value="">
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section id="messages">
|
||||
<h1>Messages</h1>
|
||||
<div id="chat_output"></div>
|
||||
</section>
|
||||
<section id="active_users">
|
||||
<h1>Active Users</h1>
|
||||
<ul id="nymlist"></ul>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<form id="chat_form" name="chat_form">
|
||||
<fieldset>
|
||||
<input type="text" id="chat_input" name="chat_input" value="" autocomplete="off">
|
||||
<button id="send_chat">Send</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
<pre id="ds-state"></pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,116 @@
|
|||
assertion type present(name, status);
|
||||
assertion type says(who, message);
|
||||
|
||||
var DOM = Syndicate.DOM.DOM;
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Application
|
||||
|
||||
function spawnChatApp() {
|
||||
$("#chat_form").submit(function (e) { e.preventDefault(); return false; });
|
||||
$("#nym_form").submit(function (e) { e.preventDefault(); return false; });
|
||||
if (!($("#nym").val())) { $("#nym").val("nym" + Math.floor(Math.random() * 65536)); }
|
||||
|
||||
actor {
|
||||
forever {
|
||||
on asserted jQueryInput('#nym', $v) { this.nym = v; }
|
||||
on asserted jQueryInput('#status', $v) { this.status = v; }
|
||||
|
||||
on asserted brokerConnected($url) { outputState('connected to ' + url); }
|
||||
on retracted brokerConnected($url) { outputState('disconnected from ' + url); }
|
||||
|
||||
during jQueryInput('#wsurl', $url) {
|
||||
assert brokerConnection(url);
|
||||
|
||||
on message Syndicate.WakeDetector.wakeEvent() {
|
||||
:: forceBrokerDisconnect(url);
|
||||
}
|
||||
|
||||
assert toBroker(url, present(this.nym, this.status));
|
||||
during fromBroker(url, present($who, $status)) {
|
||||
assert DOM('#nymlist', 'present-nym', Syndicate.seal(
|
||||
["li",
|
||||
["span", [["class", "nym"]], who],
|
||||
["span", [["class", "nym_status"]], status]]));
|
||||
}
|
||||
|
||||
on message jQueryEvent('#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Adding items to the transcript panel (plain Javascript/jQuery)
|
||||
|
||||
function outputItem(item) {
|
||||
var stamp = $("<span/>").text((new Date()).toGMTString()).addClass("timestamp");
|
||||
var item = $("<div/>").append([stamp].concat(item));
|
||||
var o = $("#chat_output");
|
||||
o.append(item);
|
||||
o[0].scrollTop = o[0].scrollHeight;
|
||||
return item;
|
||||
}
|
||||
|
||||
function outputState(state) {
|
||||
outputItem([$("<span/>").text(state).addClass(state).addClass("state")])
|
||||
.addClass("state_" + state);
|
||||
}
|
||||
|
||||
function outputUtterance(who, what) {
|
||||
outputItem([$("<span/>").text(who).addClass("nym"),
|
||||
$("<span/>").text(what).addClass("utterance")]).addClass("utterance");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Input control value monitoring
|
||||
|
||||
assertion type jQueryInput(selector, value);
|
||||
|
||||
function spawnInputChangeMonitor() {
|
||||
actor {
|
||||
forever {
|
||||
on asserted Syndicate.observe(jQueryInput($selector, _)) {
|
||||
actor {
|
||||
this.value = $(selector).val();
|
||||
state {
|
||||
assert jQueryInput(selector, this.value);
|
||||
on message jQueryEvent(selector, 'change', $e) {
|
||||
this.value = e.target.value;
|
||||
}
|
||||
} until {
|
||||
case retracted Syndicate.observe(jQueryInput(selector, _));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Main
|
||||
|
||||
$(document).ready(function () {
|
||||
ground dataspace G {
|
||||
Syndicate.JQuery.spawnJQueryDriver();
|
||||
Syndicate.DOM.spawnDOMDriver();
|
||||
Syndicate.WakeDetector.spawnWakeDetector();
|
||||
spawnBrokerClientDriver();
|
||||
spawnInputChangeMonitor();
|
||||
spawnChatApp();
|
||||
}
|
||||
|
||||
// G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
// $("#ds-state").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
// });
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
h1 {
|
||||
background: lightgrey;
|
||||
}
|
||||
|
||||
body > section {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
body > section > section {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
section#messages {
|
||||
flex-grow: 3;
|
||||
}
|
||||
|
||||
section#active_users {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
form#chat_form {
|
||||
flex: 1 100%;
|
||||
}
|
||||
|
||||
span.timestamp {
|
||||
color: #d0d0d0;
|
||||
}
|
||||
|
||||
span.timestamp:after {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
.utterance span.nym:after {
|
||||
content: ": ";
|
||||
}
|
||||
|
||||
span.arrived:after {
|
||||
content: " arrived";
|
||||
}
|
||||
|
||||
span.departed:after {
|
||||
content: " departed";
|
||||
}
|
||||
|
||||
div.notification {
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
|
||||
span.state.connected, span.arrived {
|
||||
color: #00c000;
|
||||
}
|
||||
|
||||
span.state.disconnected, span.departed {
|
||||
color: #c00000;
|
||||
}
|
||||
|
||||
span.state.crashed {
|
||||
color: white;
|
||||
background: red;
|
||||
}
|
||||
|
||||
span.state.crashed:after {
|
||||
content: "; please reload the page";
|
||||
}
|
||||
|
||||
div.state_disconnected {
|
||||
background-color: #ffeeee;
|
||||
}
|
||||
|
||||
div.state_connected {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
#chat_output {
|
||||
height: 15em;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#chat_input {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.nym {
|
||||
color: #00c000;
|
||||
}
|
||||
|
||||
.nym_status:before {
|
||||
content: " (";
|
||||
}
|
||||
|
||||
.nym_status:after {
|
||||
content: ")";
|
||||
}
|
||||
|
||||
.nym_status {
|
||||
font-size: smaller;
|
||||
}
|
|
@ -51,9 +51,9 @@ $(document).ready(function () {
|
|||
});
|
||||
});
|
||||
|
||||
G.dataspace.onStateChange = function (mux, patch) {
|
||||
G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
$("#spy-holder").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
});
|
||||
|
||||
G.startStepping();
|
||||
});
|
||||
|
|
|
@ -192,7 +192,7 @@ $(document).ready(function () {
|
|||
spawnChaosMonkey();
|
||||
}
|
||||
|
||||
G.dataspace.onStateChange = function (mux, patch) {
|
||||
G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
$("#ds-state").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@ $(document).ready(function () {
|
|||
handleEvent: function (e) {
|
||||
if (e.type === 'message'
|
||||
&& Syndicate.JQuery.jQueryEvent.isClassOf(e.message)
|
||||
&& e.message.selector === '#clicker')
|
||||
&& e.message[0] === '#clicker')
|
||||
{
|
||||
var r = $('#result');
|
||||
r.html(Number(r.html()) + 1);
|
||||
|
@ -27,8 +27,8 @@ $(document).ready(function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
G.dataspace.onStateChange = function (mux, patch) {
|
||||
G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
$("#spy-holder").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
});
|
||||
G.startStepping();
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
var beep = Syndicate.Struct.makeStructureConstructor('beep', ['counter']);
|
||||
var beep = Syndicate.Struct.makeConstructor('beep', ['counter']);
|
||||
|
||||
var G;
|
||||
$(document).ready(function () {
|
||||
|
@ -26,7 +26,7 @@ $(document).ready(function () {
|
|||
boot: function () { return sub(beep.pattern); },
|
||||
handleEvent: function (e) {
|
||||
if (e.type === 'message') {
|
||||
console.log("beep!", e.message.counter);
|
||||
console.log("beep!", e.message[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -163,7 +163,7 @@ $(document).ready(function () {
|
|||
spawnSearch();
|
||||
}
|
||||
|
||||
G.dataspace.onStateChange = function (mux, patch) {
|
||||
G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
$("#spy-holder").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,9 +8,9 @@ var __ = Syndicate.__;
|
|||
var _$ = Syndicate._$;
|
||||
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
var fieldContents = Syndicate.Struct.makeStructureConstructor('fieldContents', ['text', 'pos']);
|
||||
var highlight = Syndicate.Struct.makeStructureConstructor('highlight', ['state']);
|
||||
var fieldCommand = Syndicate.Struct.makeStructureConstructor('fieldCommand', ['detail']);
|
||||
var fieldContents = Syndicate.Struct.makeConstructor('fieldContents', ['text', 'pos']);
|
||||
var highlight = Syndicate.Struct.makeConstructor('highlight', ['state']);
|
||||
var fieldCommand = Syndicate.Struct.makeConstructor('fieldCommand', ['detail']);
|
||||
|
||||
function escapeText(text) {
|
||||
text = text.replace(/&/g, '&');
|
||||
|
@ -47,7 +47,7 @@ function spawnGui() {
|
|||
var self = this;
|
||||
switch (e.type) {
|
||||
case "message":
|
||||
var event = e.message.eventValue;
|
||||
var event = e.message[2];
|
||||
var keycode = event.keyCode;
|
||||
var character = String.fromCharCode(event.charCode);
|
||||
if (keycode === 37 /* left */) {
|
||||
|
@ -105,7 +105,7 @@ function spawnModel() {
|
|||
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && fieldCommand.isClassOf(e.message)) {
|
||||
var command = e.message.detail;
|
||||
var command = e.message[0];
|
||||
if (command === "cursorLeft") {
|
||||
this.cursorPos--;
|
||||
if (this.cursorPos < 0)
|
||||
|
@ -203,9 +203,9 @@ $(document).ready(function () {
|
|||
spawnSearch();
|
||||
});
|
||||
|
||||
G.dataspace.onStateChange = function (mux, patch) {
|
||||
G.dataspace.setOnStateChange(function (mux, patch) {
|
||||
$("#spy-holder").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
});
|
||||
|
||||
G.startStepping();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue