From d1e87a2f2ea334c1a5afa858907b2eb2fc2e4f8b Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Mon, 23 Jul 2012 22:53:20 -0700 Subject: [PATCH] onlive/ondead (doesn't work) --- packages/liveui/livedocument.js | 55 ++++++++++++++++++++------- packages/liveui/livedocument_tests.js | 25 ++++++++---- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/packages/liveui/livedocument.js b/packages/liveui/livedocument.js index c5f6e353a8..04d6a44ee5 100644 --- a/packages/liveui/livedocument.js +++ b/packages/liveui/livedocument.js @@ -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 + ""); }; - 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(); } }); diff --git a/packages/liveui/livedocument_tests.js b/packages/liveui/livedocument_tests.js index 0f709b5727..4e0b13661d 100644 --- a/packages/liveui/livedocument_tests.js +++ b/packages/liveui/livedocument_tests.js @@ -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 "

Hello

"; });