diff --git a/examples/dom/index.html b/examples/dom/index.html
index 23754b1..080f9a0 100644
--- a/examples/dom/index.html
+++ b/examples/dom/index.html
@@ -13,6 +13,10 @@
+
+
+
+
diff --git a/examples/dom/index.js b/examples/dom/index.js
index 7db09fa..6ce479c 100644
--- a/examples/dom/index.js
+++ b/examples/dom/index.js
@@ -1,76 +1,10 @@
-function count_uniq(xs) {
- var r = [];
- if (xs.length === 0) return [];
- var last = xs[0];
- var count = 1;
- function fin() {
- r.push([count, last]);
- }
- for (var i = 1; i < xs.length; i++) {
- if (xs[i] === last) {
- count++;
- } else {
- fin();
- last = xs[i];
- count = 1;
- }
- }
- fin();
- return r;
-}
-
var G;
$(document).ready(function () {
G = new Ground(function () {
console.log('starting ground boot');
// World.spawn(new Spy("GROUND", true));
spawnDOMDriver();
-
- World.spawn({
- boot: function () { this.updateState(); },
- state: [],
- nextState: [],
- timer: false,
- digestRoutes: function (rs) {
- var s = [];
- for (var i = 0; i < rs.length; i++) {
- var p = rs[i].pattern;
- if (p[0] !== "DOM" || p[1] !== "#spy-holder" || p[2] !== "spy") {
- s.push(JSON.stringify([p,
- rs[i].isSubscription ? "sub" : "pub",
- rs[i].level]));
- }
- }
- s.sort();
- s = count_uniq(s);
- return s;
- },
- updateState: function () {
- var elts = ["ul"];
- for (var i = 0; i < this.state.length; i++) {
- var r = this.state[i];
- elts.push(["li", r[0], " × ", r[1]]);
- }
- World.updateRoutes([sub(__, 0, Infinity),
- pub(__, 0, Infinity),
- pub(["DOM", "#spy-holder", "spy", elts])]);
- },
- handleEvent: function (e) {
- if (e.type === "routes") {
- this.nextState = this.digestRoutes(e.routes);
- if (!this.timer) {
- var self = this;
- this.timer = setTimeout(World.wrap(function () {
- if (JSON.stringify(self.nextState) !== JSON.stringify(self.state)) {
- self.state = self.nextState;
- self.updateState();
- }
- self.timer = false;
- }), 50);
- }
- }
- }
- });
+ spawnRoutingTableWidget("#spy-holder", "spy");
World.spawn({
handleEvent: function (e) {
diff --git a/routing-table-widget.css b/routing-table-widget.css
new file mode 100644
index 0000000..2c1851b
--- /dev/null
+++ b/routing-table-widget.css
@@ -0,0 +1,49 @@
+.routing-table li { list-style-type: none; }
+
+.routing-table .sub .pattern { background-color: lightblue; }
+.routing-table .sub .level { background-color: lightblue; }
+.routing-table .pub .pattern { background-color: lightgreen; }
+.routing-table .pub .level { background-color: lightgreen; }
+
+.routing-table .route {
+ display: inline-block;
+ height: 2em;
+}
+
+.routing-table .route .level { font-style: italic; line-height: 1em; padding: 0 0.5em; }
+.routing-table .route .polarity { display: none; }
+.routing-table .route .pattern { padding-right: 0.5em; }
+
+.routing-table .route:before {
+ content: " ";
+ float: left;
+}
+
+.routing-table .pub:before {
+ border-right: 0.6em solid lightgreen;
+ border-top: 0.75em solid transparent;
+ border-bottom: 0.75em solid transparent;
+}
+
+.routing-table .sub:before {
+ border-left: 0.6em solid transparent;
+ border-top: 0.75em solid lightblue;
+ border-bottom: 0.75em solid lightblue;
+}
+
+.routing-table .route:after {
+ content: " ";
+ float: right;
+}
+
+.routing-table .pub:after {
+ border-left: 0.6em solid lightgreen;
+ border-top: 0.75em solid transparent;
+ border-bottom: 0.75em solid transparent;
+}
+
+.routing-table .sub:after {
+ border-right: 0.6em solid transparent;
+ border-top: 0.75em solid lightblue;
+ border-bottom: 0.75em solid lightblue;
+}
diff --git a/routing-table-widget.js b/routing-table-widget.js
new file mode 100644
index 0000000..2174e9a
--- /dev/null
+++ b/routing-table-widget.js
@@ -0,0 +1,104 @@
+function spawnRoutingTableWidget(selector, fragmentClass) {
+
+ function sortedBy(xs, f) {
+ var keys = [];
+ var result = [];
+ for (var i = 0; i < xs.length; i++) {
+ keys.push([f(xs[i]), i]);
+ }
+ keys.sort();
+ for (var i = 0; i < xs.length; i++) {
+ result.push(xs[keys[i][1]]);
+ }
+ return result;
+ }
+
+ function count_uniqBy(xs, f) {
+ var r = [];
+ if (xs.length === 0) return [];
+ var last = xs[0];
+ var lastKey = f(xs[0]);
+ var count = 1;
+ function fin() {
+ r.push([count, last]);
+ }
+ for (var i = 1; i < xs.length; i++) {
+ var fi = f(xs[i]);
+ if (fi === lastKey) {
+ count++;
+ } else {
+ fin();
+ last = xs[i];
+ lastKey = fi;
+ count = 1;
+ }
+ }
+ fin();
+ return r;
+ }
+
+ World.spawn({
+ boot: function () { this.updateState(); },
+
+ state: [],
+ nextState: [],
+ timer: false,
+
+ digestRoutes: function (rs) {
+ var s = [];
+ function key(r) { return JSON.stringify([r.pattern, r.level, r.isSubscription]); }
+ for (var i = 0; i < rs.length; i++) {
+ var p = rs[i].pattern;
+ if (p[0] !== "DOM" || p[1] !== selector || p[2] !== fragmentClass) {
+ s.push(rs[i]);
+ }
+ }
+ s = sortedBy(s, key);
+ s = count_uniqBy(s, key);
+ return s;
+ },
+
+ updateState: function () {
+ var elts = ["ul", {"class": "routing-table"}];
+ for (var i = 0; i < this.state.length; i++) {
+ var r = this.state[i];
+ var levelstr;
+ switch (r[1].level) {
+ case 0: levelstr = "participant"; break;
+ case 1: levelstr = "observer"; break;
+ case 2: levelstr = "metaobserver"; break;
+ default: levelstr = "level " + r[1].level; break;
+ }
+ var polarity = r[1].isSubscription ? "sub" : "pub";
+ var pat = JSON.stringify(r[1].pattern).replace(/{"__":"__"}/g, '★');
+ elts.push(["li",
+ ["span", {"class": "repeatcount"}, r[0]],
+ ["span", {"class": "times"}, " × "],
+ ["span", {"class": polarity + " route"},
+ ["span", {"class": "level", "data-level": r[1].level}, levelstr],
+ ["span", {"class": "polarity"}, polarity],
+ ["span", {"class": "pattern"}, pat]]]);
+ }
+ World.updateRoutes([sub(__, 0, Infinity),
+ pub(__, 0, Infinity),
+ pub(["DOM", selector, fragmentClass, elts])]);
+ },
+
+ handleEvent: function (e) {
+ if (e.type === "routes") {
+ this.nextState = this.digestRoutes(e.routes);
+ if (!this.timer) {
+ var self = this;
+ this.timer = setTimeout(World.wrap(function () {
+ if (JSON.stringify(self.nextState) !== JSON.stringify(self.state)) {
+ self.state = self.nextState;
+ self.updateState();
+ }
+ self.timer = false;
+ }), 50);
+ }
+ }
+ }
+ });
+
+}