onlive/ondead (doesn't work)

This commit is contained in:
David Greenspan
2012-07-23 22:53:20 -07:00
parent 2e2ee29056
commit d1e87a2f2e
2 changed files with 59 additions and 21 deletions

View File

@@ -17,6 +17,13 @@ Meteor.ui._doc = Meteor.ui._doc || {};
Meteor.ui._doc._newRanges = []; // [LiveRange, ...] until flush time
Meteor.ui._doc._nextId = 1;
// ranges (/annotations) become "live" (range.live) when they go
// onscreen, and "dead" (range.dead) when they go offscreen.
// There are onlive and ondead callbacks. Every range either
// becomes live and then eventually dead, with both callbacks,
// or is never externally seen to materialize. This is determined
// at flush time.
// XXX to mention:
// - turning ranges into frags separately helps deal with
// mismatched tags
@@ -114,7 +121,7 @@ Meteor.ui._doc = Meteor.ui._doc || {};
var range = new Meteor.ui._LiveRange(Meteor.ui._TAG, subFrag);
// assign options to the LiveRange, including `id`
_.extend(range, options);
// enqueue the new range for onscreen callback processing
// enqueue the new range for callback processing
Meteor.ui._doc._newRanges.push(range);
var next = comment.nextSibling;
@@ -164,26 +171,46 @@ Meteor.ui._doc = Meteor.ui._doc || {};
html + "<!--" + LIVEUI_END_PREFIX + options.id + "-->");
};
Meteor.ui._doc.poke = function(range) {
// XXX like Sarge.checkOffscreen
// possibly GC range, firing synchronous ondead() callbacks
// for `range` and potentially other ranges if they are
// currently "live"
Meteor.ui._doc.touch = function(range) {
if (range.dead)
return;
var node = range.firstNode();
if (! (node.parentNode &&
(Meteor.ui._isNodeOnscreen(node) ||
Meteor.ui._doc._isNodeHeld(node)))) {
// range is offscreen!
// kill all ranges in this fragment or detached DOM tree,
// including `range`
while (node.parentNode)
node = node.parentNode;
Meteor.ui._doc.cleanNodes(node.firstChild, node.lastChild);
}
};
Meteor.ui._doc.cleanNodes = function(start, end) {
// XXX like Sarge.shuck
// should accept any (start,end) that the LiveRange constructor does
var wrapper = new Meteor.ui._LiveRange(Meteor.ui._TAG, start, end);
wrapper.visit(function (isStart, range) {
if (isStart && range.live) {
range.live = false;
range.dead = true;
range.ondead && range.ondead();
}
});
wrapper.destroy(true);
};
Meteor.ui._doc._doCallbacks = function() {
_.each(Meteor.ui._doc._newRanges, function(range) {
if (range.onscreen) {
var node = range.firstNode();
if (! (node.parentNode &&
(Meteor.ui._isNodeOnscreen(node) ||
Meteor.ui._doc._isNodeHeld(node))))
return; // range was created but isn't in the document at flush time
range.onscreen();
// existence of `killed=false` means range went onscreen and we'll
// have to call offscreen() later
range.killed = false;
Meteor.ui._doc.touch(range);
if (! range.dead) {
range.live = true;
range.onlive && range.onlive();
}
});

View File

@@ -1,11 +1,14 @@
Tinytest.add("livedocument - assembly", function(test) {
var doTest = function(calc) {
var onscreens = [];
var onlives = [];
var ondeads = [];
var frag = Meteor.ui._doc.materialize(
calc(function(str, expected) {
return Meteor.ui._doc.annotate(str, {onscreen:function() {
onscreens.push(this.id);
return Meteor.ui._doc.annotate(str, {onlive: function() {
onlives.push(this.id);
}, ondead: function() {
ondeads.push(this.id);
}});
}));
var groups = [];
@@ -29,10 +32,18 @@ Tinytest.add("livedocument - assembly", function(test) {
f.hold();
Meteor.flush();
test.equal(onscreens.length, groups.length);
var uniqueOnscreens = _.uniq(onscreens);
test.equal(uniqueOnscreens.length, onscreens.length);
f.release();
test.equal(onlives.length, groups.length);
var uniqueOnlives = _.uniq(onlives);
test.equal(uniqueOnlives.length, onlives.length);
test.equal(ondeads.length, 0);
//f.release(); XXXX
Meteor.ui._doc.cleanNodes(f.node()); // WHY DOESN'T THIS WORK
var numRanges = onlives.length;
onlives.length = 0;
Meteor.flush();
test.equal(onlives.length, 0);
test.equal(ondeads.length, numRanges);
};
doTest(function(A) { return "<p>Hello</p>"; });