porting GC logic to livedocument

This commit is contained in:
David Greenspan
2012-07-23 16:30:28 -07:00
parent 14ced70720
commit 2e2ee29056
3 changed files with 61 additions and 5 deletions

View File

@@ -11,6 +11,7 @@ Meteor.ui._doc = Meteor.ui._doc || {};
var MARKER_PARSE_REGEX = /^LIVEUI_(.*)$/;
Meteor.ui._TAG = "_liveui";
Meteor.ui._HELD = "_liveui_refs"; // XXX _liveui_held
Meteor.ui._doc._newAnnotations = {}; // {id -> options} until range created
Meteor.ui._doc._newRanges = []; // [LiveRange, ...] until flush time
@@ -113,6 +114,8 @@ 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
Meteor.ui._doc._newRanges.push(range);
var next = comment.nextSibling;
@@ -138,6 +141,11 @@ Meteor.ui._doc = Meteor.ui._doc || {};
return frag;
};
// at flush time, doCallbacks()
var cx = new Meteor.deps.Context;
cx.on_invalidate(Meteor.ui._doc._doCallbacks);
cx.invalidate();
return makeFrag(topHtml);
};
@@ -156,4 +164,41 @@ Meteor.ui._doc = Meteor.ui._doc || {};
html + "<!--" + LIVEUI_END_PREFIX + options.id + "-->");
};
Meteor.ui._doc.poke = function(range) {
// XXX like Sarge.checkOffscreen
};
Meteor.ui._doc.cleanNodes = function(start, end) {
// XXX like Sarge.shuck
};
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._newAnnotations = {};
Meteor.ui._doc._newRanges.length = 0;
};
// "node holding" is a facility used for unit tests where
// we don't GC a DocumentFragment at flush time.
Meteor.ui._doc._isNodeHeld = function(node) {
while (node.parentNode)
node = node.parentNode;
return node.nodeType !== 3 /*TEXT_NODE*/ &&
node[Meteor.ui._HELD];
};
})();

View File

@@ -1,9 +1,12 @@
Tinytest.add("livedocument - assembly", function(test) {
var doTest = function(calc) {
var onscreens = [];
var frag = Meteor.ui._doc.materialize(
calc(function(str, expected) {
return Meteor.ui._doc.annotate(str);
return Meteor.ui._doc.annotate(str, {onscreen:function() {
onscreens.push(this.id);
}});
}));
var groups = [];
var html = calc(function(str, expected, noRange) {
@@ -13,7 +16,8 @@ Tinytest.add("livedocument - assembly", function(test) {
groups.push(str);
return str;
});
test.equal(WrappedFrag(frag).html(), html);
var f = WrappedFrag(frag);
test.equal(f.html(), html);
var actualGroups = [];
var tempRange = new Meteor.ui._LiveRange(Meteor.ui._TAG, frag);
@@ -22,6 +26,13 @@ Tinytest.add("livedocument - assembly", function(test) {
actualGroups.push(Meteor.ui._rangeToHtml(rng));
});
test.equal(actualGroups.join(','), groups.join(','));
f.hold();
Meteor.flush();
test.equal(onscreens.length, groups.length);
var uniqueOnscreens = _.uniq(onscreens);
test.equal(uniqueOnscreens.length, onscreens.length);
f.release();
};
doTest(function(A) { return "<p>Hello</p>"; });

View File

@@ -8,7 +8,7 @@ Meteor.ui = Meteor.ui || {};
if (typeof html_func !== "function")
throw new Error("Meteor.ui.render() requires a function as its first argument.");
if (Meteor.ui._inRenderMode)
if (Materializer.current)
throw new Error("Can't nest Meteor.ui.render.");
return renderChunk(html_func, options, "fragment").containerNode();
@@ -323,7 +323,7 @@ Meteor.ui = Meteor.ui || {};
renderChunk(html_func, options, "patch", this);
});
};
range.destroy = function() {
range.destroyed = function() {
range.context && range.context.invalidate();
callOffscreen();
};
@@ -463,7 +463,7 @@ Meteor.ui = Meteor.ui || {};
range.killed = true;
// only one of these ever scheduled per range:
Sarge.atFlushTime(function() {
range.destroy && range.destroy();
range.destroyed && range.destroyed();
});
}
},