mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
porting GC logic to livedocument
This commit is contained in:
@@ -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];
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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>"; });
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user