- 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);
@sdesai: Regarding the overlap with View: what I mean is that, conceptually, View and WidgetStringRenderer would serve similar purposes. Out of the box, View requires a Node instance that it can use as a container, but this behavior is easy to customize via a subclass or extension, and the stage is already set for template-based rendering, not to mention future data binding support.
View supports, but does not require, an explicit Model binding. It's perfectly reasonable to use a View without a Model.
I used the word "conceptually" because there's not much actual functionality inside View; it's more of a generic idea with broad potential, and one of the things it has potential for is something like this. The benefit is in the conceptual consistency of using View throughout the library as a low-level HTML rendering tool.
I don't think it's necessary to make a TreeNode something other than a Widget, but I think relying on per-instance rendering will introduce a performance barrier that can't be overcome no matter how much the Widget lifecycle code is optimized. If the parent/child relationship can be made flexible enough that the parent can render the children without having to instantiate and call into each one of them, then there's more potential for TreeView and other parent/child widgets to be able to handle huge numbers of children without bogging down or gobbling memory.
I don't have any numbers on the Handlebars spinup cost, but it's worth looking into. I expect it will be trivial compared to widget instantiation cost, but still worth avoiding if we can.
@lsmith: I really like the idea of Views being used as markup factories like you're planning for DataTable. That's definitely worth exploring further, and I'd be happy to enhance View (or create subclasses/extensions) to better serve this use case.
Regarding Model's
toHTML()
method: there's no such thing. Maybe you're thinking ofgetAsHTML()
, which gets an HTML-escaped version of a model attribute?