Update chat example to Actor; preserve non-Actor version; remove

currently-useless OSX app resources
This commit is contained in:
Tony Garnock-Jones 2014-07-25 16:53:17 -07:00
parent 55c9fa1d49
commit 76044b539e
7 changed files with 364 additions and 118 deletions

View File

@ -0,0 +1,67 @@
<!doctype html>
<html>
<head>
<title>JS Marketplace: Chat Example</title>
<meta charset="utf-8">
<link href="../../third-party/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../third-party/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
<script src="../../third-party/jquery-2.0.3.min.js"></script>
<script src="../../dist/minimart.js"></script>
<script src="index.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<form class="form-horizontal" name="nym_form">
<fieldset>
<div class="control-group">
<label class="control-label" for="wsurl">Server:</label>
<div class="controls">
<input type="text" id="wsurl" name="wsurl" value="ws://localhost:8000/">
</div>
<label class="control-label" for="nym">Nym:</label>
<div class="controls">
<input type="text" id="nym" name="nym" value="">
</div>
<label class="control-label" for="status">Status:</label>
<div class="controls">
<input type="text" id="status" name="status" value="">
</div>
</div>
</fieldset>
</form>
</div>
</div>
<div class="row-fluid">
<div class="span9">
<h2>Messages</h2>
<div id="chat_output"></div>
</div>
<div class="span3">
<h2>Active Users</h2>
<div id="nymlist"></div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<form class="form-horizontal" name="chat_form">
<fieldset>
<div class="control-group">
<div class="controls">
<input type="text" id="chat_input" name="chat_input" value="" autocomplete="off">
<button id="send_chat">Send</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
<div class="row-fluid">
<div class="span12" id="spy-holder">
</div>
</div>
</div>
</body>
</html>

162
examples/chat-raw/index.js Normal file
View File

@ -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 = $("<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 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 = $("<span/>").text(nyms[i]).addClass("nym");
var s = statuses[nyms[i]];
if (s) {
container.append($("<div/>").append([n, $("<span/>").text(s).addClass("nym_status")]));
} else {
container.append($("<div/>").append(n));
}
}
}
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");
}
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();
});

View File

@ -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;
}

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>boot.sh</string>
<key>CFBundleIconFile</key>
<string>app.icns</string>
<key>CFBundleIdentifier</key>
<string>com.leastfixedpoint.js-marketplace.chat-demo</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>chat-demo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>chat-demo 0.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
</dict>
</plist>

Binary file not shown.

View File

@ -1,3 +0,0 @@
#!/bin/bash
cd "$(dirname "$0")"/../Resources
open examples/chat/index.html

View File

