DOM driver.
This commit is contained in:
parent
a0670ec3a3
commit
3489b5fab7
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Syndicate: DOM Example</title>
|
||||
<meta charset="utf-8">
|
||||
<script src="../../third-party/jquery-2.2.0.min.js"></script>
|
||||
<script src="../../dist/syndicate.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DOM example</h1>
|
||||
<div id="counter-holder"></div>
|
||||
<div id="clicker-holder"></div>
|
||||
<pre id="spy-holder"></pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
var G;
|
||||
$(document).ready(function () {
|
||||
var Network = Syndicate.Network;
|
||||
var sub = Syndicate.sub;
|
||||
var assert = Syndicate.assert;
|
||||
var retract = Syndicate.retract;
|
||||
var __ = Syndicate.__;
|
||||
var _$ = Syndicate._$;
|
||||
|
||||
G = new Syndicate.Ground(function () {
|
||||
console.log('starting ground boot');
|
||||
|
||||
Syndicate.DOM.spawnDOMDriver();
|
||||
|
||||
Network.spawn({
|
||||
boot: function () {
|
||||
return assert(["DOM", "#clicker-holder", "clicker",
|
||||
["button", ["span", [["style", "font-style: italic"]], "Click me!"]]])
|
||||
.andThen(sub(["jQuery", "button.clicker", "click", __]));
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message[0] === "jQuery") {
|
||||
Network.send("bump_count");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Network.spawn({
|
||||
counter: 0,
|
||||
boot: function () {
|
||||
this.updateState();
|
||||
return sub("bump_count");
|
||||
},
|
||||
updateState: function () {
|
||||
Network.stateChange(retract(["DOM", __, __, __])
|
||||
.andThen(assert(["DOM", "#counter-holder", "counter",
|
||||
["div",
|
||||
["p", "The current count is: ", this.counter]]])));
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message === "bump_count") {
|
||||
this.counter++;
|
||||
this.updateState();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
G.network.onStateChange = function (mux, patch) {
|
||||
$("#spy-holder").text(Syndicate.prettyTrie(mux.routingTable));
|
||||
};
|
||||
|
||||
G.startStepping();
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
// DOM fragment display driver
|
||||
var Syndicate = require("./syndicate.js");
|
||||
var Patch = require("./patch.js");
|
||||
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
|
||||
var Network = Syndicate.Network;
|
||||
var __ = Syndicate.__;
|
||||
var _$ = Syndicate._$;
|
||||
|
||||
function spawnDOMDriver(domWrapFunction, jQueryWrapFunction) {
|
||||
domWrapFunction = domWrapFunction || defaultWrapFunction;
|
||||
var spec = domWrapFunction(_$('selector'), _$('fragmentClass'), _$('fragmentSpec'));
|
||||
Network.spawn(
|
||||
new DemandMatcher(spec,
|
||||
Patch.advertise(spec),
|
||||
{
|
||||
onDemandIncrease: function (c) {
|
||||
Network.spawn(new DOMFragment(c.selector,
|
||||
c.fragmentClass,
|
||||
c.fragmentSpec,
|
||||
domWrapFunction,
|
||||
jQueryWrapFunction));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function defaultWrapFunction(selector, fragmentClass, fragmentSpec) {
|
||||
return ["DOM", selector, fragmentClass, fragmentSpec];
|
||||
}
|
||||
|
||||
function DOMFragment(selector, fragmentClass, fragmentSpec, domWrapFunction, jQueryWrapFunction) {
|
||||
this.selector = selector;
|
||||
this.fragmentClass = fragmentClass;
|
||||
this.fragmentSpec = fragmentSpec;
|
||||
this.domWrapFunction = domWrapFunction;
|
||||
this.jQueryWrapFunction = jQueryWrapFunction;
|
||||
this.nodes = this.buildNodes();
|
||||
}
|
||||
|
||||
DOMFragment.prototype.boot = function () {
|
||||
var self = this;
|
||||
var specification = self.domWrapFunction(self.selector, self.fragmentClass, self.fragmentSpec);
|
||||
|
||||
Network.spawn(new Network(function () {
|
||||
Syndicate.JQuery.spawnJQueryDriver(self.selector+" > ."+self.fragmentClass,
|
||||
1,
|
||||
self.jQueryWrapFunction);
|
||||
Network.spawn({
|
||||
boot: function () {
|
||||
return Patch.sub(Patch.advertise(specification), 1);
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "stateChange" && e.patch.hasRemoved()) {
|
||||
Network.exitNetwork();
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
return Patch.sub(specification).andThen(Patch.pub(specification));
|
||||
};
|
||||
|
||||
DOMFragment.prototype.handleEvent = function (e) {
|
||||
if (e.type === "stateChange" && e.patch.hasRemoved()) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var n = this.nodes[i];
|
||||
n.parentNode.removeChild(n);
|
||||
}
|
||||
Network.exit();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function isAttributes(x) {
|
||||
return Array.isArray(x) && ((x.length === 0) || Array.isArray(x[0]));
|
||||
}
|
||||
|
||||
DOMFragment.prototype.interpretSpec = function (spec) {
|
||||
// Fragment specs are roughly JSON-equivalents of SXML.
|
||||
// spec ::== ["tag", [["attr", "value"], ...], spec, spec, ...]
|
||||
// | ["tag", spec, spec, ...]
|
||||
// | "cdata"
|
||||
if (typeof(spec) === "string" || typeof(spec) === "number") {
|
||||
return document.createTextNode(spec);
|
||||
} else if ($.isArray(spec)) {
|
||||
var tagName = spec[0];
|
||||
var hasAttrs = isAttributes(spec[1]);
|
||||
var attrs = hasAttrs ? spec[1] : {};
|
||||
var kidIndex = hasAttrs ? 2 : 1;
|
||||
|
||||
// Wow! Such XSS! Many hacks! So vulnerability! Amaze!
|
||||
var n = document.createElement(tagName);
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
n.setAttribute(attrs[i][0], attrs[i][1]);
|
||||
}
|
||||
for (var i = kidIndex; i < spec.length; i++) {
|
||||
n.appendChild(this.interpretSpec(spec[i]));
|
||||
}
|
||||
return n;
|
||||
} else {
|
||||
throw new Error("Ill-formed DOM specification");
|
||||
}
|
||||
};
|
||||
|
||||
DOMFragment.prototype.buildNodes = function () {
|
||||
var self = this;
|
||||
var nodes = [];
|
||||
$(self.selector).each(function (index, domNode) {
|
||||
var n = self.interpretSpec(self.fragmentSpec.toJS());
|
||||
n.classList.add(self.fragmentClass);
|
||||
domNode.appendChild(n);
|
||||
nodes.push(n);
|
||||
});
|
||||
return nodes;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module.exports.spawnDOMDriver = spawnDOMDriver;
|
||||
module.exports.defaultWrapFunction = defaultWrapFunction;
|
|
@ -20,7 +20,7 @@ copyKeys(['__', '_$', '$Capture', '$Special',
|
|||
module.exports.DemandMatcher = require('./demand-matcher.js').DemandMatcher;
|
||||
module.exports.Seal = require('./seal.js').Seal;
|
||||
|
||||
// module.exports.DOM = require("./dom-driver.js");
|
||||
module.exports.DOM = require("./dom-driver.js");
|
||||
module.exports.JQuery = require("./jquery-driver.js");
|
||||
// module.exports.RoutingTableWidget = require("./routing-table-widget.js");
|
||||
// module.exports.WebSocket = require("./websocket-driver.js");
|
||||
|
|
Loading…
Reference in New Issue