demand-matcher.js, jquery-driver.js

This commit is contained in:
Tony Garnock-Jones 2016-02-06 06:22:49 -05:00
parent 8c55ada827
commit 9d7dd37a37
5 changed files with 216 additions and 1 deletions

View File

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>Syndicate: jQuery 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>jQuery example</h1>
<button id="clicker">Click me</button>
<div id="result">0</div>
</body>
</html>

28
js/examples/jquery/index.js vendored Normal file
View File

@ -0,0 +1,28 @@
"use strict";
var G;
$(document).ready(function () {
var Network = Syndicate.Network;
var sub = Syndicate.sub;
var __ = Syndicate.__;
var _$ = Syndicate._$;
G = new Syndicate.Ground(function () {
console.log('starting ground boot');
Syndicate.JQuery.spawnJQueryDriver();
Network.spawn({
boot: function () {
return sub(['jQuery', '#clicker', 'click', __]);
},
handleEvent: function (e) {
if (e.type === 'message' && e.message[0] === 'jQuery' && e.message[1] === '#clicker') {
var r = $('#result');
r.html(Number(r.html()) + 1);
}
}
});
});
G.startStepping();
});

80
js/src/demand-matcher.js Normal file
View File

@ -0,0 +1,80 @@
var Immutable = require('immutable');
var Syndicate = require('./syndicate.js');
var Route = require('./route.js');
var Patch = require('./patch.js');
var Util = require('./util.js');
function DemandMatcher(demandSpec, supplySpec, options) {
options = Util.extend({
metaLevel: 0,
onDemandIncrease: function (captures) {
console.error("Syndicate: Unhandled increase in demand", captures);
},
onSupplyDecrease: function (captures) {
console.error("Syndicate: Unhandled decrease in supply", captures);
}
}, options);
this.metaLevel = options.metaLevel;
this.onDemandIncrease = options.onDemandIncrease;
this.onSupplyDecrease = options.onSupplyDecrease;
this.demandSpec = demandSpec;
this.supplySpec = supplySpec;
this.demandPattern = Route.projectionToPattern(demandSpec);
this.supplyPattern = Route.projectionToPattern(supplySpec);
this.demandProjection = Route.compileProjection(demandSpec);
this.supplyProjection = Route.compileProjection(supplySpec);
this.currentDemand = Immutable.Set();
this.currentSupply = Immutable.Set();
}
DemandMatcher.prototype.boot = function () {
return Patch.sub(this.demandPattern, this.metaLevel)
.andThen(Patch.sub(this.supplyPattern, this.metaLevel));
};
DemandMatcher.prototype.handleEvent = function (e) {
if (e.type === "stateChange") {
this.handlePatch(e.patch);
}
};
DemandMatcher.prototype.handlePatch = function (p) {
var self = this;
var addedDemand = Route.trieKeys(Route.project(p.added, self.demandProjection));
var removedDemand = Route.trieKeys(Route.project(p.removed, self.demandProjection));
var addedSupply = Route.trieKeys(Route.project(p.added, self.supplyProjection));
var removedSupply = Route.trieKeys(Route.project(p.removed, self.supplyProjection));
if (addedDemand === null) {
throw new Error("Syndicate: wildcard demand detected:\n" +
self.demandSpec + "\n" +
p.pretty());
}
if (addedSupply === null) {
throw new Error("Syndicate: wildcard supply detected:\n" +
self.supplySpec + "\n" +
p.pretty());
}
self.currentSupply = self.currentSupply.union(addedSupply);
self.currentDemand = self.currentDemand.subtract(removedDemand);
removedSupply.forEach(function (captures) {
if (self.currentDemand.has(captures)) {
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjection));
}
});
addedDemand.forEach(function (captures) {
if (!self.currentSupply.has(captures)) {
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjection));
}
});
self.currentSupply = self.currentSupply.subtract(removedSupply);
self.currentDemand = self.currentDemand.union(addedDemand);
};
///////////////////////////////////////////////////////////////////////////
module.exports.DemandMatcher = DemandMatcher;

90
js/src/jquery-driver.js vendored Normal file
View File

@ -0,0 +1,90 @@
// JQuery event 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 spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
metaLevel = metaLevel || 0;
wrapFunction = wrapFunction || defaultWrapFunction;
Network.spawn(
new DemandMatcher(Patch.observe(wrapFunction(_$('selector'), _$('eventName'), __)),
Patch.advertise(wrapFunction(_$('selector'), _$('eventName'), __)),
{
metaLevel: metaLevel,
onDemandIncrease: function (c) {
Network.spawn(new JQueryEventRouter(baseSelector,
c.selector,
c.eventName,
metaLevel,
wrapFunction));
}
}));
}
function defaultWrapFunction(selector, eventName, eventValue) {
return ["jQuery", selector, eventName, eventValue];
}
function JQueryEventRouter(baseSelector, selector, eventName, metaLevel, wrapFunction) {
var self = this;
this.baseSelector = baseSelector || null;
this.selector = selector;
this.eventName = eventName;
this.metaLevel = metaLevel || 0;
this.wrapFunction = wrapFunction || defaultWrapFunction;
this.preventDefault = (this.eventName.charAt(0) !== "+");
this.handler =
Network.wrap(function (e) {
Network.send(self.wrapFunction(self.selector, self.eventName, e), self.metaLevel);
if (self.preventDefault) e.preventDefault();
return !self.preventDefault;
});
this.computeNodes().on(this.preventDefault ? this.eventName : this.eventName.substring(1),
this.handler);
}
JQueryEventRouter.prototype.boot = function () {
return Patch.pub(this.wrapFunction(this.selector, this.eventName, __), this.metaLevel)
.andThen(Patch.sub(Patch.observe(this.wrapFunction(this.selector, this.eventName, __)),
this.metaLevel));
};
JQueryEventRouter.prototype.handleEvent = function (e) {
if (e.type === "stateChange" && e.patch.hasRemoved()) {
this.computeNodes().off(this.eventName, this.handler);
Network.exit();
}
};
JQueryEventRouter.prototype.computeNodes = function () {
if (this.baseSelector) {
return $(this.baseSelector).children(this.selector).addBack(this.selector);
} else {
return $(this.selector);
}
};
function simplifyDOMEvent(e) {
var keys = [];
for (var k in e) {
var v = e[k];
if (typeof v === 'object') continue;
if (typeof v === 'function') continue;
keys.push(k);
}
keys.sort();
var simplified = [];
for (var i = 0; i < keys.length; i++) {
simplified.push([keys[i], e[keys[i]]]);
}
return simplified;
}
///////////////////////////////////////////////////////////////////////////
module.exports.spawnJQueryDriver = spawnJQueryDriver;
module.exports.simplifyDOMEvent = simplifyDOMEvent;
module.exports.defaultWrapFunction = defaultWrapFunction;

View File

@ -17,8 +17,10 @@ copyKeys(['__', '_$', '$Capture', '$Special',
module.exports,
module.exports.Route);
module.exports.DemandMatcher = require('./demand-matcher.js').DemandMatcher;
// module.exports.DOM = require("./dom-driver.js");
// module.exports.JQuery = require("./jquery-driver.js");
module.exports.JQuery = require("./jquery-driver.js");
// module.exports.RoutingTableWidget = require("./routing-table-widget.js");
// module.exports.WebSocket = require("./websocket-driver.js");
module.exports.Reflect = require("./reflect.js");