- Render widgets on NodeJS, where DOM is absent.
- Optimize rendering of Widgets at scale (1000s of TreeViewNodes).
- Avoid all Node references from Widget through the end of renderUI().
- bindUI()/syncUI() will still have Node references (to bind events and incrementally update DOM).
A boundingBox/contentBox Node instance won't be present for initializer/attr setters/attr getters/HTML_PARSER, so needs to be opt-in.
-
Component Developer can opt-in, if they have a 100% string rendered component (e.g. TreeViewNode)
In this case, get("boundingBox") etc. needs to be documented accordingly for the end user.
-
Environment can opt-in (e.g. NodeJS - conditional loading)
Example:
Y.WidgetStringRenderer = function() {...};
Y.WidgetStringRenderer.prototype = {
// override what needs to be overridden in Y.Widget to support string template based rendering.
}
Y.Foo = Y.Base.create("foo", Y.Widget, [Y.WidgetStringRenderer]);
It'll use Handlebar style templates as opposed to substitute, for forward compatibility.
However we should maybe look into a "handlebars-core" to satisfy the kweight nitpickers. We've been asked to break out less than 3KB chunks before which is where handlebars-base-min.js currently is.
"handlebars-core" could provide basic {{ }} and {{{ }}} support, and also maybe provide substitute compatibility (how to identify single { tokens, from content in a handlebars template?).
We'll need to break up the render()
phase, into the renderUI() portion and the bind/syncUI() portion
render()
renderUI() : No Node references
bindUI() : Node references
syncUI() : Node references
Not sure what the method split should be yet. Options are below, first one is my leading candidate
TreeView use case:
// While iterating 1000s treeview nodes ...
treeviewNode.renderHTML(buffer); // only renderUI() - is it OK that render event is not fired?
// I think so. Nothing is in the DOM yet.
// Once injected into the DOM ...
treeviewNode.render(); // renderUI() [if not invoked before], bindUI(), syncUI()
NodeJS use case:
// On Server
calendar.renderHTML();
// On Client
calendar.render();
Or,
treeviewNode.render();
treeviewNode.bind(); // How about if they want to do it all at once in render(); bind() and Y.bind() confusion
Or,
treeviewNode.renderHTML();
treeviewNode.bind();
Or,
treeviewNode.renderUI() // When do we fire/set render state?
treeviewNode.bindUI()
treeviewNode.syncUI()
Widget will generate node instance from rendered template content for boundingBox, contentBox
Y.TreeViewNode = Y.Base.create("treeViewNode", Y.Widget, [Y.Parent, Y.Child, Y.WidgetStringRenderer]);
// In Parent.render() ...
var buffer = [];
for (i = 0; i < children.length; i++) {
child.renderHTML(buffer);
}
var allChildrenHTML = buffer.join("");
// calendar-nodejs, or maybe just widget-base-nodejs
Y.Calendar = Y.Base.create("calendar", Y.Widget, [Y.WidgetStringRenderer]);
var buffer = []
calendar.renderHTML(buffer);
var calendarHTML = buffer.join("");
We can add sugar in the future (render straight into a template for example). Not enough time for Sprint 1.
calendar.renderHTML(template, token);
@rgrove:
I see that conceptual value if Widget is broken up into separate M, V, C components as discussed in the App/Widget conversation. If I'm just mixing in support for string based rendering to the current Widget API, I don't see any value in pulling the View API along if we won't be using any of it, especially since it'll probably lead to confusing overlap with similar areas of Widget which are already defined (bounding box/content box templates vs. template, widget destruction vs. view destruction, model vs. widgets attrs, container vs boundingBox etc).
If we do end up breaking Widget into a separate M, V and C down the road (not currently in the 3.5.0 timeline, maybe 3.6.0) then I think it makes complete sense to see what the most basic M, V and C could be which could be used in the Widget world as well as the App world.
I'm leaning towards having WidgetStringRenderer be something that maybe Tree owns (I'll do the work, but it'll be an internal TreeViewNode impl) for the 3.5.0 release (or at least for the pr1 release), due to the shortness of time, and we can visit the Widget MVC breakup in more depth for 3.6.0 - which I believe is the real answer to the above design pros/cons.
I'll think about it a little further from the angle of delegating to a View string renderer, but I think there's too much backwards compatibility baggage to carry along and I'm likely to go with the above.
@lsmith, @rgrove:
I agree - when we don't have an existing API we need to reconcile (as in the base Widget case) doing whatever we can to break the view pieces of a widget out into encapsulated reusable chunks makes sense. I would argue though that View needs to be more basic, if we have more than a couple of use cases which don't end up being bound to a Model (that was the basis of my DT review question). Having for example a DT header View instance, which is not bound to a model, but has a model/modelList attribute, leads to some confusion, especially in the DT world. The most basic View could be purely a renderer (with associated utility methods/attributes), without any Model/Data binding overhead.
@lsmith:
Re: WidgetBase, while playing around with the Widget MVC breakout during the week of NodeJS, that's actually what I had - WidgetBase + WidgetLifecycle + WidgetView + WidgetModel + WidgetController extensions [ didn't get as far as putting it all back together ]