diff --git a/examples/chat-raw/index.html b/examples/chat-raw/index.html new file mode 100644 index 0000000..b0a816f --- /dev/null +++ b/examples/chat-raw/index.html @@ -0,0 +1,67 @@ + + + + JS Marketplace: Chat Example + + + + + + + + + +
+
+
+
+
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+
+
+

Messages

+
+
+
+

Active Users

+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/examples/chat-raw/index.js b/examples/chat-raw/index.js new file mode 100644 index 0000000..997ff1c --- /dev/null +++ b/examples/chat-raw/index.js @@ -0,0 +1,162 @@ +var Route = Minimart.Route; +var World = Minimart.World; +var sub = Minimart.sub; +var pub = Minimart.pub; +var __ = Minimart.__; +var _$ = Minimart._$; + +function chatEvent(nym, status, utterance, stamp) { + return ["chatEvent", nym, status, utterance, stamp || +(new Date())]; +} +function chatEventNym(c) { return c[1]; } +function chatEventStatus(c) { return c[2]; } +function chatEventUtterance(c) { return c[3]; } +function chatEventStamp(c) { return c[4]; } + +function outputItem(item) { + var stamp = $("").text((new Date()).toGMTString()).addClass("timestamp"); + var item = $("
").append([stamp].concat(item)); + var o = $("#chat_output"); + o.append(item); + o[0].scrollTop = o[0].scrollHeight; + return item; +} + +function updateNymList(g) { + var statuses = {}; + var nymProj = ["broker", 0, ["chatEvent", _$, _$, __, __]]; + var matchedNyms = Route.matcherKeys(g.project(Route.compileProjection(nymProj), true, 0, 0)); + for (var i = 0; i < matchedNyms.length; i++) { + statuses[matchedNyms[i][0]] = matchedNyms[i][1]; + } + var nyms = []; + for (var nym in statuses) { nyms.push(nym); } + nyms.sort(); + + var container = $("#nymlist"); + container[0].innerHTML = ""; // remove all children + for (var i = 0; i < nyms.length; i++) { + var n = $("").text(nyms[i]).addClass("nym"); + var s = statuses[nyms[i]]; + if (s) { + container.append($("
").append([n, $("").text(s).addClass("nym_status")])); + } else { + container.append($("
").append(n)); + } + } +} + +function outputState(state) { + outputItem([$("").text(state).addClass(state).addClass("state")]) + .addClass("state_" + state); +} + +function outputUtterance(who, what) { + outputItem([$("").text(who).addClass("nym"), + $("").text(what).addClass("utterance")]).addClass("utterance"); +} + +var G; +$(document).ready(function () { + $("#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)); } + + G = new Minimart.Ground(function () { + console.log('starting ground boot'); + // World.spawn(new Spy()); + Minimart.JQuery.spawnJQueryDriver(); + Minimart.DOM.spawnDOMDriver(); + Minimart.RoutingTableWidget.spawnRoutingTableWidget("#spy-holder", "spy"); + + World.spawn(new Minimart.WakeDetector()); + var wsconn = new Minimart.WebSocket.WebSocketConnection("broker", $("#wsurl").val(), true); + World.spawn(wsconn); + World.spawn({ + // Monitor connection, notifying connectivity changes + state: "crashed", // start with this to avoid spurious initial message print + boot: function () { + World.updateRoutes([sub(["broker_state", __], 0, 1)]); + }, + handleEvent: function (e) { + if (e.type === "routes") { + var states = + Route.matcherKeys(e.gestalt.project(Route.compileProjection([__, _$]), + true, 0, 0)); + var newState = states.length > 0 ? states[0][0] : "crashed"; + if (this.state != newState) { + outputState(newState); + this.state = newState; + } + } + } + }); + World.spawn({ + // Actual chat functionality + boot: function () { + World.updateRoutes(this.subscriptions()); + }, + nym: function () { return $("#nym").val(); }, + currentStatus: function () { return $("#status").val(); }, + subscriptions: function () { + return [sub("wake"), + sub(["jQuery", "#send_chat", "click", __]), + sub(["jQuery", "#nym", "change", __]), + sub(["jQuery", "#status", "change", __]), + sub(["jQuery", "#wsurl", "change", __]), + pub(["broker", 0, chatEvent(this.nym(), this.currentStatus(), __, __)]), + sub(["broker", 0, chatEvent(__, __, __, __)], 0, 1)]; + }, + handleEvent: function (e) { + var self = this; + switch (e.type) { + case "routes": + updateNymList(e.gestalt); + break; + case "message": + if (e.message === "wake") { + wsconn.forceclose(); + return; + } + switch (e.message[0]) { + case "jQuery": + switch (e.message[1]) { + case "#send_chat": + var inp = $("#chat_input"); + var utterance = inp.val(); + inp.val(""); + if (utterance) { + World.send(["broker", 0, chatEvent(this.nym(), + this.currentStatus(), + utterance)]); + } + break; + case "#nym": + case "#status": + World.updateRoutes(this.subscriptions()); + break; + case "#wsurl": + wsconn.forceclose(); + wsconn.wsurl = $("#wsurl").val(); + break; + default: + console.log("Got jquery event from as-yet-unhandled subscription", + e.message[2], e.message[3]); + } + break; + case "broker": + if (e.message[2][0] === "chatEvent") { + outputUtterance(chatEventNym(e.message[2]), + chatEventUtterance(e.message[2])); + } + break; + default: + break; + } + break; + } + } + }); + }); + G.startStepping(); +}); diff --git a/examples/chat-raw/style.css b/examples/chat-raw/style.css new file mode 100644 index 0000000..a19cf9d --- /dev/null +++ b/examples/chat-raw/style.css @@ -0,0 +1,73 @@ +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; +} \ No newline at end of file diff --git a/examples/chat/app-resources/Info.plist b/examples/chat/app-resources/Info.plist deleted file mode 100644 index 3e42d52..0000000 --- a/examples/chat/app-resources/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - boot.sh - CFBundleIconFile - app.icns - CFBundleIdentifier - com.leastfixedpoint.js-marketplace.chat-demo - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - chat-demo - CFBundlePackageType - APPL - CFBundleShortVersionString - chat-demo 0.0.0 - CFBundleSignature - ???? - CFBundleVersion - 0.0.0 - LSMinimumSystemVersion - 10.6 - - diff --git a/examples/chat/app-resources/app.icns b/examples/chat/app-resources/app.icns deleted file mode 100644 index 4d50fa4..0000000 Binary files a/examples/chat/app-resources/app.icns and /dev/null differ diff --git a/examples/chat/app-resources/boot.sh b/examples/chat/app-resources/boot.sh deleted file mode 100644 index 1f69d48..0000000 --- a/examples/chat/app-resources/boot.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -cd "$(dirname "$0")"/../Resources -open examples/chat/index.html diff --git a/examples/chat/index.js b/examples/chat/index.js index 997ff1c..bfa0e2f 100644 --- a/examples/chat/index.js +++ b/examples/chat/index.js @@ -1,5 +1,6 @@ var Route = Minimart.Route; var World = Minimart.World; +var Actor = Minimart.Actor; var sub = Minimart.sub; var pub = Minimart.pub; var __ = Minimart.__; @@ -8,10 +9,6 @@ var _$ = Minimart._$; function chatEvent(nym, status, utterance, stamp) { return ["chatEvent", nym, status, utterance, stamp || +(new Date())]; } -function chatEventNym(c) { return c[1]; } -function chatEventStatus(c) { return c[2]; } -function chatEventUtterance(c) { return c[3]; } -function chatEventStamp(c) { return c[4]; } function outputItem(item) { var stamp = $("").text((new Date()).toGMTString()).addClass("timestamp"); @@ -22,12 +19,10 @@ function outputItem(item) { return item; } -function updateNymList(g) { +function updateNymList(allStatuses) { var statuses = {}; - var nymProj = ["broker", 0, ["chatEvent", _$, _$, __, __]]; - var matchedNyms = Route.matcherKeys(g.project(Route.compileProjection(nymProj), true, 0, 0)); - for (var i = 0; i < matchedNyms.length; i++) { - statuses[matchedNyms[i][0]] = matchedNyms[i][1]; + for (var i = 0; i < allStatuses.length; i++) { + statuses[allStatuses[i].nym] = allStatuses[i].status; } var nyms = []; for (var nym in statuses) { nyms.push(nym); } @@ -72,91 +67,71 @@ $(document).ready(function () { World.spawn(new Minimart.WakeDetector()); var wsconn = new Minimart.WebSocket.WebSocketConnection("broker", $("#wsurl").val(), true); World.spawn(wsconn); - World.spawn({ + World.spawn(new Actor(function () { // Monitor connection, notifying connectivity changes - state: "crashed", // start with this to avoid spurious initial message print - boot: function () { - World.updateRoutes([sub(["broker_state", __], 0, 1)]); - }, - handleEvent: function (e) { - if (e.type === "routes") { - var states = - Route.matcherKeys(e.gestalt.project(Route.compileProjection([__, _$]), - true, 0, 0)); - var newState = states.length > 0 ? states[0][0] : "crashed"; + this.state = "crashed"; // start with this to avoid spurious initial message print + + Actor.observeAdvertisers( + function () { return ["broker_state", _$("newState")]; }, + { name: "states" }, + function () { + var newState = this.states.length > 0 ? this.states[0].newState : "crashed"; if (this.state != newState) { outputState(newState); this.state = newState; } - } - } - }); - World.spawn({ + }); + })); + World.spawn(new Actor(function () { // Actual chat functionality - boot: function () { - World.updateRoutes(this.subscriptions()); - }, - nym: function () { return $("#nym").val(); }, - currentStatus: function () { return $("#status").val(); }, - subscriptions: function () { - return [sub("wake"), - sub(["jQuery", "#send_chat", "click", __]), - sub(["jQuery", "#nym", "change", __]), - sub(["jQuery", "#status", "change", __]), - sub(["jQuery", "#wsurl", "change", __]), - pub(["broker", 0, chatEvent(this.nym(), this.currentStatus(), __, __)]), - sub(["broker", 0, chatEvent(__, __, __, __)], 0, 1)]; - }, - handleEvent: function (e) { - var self = this; - switch (e.type) { - case "routes": - updateNymList(e.gestalt); - break; - case "message": - if (e.message === "wake") { - wsconn.forceclose(); - return; + this.nym = function () { return $("#nym").val(); }; + this.currentStatus = function () { return $("#status").val(); }; + + Actor.subscribe( + function () { return "wake"; }, + function () { wsconn.forceclose(); }); + + Actor.advertise( + function () { return ["broker", 0, + chatEvent(this.nym(), this.currentStatus(), __, __)]; }); + Actor.observeAdvertisers( + function () { return ["broker", 0, + chatEvent(_$("nym"), _$("status"), __, __)]; }, + { name: "allStatuses" }, + function () { updateNymList(this.allStatuses); }); + + Actor.subscribe( + function () { return ["jQuery", "#send_chat", "click", __]; }, + function () { + var inp = $("#chat_input"); + var utterance = inp.val(); + inp.val(""); + if (utterance) { + World.send(["broker", 0, chatEvent(this.nym(), + this.currentStatus(), + utterance)]); } - switch (e.message[0]) { - case "jQuery": - switch (e.message[1]) { - case "#send_chat": - var inp = $("#chat_input"); - var utterance = inp.val(); - inp.val(""); - if (utterance) { - World.send(["broker", 0, chatEvent(this.nym(), - this.currentStatus(), - utterance)]); - } - break; - case "#nym": - case "#status": - World.updateRoutes(this.subscriptions()); - break; - case "#wsurl": - wsconn.forceclose(); - wsconn.wsurl = $("#wsurl").val(); - break; - default: - console.log("Got jquery event from as-yet-unhandled subscription", - e.message[2], e.message[3]); - } - break; - case "broker": - if (e.message[2][0] === "chatEvent") { - outputUtterance(chatEventNym(e.message[2]), - chatEventUtterance(e.message[2])); - } - break; - default: - break; - } - break; - } - } - }); + }); + + Actor.subscribe( + function () { return ["jQuery", "#nym", "change", __]; }, + function () { this.updateRoutes(); }); + + Actor.subscribe( + function () { return ["jQuery", "#status", "change", __]; }, + function () { this.updateRoutes(); }); + + Actor.subscribe( + function () { return ["jQuery", "#wsurl", "change", __]; }, + function () { + wsconn.forceclose(); + wsconn.wsurl = $("#wsurl").val(); + }); + + Actor.subscribe( + function () { return ["broker", 0, chatEvent(_$("who"), __, _$("what"), __)]; }, + function (who, what) { outputUtterance(who, what); }); + })); }); G.startStepping(); });