Chromium Code Reviews| Index: lib/src/analyzer.dart |
| diff --git a/lib/src/analyzer.dart b/lib/src/analyzer.dart |
| index 4c071611c5d3fb8b301ba13ea03562bf0987bf8b..9bdc7146f2545688d81fe5aca3939555b141b4df 100644 |
| --- a/lib/src/analyzer.dart |
| +++ b/lib/src/analyzer.dart |
| @@ -103,7 +103,8 @@ class _Analyzer extends TreeVisitor { |
| || node.attributes.containsKey('template') |
| || node.attributes.containsKey('if') |
| || node.attributes.containsKey('instantiate') |
| - || node.attributes.containsKey('iterate')) { |
| + || node.attributes.containsKey('iterate') |
| + || node.attributes.containsKey('repeat')) { |
| // template tags, conditionals and iteration are handled specially. |
| info = _createTemplateInfo(node); |
| } |
| @@ -284,7 +285,7 @@ class _Analyzer extends TreeVisitor { |
| if (node.tagName != 'template' && |
| !node.attributes.containsKey('template')) { |
| _messages.warning('template attribute is required when using if, ' |
| - 'instantiate, or iterate attributes.', |
| + 'instantiate, repeat, or iterate attributes.', |
| node.sourceSpan); |
| } |
| @@ -301,18 +302,28 @@ class _Analyzer extends TreeVisitor { |
| } |
| } |
| } |
| + |
| + // TODO(jmesserly): deprecate iterate. |
| var iterate = node.attributes['iterate']; |
| + var repeat = node.attributes['repeat']; |
| + if (repeat == null) { |
| + repeat = iterate; |
| + } else if (iterate != null) { |
| + _messages.warning('template cannot have both iterate and repeat. ' |
| + 'iterate attribute will be ignored.', node.sourceSpan); |
| + iterate = null; |
| + } |
| // Note: we issue warnings instead of errors because the spirit of HTML and |
| // Dart is to be forgiving. |
| - if (condition != null && iterate != null) { |
| + if (condition != null && repeat != null) { |
| _messages.warning('template cannot have both iteration and conditional ' |
| 'attributes', node.sourceSpan); |
| return null; |
| } |
| if (node.parent != null && node.parent.tagName == 'element' && |
| - (condition != null || iterate != null)) { |
| + (condition != null || repeat != null)) { |
| // TODO(jmesserly): would be cool if we could just refactor this, or offer |
| // a quick fix in the Editor. |
| @@ -322,8 +333,8 @@ class _Analyzer extends TreeVisitor { |
| node.attributes.forEach((k, v) { nestedTemplate.attributes[k] = v; }); |
| _messages.warning('the <template> of a custom element does not support ' |
| - '"if" or "iterate". However, you can create another template node ' |
| - 'that is a child node, for example:\n' |
| + '"if", "iterate" or "repeat". However, you can create another ' |
| + 'template node that is a child node, for example:\n' |
| '${example.outerHtml}', |
| node.parent.sourceSpan); |
| return null; |
| @@ -337,41 +348,62 @@ class _Analyzer extends TreeVisitor { |
| return node.nodes.length > 0 ? result : null; |
| } |
| - result.removeAttributes.add('template'); |
| - |
| - // TODO(jmesserly): if-conditions in attributes require injecting a |
| - // placeholder node, and a real node which is a clone. We should |
| - // consider a design where we show/hide the node instead (with care |
| - // taken not to evaluate hidden bindings). That is more along the lines |
| - // of AngularJS, and would have a cleaner DOM. See issue #142. |
| - var contentNode = node.clone(); |
| - // Clear out the original attributes. This is nice to have, but |
| - // necessary for ID because of issue #141. |
| - node.attributes.clear(); |
| - contentNode.nodes.addAll(node.nodes); |
| - |
| - // Create a new ElementInfo that is a child of "result" -- the |
| - // placeholder node. This will become result.contentInfo. |
| - visitElementInfo(_createElementInfo(contentNode, result)); |
| + _createTemplateAttributePlaceholder(node, result); |
| return result; |
| - } else if (iterate != null) { |
| - var match = new RegExp(r"(.*) in (.*)").firstMatch(iterate); |
| - if (match != null) { |
| - if (node.nodes.length == 0) return null; |
| - var result = new TemplateInfo(node, _parent, loopVariable: match[1], |
| - loopItems: match[2]); |
| - result.removeAttributes.add('iterate'); |
| - if (node.tagName != 'template') result.removeAttributes.add('template'); |
| + |
| + } else if (repeat != null) { |
| + var match = new RegExp(r"(.*) in (.*)").firstMatch(repeat); |
| + if (match == null) { |
| + _messages.warning('template iterate/repeat must be of the form: ' |
| + 'repeat="variable in list", where "variable" is your variable name ' |
| + 'and "list" is the list of items.', |
| + node.sourceSpan); |
| + return null; |
| + } |
| + |
| + if (node.nodes.length == 0) return null; |
| + var result = new TemplateInfo(node, _parent, loopVariable: match[1], |
| + loopItems: match[2], isRepeat: iterate == null); |
| + result.removeAttributes.add('iterate'); |
| + result.removeAttributes.add('repeat'); |
| + if (node.tagName == 'template') { |
| return result; |
| } |
| - _messages.warning('template iterate must be of the form: ' |
| - 'iterate="variable in list", where "variable" is your variable name ' |
| - 'and "list" is the list of items.', |
| - node.sourceSpan); |
| + |
| + result.removeAttributes.add('template'); |
|
Siggi Cherem (dart-lang)
2013/04/05 20:09:24
consider moving this inside the if (given that it
Jennifer Messerly
2013/04/05 20:34:36
oops. good catch!
|
| + if (!result.isRepeat) { |
| + // TODO(jmesserly): deprecation warning |
| + if (false) { |
| + _messages.warning('template attribute with iterate is deprecated.' |
| + 'You should use the repeat attribute on the children instead.', |
| + node.sourceSpan); |
| + } |
| + return result; |
| + } |
| + |
| + _createTemplateAttributePlaceholder(node, result); |
| + return result; |
| } |
| + |
| return null; |
| } |
| + // TODO(jmesserly): if and repeat in attributes require injecting a |
| + // placeholder node, and a real node which is a clone. We should |
| + // consider a design where we show/hide the node instead (with care |
| + // taken not to evaluate hidden bindings). That is more along the lines |
| + // of AngularJS, and would have a cleaner DOM. See issue #142. |
| + void _createTemplateAttributePlaceholder(Element node, TemplateInfo result) { |
| + result.removeAttributes.add('template'); |
| + var contentNode = node.clone(); |
| + node.attributes.clear(); |
| + contentNode.nodes.addAll(node.nodes); |
| + |
| + // Create a new ElementInfo that is a child of "result" -- the |
| + // placeholder node. This will become result.contentInfo. |
| + visitElementInfo(_createElementInfo(contentNode, result)); |
| + } |
| + |
| void visitAttribute(ElementInfo info, String name, String value) { |
| if (name.startsWith('on')) { |
| _readEventHandler(info, name, value); |