@ -1,5 +1,6 @@
var Route = Minimart.Route; var Route = Minimart.Route;
var World = Minimart.World; var World = Minimart.World;
var Actor = Minimart.Actor;
var sub = Minimart.sub; var sub = Minimart.sub;
var pub = Minimart.pub; var pub = Minimart.pub;
var __ = Minimart.__; var __ = Minimart.__;
@ -8,10 +9,6 @@ var _$ = Minimart._$;
function chatEvent(nym, status, utterance, stamp) { function chatEvent(nym, status, utterance, stamp) {
return ["chatEvent", nym, status, utterance, stamp || +(new Date())]; 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) { function outputItem(item) {
var stamp = $("<span/>").text((new Date()).toGMTString()).addClass("timestamp"); var stamp = $("<span/>").text((new Date()).toGMTString()).addClass("timestamp");
@ -22,12 +19,10 @@ function outputItem(item) {
return item; return item;
} }
function updateNymList(g) { function updateNymList(allStatuses) {
var statuses = {}; var statuses = {};
var nymProj = ["broker", 0, ["chatEvent", _$, _$, __, __]]; for (var i = 0; i < allStatuses.length; i++) {
var matchedNyms = Route.matcherKeys(g.project(Route.compileProjection(nymProj), true, 0, 0)); statuses[allStatuses[i].nym] = allStatuses[i].status;
for (var i = 0; i < matchedNyms.length; i++) {
statuses[matchedNyms[i][0]] = matchedNyms[i][1];
} }
var nyms = []; var nyms = [];
for (var nym in statuses) { nyms.push(nym); } for (var nym in statuses) { nyms.push(nym); }
@ -72,91 +67,71 @@ $(document).ready(function () {
World.spawn(new Minimart.WakeDetector()); World.spawn(new Minimart.WakeDetector());
var wsconn = new Minimart.WebSocket.WebSocketConnection("broker", $("#wsurl").val(), true); var wsconn = new Minimart.WebSocket.WebSocketConnection("broker", $("#wsurl").val(), true);
World.spawn(wsconn); World.spawn(wsconn);
World.spawn({ World.spawn(new Actor(function () {
// Monitor connection, notifying connectivity changes // Monitor connection, notifying connectivity changes
state: "crashed", // start with this to avoid spurious initial message print this.state = "crashed"; // start with this to avoid spurious initial message print
boot: function () {
World.updateRoutes([sub(["broker_state", __], 0, 1)]); Actor.observeAdvertisers(
}, function () { return ["broker_state", _$("newState")]; },
handleEvent: function (e) { { name: "states" },
if (e.type === "routes") { function () {
var states = var newState = this.states.length > 0 ? this.states[0].newState : "crashed";
Route.matcherKeys(e.gestalt.project(Route.compileProjection([__, _$]),
true, 0, 0));
var newState = states.length > 0 ? states[0][0] : "crashed";
if (this.state != newState) { if (this.state != newState) {
outputState(newState); outputState(newState);
this.state = newState; this.state = newState;
} }
} });
} }));
}); World.spawn(new Actor(function () {
World.spawn({
// Actual chat functionality // Actual chat functionality
boot: function () { this.nym = function () { return $("#nym").val(); };
World.updateRoutes(this.subscriptions()); this.currentStatus = function () { return $("#status").val(); };
},
nym: function () { return $("#nym").val(); }, Actor.subscribe(
currentStatus: function () { return $("#status").val(); }, function () { return "wake"; },
subscriptions: function () { function () { wsconn.forceclose(); });
return [sub("wake"),
sub(["jQuery", "#send_chat", "click", __]), Actor.advertise(
sub(["jQuery", "#nym", "change", __]), function () { return ["broker", 0,
sub(["jQuery", "#status", "change", __]), chatEvent(this.nym(), this.currentStatus(), __, __)]; });
sub(["jQuery", "#wsurl", "change", __]), Actor.observeAdvertisers(
pub(["broker", 0, chatEvent(this.nym(), this.currentStatus(), __, __)]), function () { return ["broker", 0,
sub(["broker", 0, chatEvent(__, __, __, __)], 0, 1)]; chatEvent(_$("nym"), _$("status"), __, __)]; },
}, { name: "allStatuses" },
handleEvent: function (e) { function () { updateNymList(this.allStatuses); });
var self = this;
switch (e.type) { Actor.subscribe(
case "routes": function () { return ["jQuery", "#send_chat", "click", __]; },
updateNymList(e.gestalt); function () {
break; var inp = $("#chat_input");
case "message": var utterance = inp.val();
if (e.message === "wake") { inp.val("");
wsconn.forceclose(); if (utterance) {
return; World.send(["broker", 0, chatEvent(this.nym(),
this.currentStatus(),
utterance)]);
} }
switch (e.message[0]) { });
case "jQuery":
switch (e.message[1]) { Actor.subscribe(
case "#send_chat": function () { return ["jQuery", "#nym", "change", __]; },
var inp = $("#chat_input"); function () { this.updateRoutes(); });
var utterance = inp.val();
inp.val(""); Actor.subscribe(
if (utterance) { function () { return ["jQuery", "#status", "change", __]; },
World.send(["broker", 0, chatEvent(this.nym(), function () { this.updateRoutes(); });
this.currentStatus(),
utterance)]); Actor.subscribe(
} function () { return ["jQuery", "#wsurl", "change", __]; },
break; function () {
case "#nym": wsconn.forceclose();
case "#status": wsconn.wsurl = $("#wsurl").val();
World.updateRoutes(this.subscriptions()); });
break;
case "#wsurl": Actor.subscribe(
wsconn.forceclose(); function () { return ["broker", 0, chatEvent(_$("who"), __, _$("what"), __)]; },
wsconn.wsurl = $("#wsurl").val(); function (who, what) { outputUtterance(who, what); });
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(); G.startStepping();
}); });