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

Unified Diff: tools/dom/src/TemplateBindings.dart

Issue 14651030: Version 0.5.7.1 . (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 7 years, 7 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
« no previous file with comments | « tools/VERSION ('k') | tools/dom/templates/html/impl/impl_Element.darttemplate » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/dom/src/TemplateBindings.dart
===================================================================
--- tools/dom/src/TemplateBindings.dart (revision 22591)
+++ tools/dom/src/TemplateBindings.dart (working copy)
@@ -44,11 +44,61 @@
// 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);
+ 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();
}
/** The callback used in the [CompoundBinding.combinator] field. */
@@ -416,7 +466,7 @@
if (node is Element) {
_addAttributeBindings(node, model, syntax);
} else if (node is Text) {
- _parseAndBind(node, node.text, 'text', model, syntax);
+ _parseAndBind(node, 'text', node.text, model, syntax);
}
for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
@@ -430,11 +480,11 @@
if (value == '' && (name == 'bind' || name == 'repeat')) {
value = '{{}}';
}
- _parseAndBind(element, value, name, model, syntax);
+ _parseAndBind(element, name, value, model, syntax);
});
}
-void _parseAndBind(Node node, String text, String name, model,
+void _parseAndBind(Node node, String name, String text, model,
CustomBindingSyntax syntax) {
var tokens = _parseMustacheTokens(text);
@@ -569,105 +619,12 @@
_removeAllBindingsRecursively(child);
}
-class _InstanceCursor {
- final Element _template;
- Node _terminator;
- Node _previousTerminator;
- int _previousIndex = -1;
- int _index = 0;
- _InstanceCursor(this._template, [index]) {
- _terminator = _template;
- if (index != null) {
- while (index-- > 0) {
- next();
- }
- }
- }
-
- void next() {
- _previousTerminator = _terminator;
- _previousIndex = _index;
- _index++;
-
- while (_index > _terminator._instanceTerminatorCount) {
- _index -= _terminator._instanceTerminatorCount;
- _terminator = _terminator.nextNode;
- if (_terminator is Element && _terminator.tagName == 'TEMPLATE') {
- _index += _instanceCount(_terminator);
- }
- }
- }
-
- void abandon() {
- assert(_instanceCount(_template) > 0);
- assert(_terminator._instanceTerminatorCount > 0);
- assert(_index > 0);
-
- _terminator._instanceTerminatorCount--;
- _index--;
- }
-
- void insert(fragment) {
- assert(_template.parentNode != null);
-
- _previousTerminator = _terminator;
- _previousIndex = _index;
- _index++;
-
- _terminator = fragment.$dom_lastChild;
- if (_terminator == null) _terminator = _previousTerminator;
- _template.parentNode.insertBefore(fragment, _previousTerminator.nextNode);
-
- _terminator._instanceTerminatorCount++;
- if (_terminator != _previousTerminator) {
- while (_previousTerminator._instanceTerminatorCount >
- _previousIndex) {
- _previousTerminator._instanceTerminatorCount--;
- _terminator._instanceTerminatorCount++;
- }
- }
- }
-
- void remove() {
- assert(_previousIndex != -1);
- assert(_previousTerminator != null &&
- (_previousIndex > 0 || _previousTerminator == _template));
- assert(_terminator != null && _index > 0);
- assert(_template.parentNode != null);
- assert(_instanceCount(_template) > 0);
-
- if (_previousTerminator == _terminator) {
- assert(_index == _previousIndex + 1);
- _terminator._instanceTerminatorCount--;
- _terminator = _template;
- _previousTerminator = null;
- _previousIndex = -1;
- return;
- }
-
- _terminator._instanceTerminatorCount--;
-
- var parent = _template.parentNode;
- while (_previousTerminator.nextNode != _terminator) {
- _removeTemplateChild(parent, _previousTerminator.nextNode);
- }
- _removeTemplateChild(parent, _terminator);
-
- _terminator = _previousTerminator;
- _index = _previousIndex;
- _previousTerminator = null;
- _previousIndex = -1; // 0?
- }
-}
-
-
class _TemplateIterator {
final Element _templateElement;
- int instanceCount = 0;
+ final List<Node> terminators = [];
+ final CompoundBinding inputs;
List iteratedValue;
- bool observing = false;
- final CompoundBinding inputs;
StreamSubscription _sub;
StreamSubscription _valueBinding;
@@ -710,10 +667,75 @@
}
}
- // TODO(jmesserly): port MDV v3.
- getInstanceModel(model, syntax) => model;
- getInstanceFragment(syntax) => _templateElement.createInstance();
+ Node getTerminatorAt(int index) {
+ if (index == -1) return _templateElement;
+ var terminator = terminators[index];
+ if (terminator is! Element) return terminator;
+ var subIterator = terminator._templateIterator;
+ if (subIterator == null) return terminator;
+
+ return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
+ }
+
+ void insertInstanceAt(int index, Node fragment) {
+ var previousTerminator = getTerminatorAt(index - 1);
+ var terminator = fragment.$dom_lastChild;
+ if (terminator == null) terminator = previousTerminator;
+
+ terminators.insert(index, terminator);
+ var parent = _templateElement.parentNode;
+ parent.insertBefore(fragment, previousTerminator.nextNode);
+ }
+
+ void removeInstanceAt(int index) {
+ var previousTerminator = getTerminatorAt(index - 1);
+ var terminator = getTerminatorAt(index);
+ terminators.removeAt(index);
+
+ var parent = _templateElement.parentNode;
+ while (terminator != previousTerminator) {
+ var node = terminator;
+ terminator = node.previousNode;
+ _removeTemplateChild(parent, node);
+ }
+ }
+
+ void removeAllInstances() {
+ if (terminators.length == 0) return;
+
+ var previousTerminator = _templateElement;
+ var terminator = getTerminatorAt(terminators.length - 1);
+ terminators.length = 0;
+
+ var parent = _templateElement.parentNode;
+ while (terminator != previousTerminator) {
+ var node = terminator;
+ terminator = node.previousNode;
+ _removeTemplateChild(parent, node);
+ }
+ }
+
+ void clear() {
+ unobserve();
+ removeAllInstances();
+ iteratedValue = null;
+ }
+
+ getInstanceModel(model, syntax) {
+ if (syntax != null) {
+ return syntax.getInstanceModel(_templateElement, model);
+ }
+ return model;
+ }
+
+ getInstanceFragment(syntax) {
+ if (syntax != null) {
+ return syntax.getInstanceFragment(_templateElement);
+ }
+ return _templateElement.createInstance();
+ }
+
void _handleChanges(List<ListChangeRecord> splices) {
var syntax = TemplateElement.syntax[_templateElement.attributes['syntax']];
@@ -721,9 +743,7 @@
if (splice is! ListChangeRecord) continue;
for (int i = 0; i < splice.removedCount; i++) {
- var cursor = new _InstanceCursor(_templateElement, splice.index + 1);
- cursor.remove();
- instanceCount--;
+ removeInstanceAt(splice.index);
}
for (var addIndex = splice.index;
@@ -731,14 +751,13 @@
addIndex++) {
var model = getInstanceModel(iteratedValue[addIndex], syntax);
+
var fragment = getInstanceFragment(syntax);
_addBindings(fragment, model, syntax);
_addTemplateInstanceRecord(fragment, model);
- var cursor = new _InstanceCursor(_templateElement, addIndex);
- cursor.insert(fragment);
- instanceCount++;
+ insertInstanceAt(addIndex, fragment);
}
}
}
@@ -749,28 +768,9 @@
_sub = null;
}
- void clear() {
- unobserve();
-
- iteratedValue = null;
- if (instanceCount == 0) return;
-
- for (var i = 0; i < instanceCount; i++) {
- var cursor = new _InstanceCursor(_templateElement, 1);
- cursor.remove();
- }
-
- instanceCount = 0;
- }
-
void abandon() {
unobserve();
_valueBinding.cancel();
inputs.dispose();
}
}
-
-int _instanceCount(Element element) {
- var templateIterator = element._templateIterator;
- return templateIterator != null ? templateIterator.instanceCount : 0;
-}
« no previous file with comments | « tools/VERSION ('k') | tools/dom/templates/html/impl/impl_Element.darttemplate » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698