Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Unified Diff: tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate

Issue 17552019: Reorganize mdv and observe packages (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index 3ee36461f789ca8b365a13c9ddcb8368ddd29c17..1aba301acaa2bd5a2de28040e91baaa5191e2a4f 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -6,6 +6,99 @@
part of $LIBRARYNAME;
+
+/**
+ * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
+ * but (by design) don't attempt to implement a wide array of specialized
+ * behaviors.
+ *
+ * Enabling these features in MDV is a matter of implementing and registering an
+ * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
+ * delegation functions which implement specialized behavior. This object is
+ * registered with MDV via [TemplateElement.syntax]:
+ *
+ *
+ * HTML:
+ * <template bind syntax="MySyntax">
+ * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
+ * </template>
+ *
+ * Dart:
+ * class MySyntax extends CustomBindingSyntax {
+ * getBinding(model, path, name, node) {
+ * // The magic happens here!
+ * }
+ * }
+ *
+ * ...
+ *
+ * TemplateElement.syntax['MySyntax'] = new MySyntax();
+ *
+ * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for
+ * more information about Custom Syntax.
+ */
+// TODO(jmesserly): if this is just one method, a function type would make it
+// more Dart-friendly.
+@Experimental
+abstract class CustomBindingSyntax {
+ /**
+ * This syntax method allows for a custom interpretation of the contents of
+ * mustaches (`{{` ... `}}`).
+ *
+ * When a template is inserting an instance, it will invoke this method for
+ * each mustache which is encountered. The function is invoked with four
+ * arguments:
+ *
+ * - [model]: The data context for which this instance is being created.
+ * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
+ * - [name]: The context in which the mustache occurs. Within element
+ * attributes, this will be the name of the attribute. Within text,
+ * this will be 'text'.
+ * - [node]: A reference to the node to which this binding will be created.
+ *
+ * If the method wishes to handle binding, it is required to return an object
+ * which has at least a `value` property that can be observed. If it does,
+ * then MDV will call [Node.bind on the node:
+ *
+ * node.bind(name, retval, 'value');
+ *
+ * If the 'getBinding' does not wish to override the binding, it should return
+ * null.
+ */
+ // TODO(jmesserly): I had to remove type annotations from "name" and "node"
+ // Normally they are String and Node respectively. But sometimes it will pass
+ // (int name, CompoundBinding node). That seems very confusing; we may want
+ // to change this API.
+ getBinding(model, String path, name, node) => null;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate model than the
+ * one the template would otherwise use when producing an instance.
+ *
+ * When a template is about to create an instance, it will invoke this method
+ * The function is invoked with two arguments:
+ *
+ * - [template]: The template element which is about to create and insert an
+ * instance.
+ * - [model]: The data context for which this instance is being created.
+ *
+ * The template element will always use the return value of `getInstanceModel`
+ * as the model for the new instance. If the syntax does not wish to override
+ * the value, it should simply return the `model` value it was passed.
+ */
+ getInstanceModel(Element template, model) => model;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate expansion of
+ * the [template] contents. When the template wants to create an instance,
+ * it will call this method with the template element.
+ *
+ * By default this will call `template.createInstance()`.
+ */
+ getInstanceFragment(Element template) => template.createInstance();
+}
+
+
@Experimental
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
$!MEMBERS
@@ -15,24 +108,23 @@ $!MEMBERS
@Experimental
DocumentFragment get content => $dom_content;
- static StreamController<DocumentFragment> _instanceCreated;
/**
- * *Warning*: This is an implementation helper for Model-Driven Views and
- * should not be used in your code.
+ * The MDV package, if available.
*
- * This event is fired whenever a template is instantiated via
- * [createInstance].
+ * This can be used to initialize MDV support via:
+ *
+ * import 'dart:html';
+ * import 'package:mdv/mdv.dart' as mdv;
+ * main() {
+ * mdv.initialize();
+ * }
*/
- // TODO(rafaelw): This is a hack, and is neccesary for the polyfill
- // because custom elements are not upgraded during clone()
- @Experimental
- static Stream<DocumentFragment> get instanceCreated {
- if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>(sync: true);
- }
- return _instanceCreated.stream;
- }
+ static Function mdvPackage = (node) {
+ throw new UnsupportedError("The MDV package is not available. "
+ "You can enable it with `import 'package:mdv/mdv.dart' as mdv;` and "
+ "`mdv.initialize()`");
+ };
/**
* Ensures proper API and content model for template elements.
@@ -55,7 +147,7 @@ $!MEMBERS
// Create content
if (template is! TemplateElement) {
- var doc = _Bindings._getTemplateContentsOwner(template.document);
+ var doc = _getTemplateContentsOwner(template.document);
template._templateContent = doc.createDocumentFragment();
}
@@ -67,12 +159,80 @@ $!MEMBERS
if (template is TemplateElement) {
bootstrap(template.content);
} else {
- _Bindings._liftNonNativeChildrenIntoContent(template);
+ _liftNonNativeChildrenIntoContent(template);
}
return true;
}
+ // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
+ if (doc.window == null) {
+ return doc;
+ }
+ var d = doc._templateContentsOwner;
+ if (d == null) {
+ // TODO(arv): This should either be a Document or HTMLDocument depending
+ // on doc.
+ d = doc.implementation.createHtmlDocument('');
+ while (d.lastChild != null) {
+ d.lastChild.remove();
+ }
+ doc._templateContentsOwner = d;
+ }
+ return d;
+ }
+
+ static Element _cloneAndSeperateAttributeTemplate(Element templateElement) {
+ var clone = templateElement.clone(false);
+ var attributes = templateElement.attributes;
+ for (var name in attributes.keys.toList()) {
+ switch (name) {
+ case 'template':
+ case 'repeat':
+ case 'bind':
+ case 'ref':
+ clone.attributes.remove(name);
+ break;
+ default:
+ attributes.remove(name);
+ break;
+ }
+ }
+
+ return clone;
+ }
+
+ static void _liftNonNativeChildrenIntoContent(Element templateElement) {
+ var content = templateElement.content;
+
+ if (!templateElement._isAttributeTemplate) {
+ var child;
+ while ((child = templateElement.firstChild) != null) {
+ content.append(child);
+ }
+ return;
+ }
+
+ // For attribute templates we copy the whole thing into the content and
+ // we move the non template attributes into the content.
+ //
+ // <tr foo template>
+ //
+ // becomes
+ //
+ // <tr template>
+ // + #document-fragment
+ // + <tr foo>
+ //
+ var newRoot = _cloneAndSeperateAttributeTemplate(templateElement);
+ var child;
+ while ((child = templateElement.firstChild) != null) {
+ newRoot.append(child);
+ }
+ content.append(newRoot);
+ }
+
/**
* This used to decorate recursively all templates from a given node.
*
@@ -83,25 +243,26 @@ $!MEMBERS
// TODO(rafaelw): Review whether this is the right public API.
@Experimental
static void bootstrap(Node content) {
- _Bindings._bootstrapTemplatesRecursivelyFrom(content);
- }
+ void _bootstrap(template) {
+ if (!TemplateElement.decorate(template)) {
+ bootstrap(template.content);
+ }
+ }
- /**
- * Binds all mustaches recursively starting from the [root] node.
- *
- * Note: this is not an official Model-Driven-Views API; it is intended to
- * support binding the [ShadowRoot]'s content to a model.
- */
- // TODO(jmesserly): this is needed to avoid two <template> nodes when using
- // bindings in a custom element's template. See also:
- // https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
- // Called from:
- // https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
- @Experimental
- static void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
- _Bindings._addBindings(root, model, syntax);
+ // Need to do this first as the contents may get lifted if |node| is
+ // template.
+ // TODO(jmesserly): content is DocumentFragment or Element
+ var descendents = (content as dynamic).queryAll(_allTemplatesSelectors);
+ if (content is Element && (content as Element).isTemplate) {
+ _bootstrap(content);
+ }
+
+ descendents.forEach(_bootstrap);
}
+ static final String _allTemplatesSelectors = 'template, option[template], ' +
+ Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
+
static bool _initStyles;
static void _injectStylesheet() {
« no previous file with comments | « tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate ('k') | tools/dom/templates/html/impl/impl_Node.darttemplate » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698