Introduce Syndicate.Ack() to reliably detect lack of demand in DOMFragment.
This commit is contained in:
parent
3489b5fab7
commit
afa657096a
|
@ -0,0 +1,41 @@
|
|||
// Utility protocol for measuring when a stateChange takes effect.
|
||||
|
||||
var RandomID = require('./randomid.js');
|
||||
var Syndicate = require('./syndicate.js');
|
||||
var Route = require('./route.js');
|
||||
var Patch = require('./patch.js');
|
||||
|
||||
var $Ack = new Route.$Special('ack');
|
||||
|
||||
function Ack(metaLevel, id) {
|
||||
this.metaLevel = metaLevel || 0;
|
||||
this.id = id || RandomID.randomId(16);
|
||||
this.done = false;
|
||||
}
|
||||
|
||||
Ack.prototype.arm = function () {
|
||||
Syndicate.Network.stateChange(Patch.sub([$Ack, this.id], this.metaLevel));
|
||||
Syndicate.Network.send([$Ack, this.id], this.metaLevel);
|
||||
};
|
||||
|
||||
Ack.prototype.disarm = function () {
|
||||
Syndicate.Network.stateChange(Patch.unsub([$Ack, this.id], this.metaLevel));
|
||||
};
|
||||
|
||||
Ack.prototype.check = function (e) {
|
||||
if (!this.done) {
|
||||
if (e.type === 'message') {
|
||||
var m = Patch.stripAtMeta(e.message, this.metaLevel);
|
||||
if (m && m[0] === $Ack && m[1] === this.id) {
|
||||
this.disarm();
|
||||
this.done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.done;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module.exports.$Ack = $Ack;
|
||||
module.exports.Ack = Ack;
|
|
@ -33,6 +33,8 @@ function DOMFragment(selector, fragmentClass, fragmentSpec, domWrapFunction, jQu
|
|||
this.fragmentSpec = fragmentSpec;
|
||||
this.domWrapFunction = domWrapFunction;
|
||||
this.jQueryWrapFunction = jQueryWrapFunction;
|
||||
this.demandExists = false;
|
||||
this.subscriptionEstablished = new Syndicate.Ack();
|
||||
this.nodes = this.buildNodes();
|
||||
}
|
||||
|
||||
|
@ -45,22 +47,36 @@ DOMFragment.prototype.boot = function () {
|
|||
1,
|
||||
self.jQueryWrapFunction);
|
||||
Network.spawn({
|
||||
demandExists: false,
|
||||
subscriptionEstablished: new Syndicate.Ack(1),
|
||||
boot: function () {
|
||||
this.subscriptionEstablished.arm();
|
||||
return Patch.sub(Patch.advertise(specification), 1);
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "stateChange" && e.patch.hasRemoved()) {
|
||||
this.subscriptionEstablished.check(e);
|
||||
if (e.type === "stateChange") {
|
||||
if (e.patch.hasAdded()) this.demandExists = true;
|
||||
if (e.patch.hasRemoved()) this.demandExists = false;
|
||||
}
|
||||
if (this.subscriptionEstablished.done && !this.demandExists) {
|
||||
Network.exitNetwork();
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this.subscriptionEstablished.arm();
|
||||
return Patch.sub(specification).andThen(Patch.pub(specification));
|
||||
};
|
||||
|
||||
DOMFragment.prototype.handleEvent = function (e) {
|
||||
if (e.type === "stateChange" && e.patch.hasRemoved()) {
|
||||
this.subscriptionEstablished.check(e);
|
||||
if (e.type === "stateChange") {
|
||||
if (e.patch.hasAdded()) this.demandExists = true;
|
||||
if (e.patch.hasRemoved()) this.demandExists = false;
|
||||
}
|
||||
if (this.subscriptionEstablished.done && !this.demandExists) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var n = this.nodes[i];
|
||||
n.parentNode.removeChild(n);
|
||||
|
|
|
@ -19,7 +19,9 @@ copyKeys(['__', '_$', '$Capture', '$Special',
|
|||
|
||||
module.exports.DemandMatcher = require('./demand-matcher.js').DemandMatcher;
|
||||
module.exports.Seal = require('./seal.js').Seal;
|
||||
module.exports.Ack = require('./ack.js').Ack;
|
||||
|
||||
module.exports.RandomID = require('./randomid.js');
|
||||
module.exports.DOM = require("./dom-driver.js");
|
||||
module.exports.JQuery = require("./jquery-driver.js");
|
||||
// module.exports.RoutingTableWidget = require("./routing-table-widget.js");
|
||||
|
|
|
@ -33,6 +33,17 @@ function prependAtMeta(p, level) {
|
|||
return p;
|
||||
}
|
||||
|
||||
function stripAtMeta(p, level) {
|
||||
while (level--) {
|
||||
if (p.length === 2 && p[0] === $AtMeta) {
|
||||
p = p[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
function observeAtMeta(p, level) {
|
||||
if (level === 0) {
|
||||
return Route.compilePattern(true, observe(p));
|
||||
|
@ -240,6 +251,7 @@ module.exports.isAtMeta = isAtMeta;
|
|||
module.exports.isAdvertise = isAdvertise;
|
||||
|
||||
module.exports.prependAtMeta = prependAtMeta;
|
||||
module.exports.stripAtMeta = stripAtMeta;
|
||||
module.exports.observeAtMeta = observeAtMeta;
|
||||
module.exports.assert = assert;
|
||||
module.exports.retract = retract;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
var randomId;
|
||||
|
||||
if ((typeof window !== 'undefined') &&
|
||||
(typeof window.crypto !== 'undefined') &&
|
||||
(typeof window.crypto.getRandomValues !== 'undefined')) {
|
||||
randomId = function (byteCount) {
|
||||
var buf = new Uint8Array(byteCount);
|
||||
window.crypto.getRandomValues(buf);
|
||||
return btoa(String.fromCharCode.apply(null, buf)).replace(/=/g,'');
|
||||
};
|
||||
} else if ((typeof crypto !== 'undefined') &&
|
||||
(typeof crypto.randomBytes !== 'undefined')) {
|
||||
randomId = function (byteCount) {
|
||||
return crypto.randomBytes(byteCount).base64Slice().replace(/=/g,'');
|
||||
};
|
||||
} else {
|
||||
console.warn('No suitable implementation for RandomID.randomId available.');
|
||||
}
|
||||
|
||||
module.exports.randomId = randomId;
|
Loading…
Reference in New Issue