From 81030dde483bf0b4bb943f31408733f3238286ee Mon Sep 17 00:00:00 2001 From: James deBoer Date: Tue, 18 Mar 2014 16:57:56 -0700 Subject: [PATCH] fix(tagging compiler): a text child after a directive child --- lib/core_dom/element_binder.dart | 2 +- lib/core_dom/tagging_compiler.dart | 65 +++++++++++++++++++++++------- test/core_dom/compiler_spec.dart | 4 ++ 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 7a30053eb..ad14c2be5 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -400,7 +400,7 @@ class TaggedTextBinder { // Used for the tagging compiler class TaggedElementBinder { final ElementBinder binder; - final int parentBinderOffset; + int parentBinderOffset; var injector; List textBinders; diff --git a/lib/core_dom/tagging_compiler.dart b/lib/core_dom/tagging_compiler.dart index 5a578a779..bc400785a 100644 --- a/lib/core_dom/tagging_compiler.dart +++ b/lib/core_dom/tagging_compiler.dart @@ -47,7 +47,9 @@ class TaggingCompiler implements Compiler { } node = domCursor.current; + if (node.nodeType == 1) { + var templateNode = templateCursor.current as dom.Element; var taggedElementBinder = null; int taggedElementBinderIndex = parentElementBinderOffset; @@ -57,16 +59,35 @@ class TaggingCompiler implements Compiler { taggedElementBinderIndex = elementBinders.length - 1; // TODO(deboer): Hack, this sucks. - (templateCursor.current as dom.Element).classes.add('ng-binding'); + templateNode.classes.add('ng-binding'); node.classes.add('ng-binding'); } if (elementBinder.shouldCompileChildren) { if (domCursor.descend()) { templateCursor.descend(); + + var addedDummy = false; + if (taggedElementBinder == null) { + addedDummy = true; + // add a dummy to the list which may be removed later. + taggedElementBinder = _addBinder(elementBinders, + new TaggedElementBinder(null, parentElementBinderOffset)); + } + _compileView(domCursor, templateCursor, null, directives, taggedElementBinderIndex, taggedElementBinder, elementBinders); + if (addedDummy && !_isDummyBinder(taggedElementBinder)) { + // We are keeping the element binder, so add the class + // to the DOM node as well. + // + // To avoid array chrun, we remove all dummy binders at the + // end of the compilation process. + templateNode.classes.add('ng-binding'); + node.classes.add('ng-binding'); + } + domCursor.ascend(); templateCursor.ascend(); } @@ -79,17 +100,6 @@ class TaggingCompiler implements Compiler { if (elementBinder != null && elementBinder.hasDirectivesOrEvents && (node.parentNode != null && templateCursor.current.parentNode != null)) { - if (directParentElementBinder == null) { - - directParentElementBinder = _addBinder(elementBinders, - new TaggedElementBinder(null, parentElementBinderOffset)); - - assert(templateCursor.current.parentNode is dom.Element); - assert(node.parentNode is dom.Element); - - (node.parentNode as dom.Element).classes.add('ng-binding'); - (templateCursor.current.parentNode as dom.Element).classes.add('ng-binding'); - } directParentElementBinder.addText( new TaggedTextBinder(elementBinder, domCursor.index)); } else if(!(node.parentNode != null && @@ -123,7 +133,7 @@ class TaggingCompiler implements Compiler { directives, -1, null, elementBinders); viewFactory = new TaggingViewFactory(transcludeCursor.elements, - elementBinders, _perf, _expando); + _removeUnusedBinders(elementBinders), _perf, _expando); domCursor.index = domCursorIndex; if (domCursor.isInstance) { @@ -153,9 +163,36 @@ class TaggingCompiler implements Compiler { null, directives, -1, null, elementBinders); var viewFactory = new TaggingViewFactory( - templateElements, elementBinders, _perf, _expando); + templateElements, _removeUnusedBinders(elementBinders), _perf, _expando); assert(_perf.stopTimer(timerId) != false); return viewFactory; } + + _isDummyBinder(TaggedElementBinder binder) => + binder.binder == null && binder.textBinders == null; + + _removeUnusedBinders(List binders) { + // In order to support text nodes with directiveless parents, we + // add dummy ElementBinders to the list. After the entire template + // has been compiled, we remove the dummies and update the offset indices + final output = []; + final List offsetMap = []; + int outputIndex = 0; + + for (var i = 0, ii = binders.length; i < ii; i++) { + TaggedElementBinder binder = binders[i]; + if (_isDummyBinder(binder)) { + offsetMap.add(-2); + } else { + if (binder.parentBinderOffset != -1) { + binder.parentBinderOffset = offsetMap[binder.parentBinderOffset]; + } + assert(binder.parentBinderOffset != -2); + output.add(binder); + offsetMap.add(outputIndex++); + } + } + return output; + } } diff --git a/test/core_dom/compiler_spec.dart b/test/core_dom/compiler_spec.dart index 54e9b9d30..79e9ae599 100644 --- a/test/core_dom/compiler_spec.dart +++ b/test/core_dom/compiler_spec.dart @@ -173,6 +173,10 @@ void main() { expect(log).toEqual(['Ignore', 'Ignore']); }); + it('should compile a text child after a directive child', () { + _.compile('
hi{{hello}}
'); + }); + describe("interpolation", () { it('should interpolate attribute nodes', () {