mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
reimplement #each in terms of renderList
not tested yet
This commit is contained in:
committed by
Nick Martin
parent
0f397a2a08
commit
f0df8212ee
@@ -169,29 +169,36 @@ Sky.ui.render = function (render_func, events, event_data) {
|
||||
/// options to include:
|
||||
/// selector: minimongo selector (default: {})
|
||||
/// sort: minimongo sort specification (default: natural order)
|
||||
/// render: render function (from object to element)
|
||||
/// render: render function (as in render(), but takes a document)
|
||||
/// .. plus optionally
|
||||
/// render_empty: render function for content to show when query empty.
|
||||
/// still gets same event bindings.
|
||||
/// events: vaguely backbone-style live event specification
|
||||
/// {'click #selector #path' : function (obj) { } }
|
||||
///
|
||||
/// returns an object with:
|
||||
/// stop(): stop updating, tear everything down and let it get GC'd
|
||||
///
|
||||
/// XXX rewrite using Sky.ui.render, and new GC semantics, and make it
|
||||
/// return a fragment rather than plopping its results into a
|
||||
/// container
|
||||
|
||||
Sky.ui.renderList = function (collection, options) {
|
||||
/// XXX consider making render an argument rather than an option
|
||||
///
|
||||
/// XXX what package should this go in? depends on both liveui and minimongo..
|
||||
///
|
||||
/// XXX what can now be a collection, or the handle of an existing
|
||||
/// findlive. messy.
|
||||
Sky.ui.renderList = function (what, options) {
|
||||
var frag = document.createDocumentFragment();
|
||||
var context = new Sky.deps.Context;
|
||||
|
||||
var start = document.createComment("renderList " + collection._name);
|
||||
var end = document.createComment("end " + collection._name);
|
||||
var is_handle = what instanceof Collection.LiveResultsSet;
|
||||
var name = (is_handle ? what.collection : what)._name;
|
||||
var start = document.createComment("renderList " + name);
|
||||
var end = document.createComment("end " + name);
|
||||
start._used = end._used = true;
|
||||
start._context = context;
|
||||
frag.appendChild(start);
|
||||
frag.appendChild(end);
|
||||
|
||||
var empty_shown = false;
|
||||
var entry_starts = [];
|
||||
var entry_end = function (idx) {
|
||||
return (entry_starts[idx + 1] || end).previousSibling;
|
||||
@@ -206,14 +213,26 @@ Sky.ui.renderList = function (collection, options) {
|
||||
return this_start;
|
||||
};
|
||||
|
||||
var query = collection.findLive(options.selector, {
|
||||
sort: options.sort,
|
||||
var maybe_show_empty = function () {
|
||||
if (!entry_starts.length && options.render_empty) {
|
||||
start.parentNode.insertBefore(
|
||||
Sky.ui.render(options.render_empty, options.events), end);
|
||||
empty_shown = true;
|
||||
}
|
||||
};
|
||||
|
||||
var query_opts = {
|
||||
added: function (doc, before_idx) {
|
||||
if (empty_shown) {
|
||||
Sky.ui._remove(start.nextSibling, end.previousSibling);
|
||||
empty_shown = false;
|
||||
}
|
||||
entry_starts.splice(before_idx, 0, insert_entry(doc, before_idx));
|
||||
},
|
||||
removed: function (id, at_idx) {
|
||||
Sky.ui._remove(entry_starts[at_idx], entry_end(at_idx));
|
||||
entry_starts.splice(at_idx, 1);
|
||||
maybe_show_empty();
|
||||
},
|
||||
changed: function (doc, at_idx) {
|
||||
var this_start = insert_entry(doc, at_idx);
|
||||
@@ -228,7 +247,16 @@ Sky.ui.renderList = function (collection, options) {
|
||||
entry_starts.splice(old_idx, 1);
|
||||
entry_starts.splice(new_idx, 0, this_start);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (is_handle) {
|
||||
var query = what;
|
||||
query.reconnect(query_opts);
|
||||
} else {
|
||||
query_opts.sort = options.sort;
|
||||
var query = what.findLive(options.selector || {}, query_opts);
|
||||
}
|
||||
maybe_show_empty();
|
||||
|
||||
context.on_invalidate(function (old_context) {
|
||||
query.stop();
|
||||
|
||||
@@ -111,12 +111,13 @@ Collection.prototype.find = function (selector, options) {
|
||||
// - removed (id, at_index)
|
||||
// * sort: sort descriptor
|
||||
//
|
||||
// functions available on returned query handle:
|
||||
// attributes available on returned query handle:
|
||||
// * stop(): end updates
|
||||
// * indexOf(id): return current index of object in result set, or -1
|
||||
// * reconnect({}): replace added, changed, moved, removed, from the
|
||||
// arguments, and call added to deliver the current state of the
|
||||
// query (XXX ugly hack to support templating)
|
||||
// * collection: the collection this query is querying
|
||||
//
|
||||
// iff x is a returned query handle, (x instanceof
|
||||
// Collection.LiveResultsSet) is true
|
||||
@@ -127,6 +128,7 @@ Collection.prototype.find = function (selector, options) {
|
||||
// XXX maybe support limit/skip
|
||||
// XXX it'd be helpful if removed got the object that just left the
|
||||
// query, not just its id
|
||||
// XXX document that initial results will definitely be delivered before we return [do, add to asana]
|
||||
|
||||
Collection.LiveResultsSet = function () {};
|
||||
Collection.prototype.findLive = function (selector, options) {
|
||||
@@ -165,7 +167,8 @@ Collection.prototype.findLive = function (selector, options) {
|
||||
return i;
|
||||
return -1;
|
||||
},
|
||||
reconnect: connect
|
||||
reconnect: connect,
|
||||
collection: this
|
||||
});
|
||||
return handle;
|
||||
};
|
||||
|
||||
@@ -17,14 +17,9 @@ if (typeof Sky === "undefined") Sky = {};
|
||||
Sky._pending_partials = null; // id -> element
|
||||
Sky._pending_partials_idx_nonce = 0;
|
||||
|
||||
// XXX another disgusting hack -- we reach into handlebars and
|
||||
// extend #each to know how to cooperate with pending_partials and
|
||||
// minimongo findlive.
|
||||
//
|
||||
// XXX XXX XXX the garbage collection implications are terrible.. we
|
||||
// don't even pretend to call stop on the findlive, so every time
|
||||
// we're rerendered, we kick off another findlive that runs
|
||||
// .. forever!
|
||||
// XXX another messy hack -- we reach into handlebars and extend #each
|
||||
// to know how to cooperate with pending_partials and minimongo
|
||||
// findlive.
|
||||
Sky._hook_handlebars_each = function () {
|
||||
Sky._hook_handlebars_each = function(){}; // install the hook only once
|
||||
|
||||
@@ -33,80 +28,15 @@ Sky._hook_handlebars_each = function () {
|
||||
if (!(context instanceof Collection.LiveResultsSet))
|
||||
return orig(context, options);
|
||||
|
||||
// XXX inserts an intermediate DIV!! that is lame and should be
|
||||
// fixed. besides general hygiene/pride, we really need to
|
||||
// support <ul>{{#each items}}<li>{{name}}</li>{{/each}}</ul>
|
||||
var element = document.createElement("div");
|
||||
|
||||
var trim = function (markup) {
|
||||
// Consider {{#each items}\n{{> item}}\n{{/each}}
|
||||
//
|
||||
// In that case, options.fn will return HTML that parses into
|
||||
// three nodes: whitespace, the partial, whitespace. That
|
||||
// won't work. I can't reconcile this logically at the moment,
|
||||
// but "do what you mean" and strip the whitespace.
|
||||
//
|
||||
// XXX fails if a {{#if}..{{else}}..{{/if}} is at toplevel in
|
||||
// a template?
|
||||
var match = markup.match(/^\s*(<[\s\S]+>)\s*$/);
|
||||
if (match)
|
||||
markup = match[1];
|
||||
return markup;
|
||||
}
|
||||
|
||||
var render = Sky._def_template(null, function (obj) {
|
||||
return trim(options.fn(obj));
|
||||
});
|
||||
|
||||
var renderElse = Sky._def_template(null, function () {
|
||||
return trim(options.inverse({}));
|
||||
});
|
||||
|
||||
// XXX sort of lame that we always end up rendering this even if
|
||||
// the query returns results 100% of the time ..
|
||||
var is_empty = true;
|
||||
element.appendChild(renderElse());
|
||||
|
||||
// XXX copied code from Sky.ui.renderList.. bleh
|
||||
// (with addition of is_empty / renderElse)
|
||||
context.reconnect({
|
||||
added: function (obj, before_idx) {
|
||||
if (is_empty) {
|
||||
element.removeChild(element.childNodes[0]);
|
||||
is_empty = false;
|
||||
}
|
||||
if (before_idx === element.childNodes.length)
|
||||
element.appendChild(render(obj));
|
||||
else
|
||||
element.insertBefore(render(obj), element.childNodes[before_idx]);
|
||||
Sky.ui._tryFocus();
|
||||
},
|
||||
removed: function (id, at_idx) {
|
||||
element.removeChild(element.childNodes[at_idx]);
|
||||
if (element.childNodes.length === 0) {
|
||||
is_empty = true;
|
||||
element.appendChild(renderElse());
|
||||
}
|
||||
},
|
||||
changed: function (obj, at_idx) {
|
||||
element.insertBefore(render(obj), element.childNodes[at_idx]);
|
||||
element.removeChild(element.childNodes[at_idx + 1]);
|
||||
Sky.ui._tryFocus();
|
||||
},
|
||||
moved: function (obj, old_idx, new_idx) {
|
||||
var elt = element.removeChild(element.childNodes[old_idx]);
|
||||
if (new_idx === element.childNodes.length)
|
||||
element.appendChild(elt);
|
||||
else
|
||||
element.insertBefore(elt, element.childNodes[new_idx]);
|
||||
}
|
||||
});
|
||||
|
||||
var id = Sky._pending_partials_idx_nonce++;
|
||||
Sky._pending_partials[id] = element;
|
||||
Sky._pending_partials[id] = Sky.ui.renderList(context, {
|
||||
render: Sky._def_template(null, options.fn),
|
||||
render_empty: Sky._def_template(null, _.bind(options.inverse, null, {}))
|
||||
});
|
||||
|
||||
return "<div id='" + id +
|
||||
"'><!-- for replacement with findlive each --></div>";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// XXX namespacing
|
||||
|
||||
Reference in New Issue
Block a user