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); + } + } + } + }); + +}