Chromium Code Reviews| Index: pkg/mdv/lib/src/bindings.dart |
| diff --git a/pkg/mdv/lib/src/bindings.dart b/pkg/mdv/lib/src/bindings.dart |
| index 2b40671b5e23667fd008ede789ef86f0761f40e8..f2aa0ea09a3cb8b4a3c2ed8256bcffcc5dbbb624 100644 |
| --- a/pkg/mdv/lib/src/bindings.dart |
| +++ b/pkg/mdv/lib/src/bindings.dart |
| @@ -81,7 +81,7 @@ class _CheckedBinding extends _InputBinding { |
| _CheckedBinding(element, model, path) : super(element, model, path); |
| void valueChanged(value) { |
| - element.checked = _Bindings._toBoolean(value); |
| + element.checked = _toBoolean(value); |
| } |
| void updateBinding(e) { |
| @@ -136,164 +136,162 @@ class _CheckedBinding extends _InputBinding { |
| } |
| } |
| -class _Bindings { |
| - // TODO(jmesserly): not sure what kind of boolean conversion rules to |
| - // apply for template data-binding. HTML attributes are true if they're |
| - // present. However Dart only treats "true" as true. Since this is HTML we'll |
| - // use something closer to the HTML rules: null (missing) and false are false, |
| - // everything else is true. See: https://github.com/polymer-project/mdv/issues/59 |
| - static bool _toBoolean(value) => null != value && false != value; |
| - |
| - static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { |
| - var clone = node.clone(false); // Shallow clone. |
| - if (clone is Element && clone.isTemplate) { |
| - TemplateElement.decorate(clone, node); |
| - if (syntax != null) { |
| - clone.attributes.putIfAbsent('syntax', () => syntax); |
| - } |
| - } |
| - |
| - for (var c = node.firstChild; c != null; c = c.nextNode) { |
| - clone.append(_createDeepCloneAndDecorateTemplates(c, syntax)); |
| +// TODO(jmesserly): not sure what kind of boolean conversion rules to |
| +// apply for template data-binding. HTML attributes are true if they're |
| +// present. However Dart only treats "true" as true. Since this is HTML we'll |
| +// use something closer to the HTML rules: null (missing) and false are false, |
| +// everything else is true. See: https://github.com/polymer-project/mdv/issues/59 |
| +bool _toBoolean(value) => null != value && false != value; |
| + |
| +Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { |
|
Siggi Cherem (dart-lang)
2013/06/28 20:42:00
other than indentation, did anything else change f
Jennifer Messerly
2013/06/28 20:45:39
"syntax" was renamed to "delegate" if it's not a S
Siggi Cherem (dart-lang)
2013/06/28 20:47:28
I see- will the type change too? (CustomBindingSyn
Jennifer Messerly
2013/06/28 20:48:48
yeah I'll rename it once I catch up to the "bindin
|
| + var clone = node.clone(false); // Shallow clone. |
| + if (clone is Element && clone.isTemplate) { |
| + TemplateElement.decorate(clone, node); |
| + if (syntax != null) { |
| + clone.attributes.putIfAbsent('syntax', () => syntax); |
| } |
| - return clone; |
| } |
| - static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) { |
| - if (node is Element) { |
| - _addAttributeBindings(node, model, syntax); |
| - } else if (node is Text) { |
| - _parseAndBind(node, 'text', node.text, model, syntax); |
| - } |
| - |
| - for (var c = node.firstChild; c != null; c = c.nextNode) { |
| - _addBindings(c, model, syntax); |
| - } |
| + for (var c = node.firstChild; c != null; c = c.nextNode) { |
| + clone.append(_createDeepCloneAndDecorateTemplates(c, syntax)); |
| } |
| + return clone; |
| +} |
| - static void _addAttributeBindings(Element element, model, syntax) { |
| - element.attributes.forEach((name, value) { |
| - if (value == '' && (name == 'bind' || name == 'repeat')) { |
| - value = '{{}}'; |
| - } |
| - _parseAndBind(element, name, value, model, syntax); |
| - }); |
| +void _addBindings(Node node, model, [CustomBindingSyntax delegate]) { |
| + if (node is Element) { |
| + _addAttributeBindings(node, model, delegate); |
| + } else if (node is Text) { |
| + _parseAndBind(node, 'text', node.text, model, delegate); |
| } |
| - static void _parseAndBind(Node node, String name, String text, model, |
| - CustomBindingSyntax syntax) { |
| + for (var c = node.firstChild; c != null; c = c.nextNode) { |
| + _addBindings(c, model, delegate); |
| + } |
| +} |
| - var tokens = _parseMustacheTokens(text); |
| - if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) { |
| - return; |
| +void _addAttributeBindings(Element element, model, delegate) { |
| + element.attributes.forEach((name, value) { |
| + if (value == '' && (name == 'bind' || name == 'repeat')) { |
| + value = '{{}}'; |
| } |
| + _parseAndBind(element, name, value, model, delegate); |
| + }); |
| +} |
| - // If this is a custom element, give the .xtag a change to bind. |
| - node = _nodeOrCustom(node); |
| +void _parseAndBind(Node node, String name, String text, model, |
| + CustomBindingSyntax delegate) { |
| - if (tokens.length == 1 && tokens[0].isBinding) { |
| - _bindOrDelegate(node, name, model, tokens[0].value, syntax); |
| - return; |
| - } |
| + var tokens = _parseMustacheTokens(text); |
| + if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) { |
| + return; |
| + } |
| - var replacementBinding = new CompoundBinding(); |
| - for (var i = 0; i < tokens.length; i++) { |
| - var token = tokens[i]; |
| - if (token.isBinding) { |
| - _bindOrDelegate(replacementBinding, i, model, token.value, syntax); |
| - } |
| + // If this is a custom element, give the .xtag a change to bind. |
| + node = _nodeOrCustom(node); |
| + |
| + if (tokens.length == 1 && tokens[0].isBinding) { |
| + _bindOrDelegate(node, name, model, tokens[0].value, delegate); |
| + return; |
| + } |
| + |
| + var replacementBinding = new CompoundBinding(); |
| + for (var i = 0; i < tokens.length; i++) { |
| + var token = tokens[i]; |
| + if (token.isBinding) { |
| + _bindOrDelegate(replacementBinding, i, model, token.value, delegate); |
| } |
| + } |
| - replacementBinding.combinator = (values) { |
| - var newValue = new StringBuffer(); |
| + replacementBinding.combinator = (values) { |
| + var newValue = new StringBuffer(); |
| - for (var i = 0; i < tokens.length; i++) { |
| - var token = tokens[i]; |
| - if (token.isText) { |
| - newValue.write(token.value); |
| - } else { |
| - var value = values[i]; |
| - if (value != null) { |
| - newValue.write(value); |
| - } |
| + for (var i = 0; i < tokens.length; i++) { |
| + var token = tokens[i]; |
| + if (token.isText) { |
| + newValue.write(token.value); |
| + } else { |
| + var value = values[i]; |
| + if (value != null) { |
| + newValue.write(value); |
| } |
| } |
| + } |
| - return newValue.toString(); |
| - }; |
| + return newValue.toString(); |
| + }; |
| - node.bind(name, replacementBinding, 'value'); |
| - } |
| + node.bind(name, replacementBinding, 'value'); |
| +} |
| - static void _bindOrDelegate(node, name, model, String path, |
| - CustomBindingSyntax syntax) { |
| +void _bindOrDelegate(node, name, model, String path, |
| + CustomBindingSyntax delegate) { |
| - if (syntax != null) { |
| - var delegateBinding = syntax.getBinding(model, path, name, node); |
| - if (delegateBinding != null) { |
| - model = delegateBinding; |
| - path = 'value'; |
| - } |
| + if (delegate != null) { |
| + var delegateBinding = delegate.getBinding(model, path, name, node); |
| + if (delegateBinding != null) { |
| + model = delegateBinding; |
| + path = 'value'; |
| } |
| - |
| - node.bind(name, model, path); |
| } |
| - /** |
| - * Gets the [node]'s custom [Element.xtag] if present, otherwise returns |
| - * the node. This is used so nodes can override [Node.bind], [Node.unbind], |
| - * and [Node.unbindAll] like InputElement does. |
| - */ |
| - // TODO(jmesserly): remove this when we can extend Element for real. |
| - static _nodeOrCustom(node) => node is Element ? node.xtag : node; |
| + node.bind(name, model, path); |
| +} |
| - static List<_BindingToken> _parseMustacheTokens(String s) { |
| - var result = []; |
| - var length = s.length; |
| - var index = 0, lastIndex = 0; |
| - while (lastIndex < length) { |
| - index = s.indexOf('{{', lastIndex); |
| +/** |
| + * Gets the [node]'s custom [Element.xtag] if present, otherwise returns |
| + * the node. This is used so nodes can override [Node.bind], [Node.unbind], |
| + * and [Node.unbindAll] like InputElement does. |
| + */ |
| +// TODO(jmesserly): remove this when we can extend Element for real. |
| +_nodeOrCustom(node) => node is Element ? node.xtag : node; |
| + |
| +List<_BindingToken> _parseMustacheTokens(String s) { |
| + var result = []; |
| + var length = s.length; |
| + var index = 0, lastIndex = 0; |
| + while (lastIndex < length) { |
| + index = s.indexOf('{{', lastIndex); |
| + if (index < 0) { |
| + result.add(new _BindingToken(s.substring(lastIndex))); |
| + break; |
| + } else { |
| + // There is a non-empty text run before the next path token. |
| + if (index > 0 && lastIndex < index) { |
| + result.add(new _BindingToken(s.substring(lastIndex, index))); |
| + } |
| + lastIndex = index + 2; |
| + index = s.indexOf('}}', lastIndex); |
| if (index < 0) { |
| - result.add(new _BindingToken(s.substring(lastIndex))); |
| - break; |
| - } else { |
| - // There is a non-empty text run before the next path token. |
| - if (index > 0 && lastIndex < index) { |
| - result.add(new _BindingToken(s.substring(lastIndex, index))); |
| - } |
| - lastIndex = index + 2; |
| - index = s.indexOf('}}', lastIndex); |
| - if (index < 0) { |
| - var text = s.substring(lastIndex - 2); |
| - if (result.length > 0 && result.last.isText) { |
| - result.last.value += text; |
| - } else { |
| - result.add(new _BindingToken(text)); |
| - } |
| - break; |
| + var text = s.substring(lastIndex - 2); |
| + if (result.length > 0 && result.last.isText) { |
| + result.last.value += text; |
| + } else { |
| + result.add(new _BindingToken(text)); |
| } |
| - |
| - var value = s.substring(lastIndex, index).trim(); |
| - result.add(new _BindingToken(value, isBinding: true)); |
| - lastIndex = index + 2; |
| + break; |
| } |
| + |
| + var value = s.substring(lastIndex, index).trim(); |
| + result.add(new _BindingToken(value, isBinding: true)); |
| + lastIndex = index + 2; |
| } |
| - return result; |
| } |
| + return result; |
| +} |
| - static void _addTemplateInstanceRecord(fragment, model) { |
| - if (fragment.firstChild == null) { |
| - return; |
| - } |
| +void _addTemplateInstanceRecord(fragment, model) { |
| + if (fragment.firstChild == null) { |
| + return; |
| + } |
| - var instanceRecord = new TemplateInstance( |
| - fragment.firstChild, fragment.lastChild, model); |
| + var instanceRecord = new TemplateInstance( |
| + fragment.firstChild, fragment.lastChild, model); |
| - var node = instanceRecord.firstNode; |
| - while (node != null) { |
| - _mdv(node)._templateInstance = instanceRecord; |
| - node = node.nextNode; |
| - } |
| + var node = instanceRecord.firstNode; |
| + while (node != null) { |
| + _mdv(node)._templateInstance = instanceRecord; |
| + node = node.nextNode; |
| } |
| } |
| @@ -323,7 +321,7 @@ class _TemplateIterator { |
| } |
| static Object resolveInputs(Map values) { |
| - if (values.containsKey('if') && !_Bindings._toBoolean(values['if'])) { |
| + if (values.containsKey('if') && !_toBoolean(values['if'])) { |
| return null; |
| } |
| @@ -405,29 +403,20 @@ class _TemplateIterator { |
| return instanceNodes; |
| } |
| - getInstanceModel(model, syntax) { |
| - if (syntax != null) { |
| - return syntax.getInstanceModel(_templateElement, model); |
| + getInstanceModel(model, String syntax) { |
| + var delegate = TemplateElement.syntax[syntax]; |
| + if (delegate != null) { |
| + return delegate.getInstanceModel(_templateElement, model); |
| } |
| return model; |
| } |
| - Node getInstanceFragment(syntax) { |
| - if (syntax != null) { |
| - return syntax.getInstanceFragment(_templateElement); |
| - } |
| - return _templateElement.createInstance(); |
| - } |
| + List<Node> getInstanceNodes(model, String syntax, IdentityMap instanceCache) { |
| + var instanceNodes = instanceCache.remove(model); |
| + if (instanceNodes != null) return instanceNodes; |
| - List<Node> getInstanceNodes(model, syntax) { |
| - // TODO(jmesserly): this line of code is jumping ahead of what MDV supports. |
| - // It doesn't let the custom syntax override createInstance(). |
| - var fragment = getInstanceFragment(syntax); |
| - |
| - _Bindings._addBindings(fragment, model, syntax); |
| - _Bindings._addTemplateInstanceRecord(fragment, model); |
| - |
| - var instanceNodes = fragment.nodes.toList(); |
| + var fragment = _templateElement.createInstance(model, syntax); |
| + instanceNodes = fragment.nodes.toList(); |
| fragment.nodes.clear(); |
| return instanceNodes; |
| } |
| @@ -436,7 +425,7 @@ class _TemplateIterator { |
| splices = splices.where((s) => s is ListChangeRecord); |
| var template = _templateElement; |
| - var syntax = TemplateElement.syntax[template.attributes['syntax']]; |
| + var syntax = template.attributes['syntax']; |
| if (template.parentNode == null || template.document.window == null) { |
| abandon(); |
| @@ -467,10 +456,7 @@ class _TemplateIterator { |
| var model = getInstanceModel(iteratedValue[addIndex], syntax); |
| - var instanceNodes = instanceCache.remove(model); |
| - if (instanceNodes == null) { |
| - instanceNodes = getInstanceNodes(model, syntax); |
| - } |
| + var instanceNodes = getInstanceNodes(model, syntax, instanceCache); |
| insertInstanceAt(addIndex, instanceNodes); |
| } |
| } |
| @@ -505,7 +491,7 @@ class _TemplateIterator { |
| } |
| } |
| - _Bindings._nodeOrCustom(node).unbindAll(); |
| + _nodeOrCustom(node).unbindAll(); |
| for (var c = node.firstChild; c != null; c = c.nextNode) { |
| _unbindAllRecursively(c); |
| } |