diff options
| -rw-r--r-- | docs/src/templates/css/animations.css | 4 | ||||
| -rw-r--r-- | src/ng/directive/ngInclude.js | 82 | ||||
| -rw-r--r-- | src/ngAnimate/animate.js | 8 | ||||
| -rw-r--r-- | test/ng/directive/ngIncludeSpec.js | 81 | 
4 files changed, 105 insertions, 70 deletions
diff --git a/docs/src/templates/css/animations.css b/docs/src/templates/css/animations.css index 7324a8a1..cc531ccb 100644 --- a/docs/src/templates/css/animations.css +++ b/docs/src/templates/css/animations.css @@ -15,7 +15,7 @@    overflow:hidden;  } -.slide-reveal > .ng-enter { +.slide-reveal.ng-enter {    -webkit-transition:0.5s linear all;    -moz-transition:0.5s linear all;    -o-transition:0.5s linear all; @@ -26,7 +26,7 @@    opacity:0;    top:10px;  } -.slide-reveal > .ng-enter.ng-enter-active { +.slide-reveal.ng-enter.ng-enter-active {    top:0;    opacity:1;  } diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js index d5ed1fc5..2ab9f847 100644 --- a/src/ng/directive/ngInclude.js +++ b/src/ng/directive/ngInclude.js @@ -24,8 +24,10 @@   *      access on some browsers)   *   * @animations - * enter - happens just after the ngInclude contents change and a new DOM element is created and injected into the ngInclude container - * leave - happens just after the ngInclude contents change and just before the former contents are removed from the DOM + * enter - animation is used to bring new content into the browser. + * leave - animation is used to animate existing content away. + * + * The enter and leave animation occur concurrently.   *   * @scope   * @@ -49,9 +51,9 @@         </select>         url of the template: <tt>{{template.url}}</tt>         <hr/> -       <div class="example-animate-container" -            ng-include="template.url" -            ng-animate="{enter: 'example-enter', leave: 'example-leave'}"></div> +       <div class="example-animate-container"> +         <div class="include-example" ng-include="template.url"></div> +       </div>       </div>      </file>      <file name="script.js"> @@ -63,14 +65,13 @@        }       </file>      <file name="template1.html"> -      <div>Content of template1.html</div> +      Content of template1.html      </file>      <file name="template2.html"> -      <div>Content of template2.html</div> +      Content of template2.html      </file>      <file name="animations.css"> -      .example-leave, -      .example-enter { +      .include-example.ng-enter, .include-example.ng-leave {          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; @@ -82,24 +83,21 @@          left:0;          right:0;          bottom:0; -      } - -      .example-animate-container > * {          display:block;          padding:10px;        } -      .example-enter { +      .include-example.ng-enter {          top:-50px;        } -      .example-enter.example-enter-active { +      .include-example.ng-enter.ng-enter-active {          top:0;        } -      .example-leave { +      .include-example.ng-leave {          top:0;        } -      .example-leave.example-leave-active { +      .include-example.ng-leave.ng-leave-active {          top:50px;        }      </file> @@ -115,7 +113,7 @@        });        it('should change to blank', function() {         select('template').option(''); -       expect(element('.doc-example-live [ng-include]').text()).toEqual(''); +       expect(element('.doc-example-live [ng-include]')).toBe(undefined);        });      </file>    </example> @@ -145,21 +143,26 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'    return {      restrict: 'ECA',      terminal: true, -    compile: function(element, attr) { +    transclude: 'element', +    compile: function(element, attr, transclusion) {        var srcExp = attr.ngInclude || attr.src,            onloadExp = attr.onload || '',            autoScrollExp = attr.autoscroll; -      return function(scope, element, attr) { +      return function(scope, $element) {          var changeCounter = 0, -            childScope; +            currentScope, +            currentElement; -        var clearContent = function() { -          if (childScope) { -            childScope.$destroy(); -            childScope = null; +        var cleanupLastIncludeContent = function() { +          if (currentScope) { +            currentScope.$destroy(); +            currentScope = null; +          } +          if(currentElement) { +            $animate.leave(currentElement); +            currentElement = null;            } -          $animate.leave(element.contents());          };          scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { @@ -168,28 +171,31 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'            if (src) {              $http.get(src, {cache: $templateCache}).success(function(response) {                if (thisChangeId !== changeCounter) return; +              var newScope = scope.$new(); -              if (childScope) childScope.$destroy(); -              childScope = scope.$new(); -              $animate.leave(element.contents()); +              transclusion(newScope, function(clone) { +                cleanupLastIncludeContent(); -              var contents = jqLite('<div/>').html(response).contents(); +                currentScope = newScope; +                currentElement = clone; -              $animate.enter(contents, element); -              $compile(contents)(childScope); +                currentElement.html(response); +                $animate.enter(currentElement, null, $element); +                $compile(currentElement.contents())(currentScope); -              if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { -                $anchorScroll(); -              } +                if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { +                  $anchorScroll(); +                } -              childScope.$emit('$includeContentLoaded'); -              scope.$eval(onloadExp); +                currentScope.$emit('$includeContentLoaded'); +                scope.$eval(onloadExp); +              });              }).error(function() { -              if (thisChangeId === changeCounter) clearContent(); +              if (thisChangeId === changeCounter) cleanupLastIncludeContent();              });              scope.$emit('$includeContentRequested');            } else { -            clearContent(); +            cleanupLastIncludeContent();            }          });        }; diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 93ff9d8c..201d4aab 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -47,10 +47,10 @@   *   transition:0.5s linear all;   * }   *  - * .slide > .ng-enter { }        /* starting animations for enter */ - * .slide > .ng-enter-active { } /* terminal animations for enter */ - * .slide > .ng-leave { }        /* starting animations for leave */ - * .slide > .ng-leave-active { } /* terminal animations for leave */ + * .slide.ng-enter { }        /* starting animations for enter */ + * .slide.ng-enter-active { } /* terminal animations for enter */ + * .slide.ng-leave { }        /* starting animations for leave */ + * .slide.ng-leave-active { } /* terminal animations for leave */   * </style>   *   * <!-- diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js index 286ee5af..c55fb0b3 100644 --- a/test/ng/directive/ngIncludeSpec.js +++ b/test/ng/directive/ngIncludeSpec.js @@ -17,7 +17,7 @@ describe('ngInclude', function() {    it('should trust and use literal urls', inject(function(        $rootScope, $httpBackend, $compile) { -    element = $compile('<div ng-include="\'url\'"></div>')($rootScope); +    element = $compile('<div><div ng-include="\'url\'"></div></div>')($rootScope);      $httpBackend.expect('GET', 'url').respond('template text');      $rootScope.$digest();      $httpBackend.flush(); @@ -27,7 +27,7 @@ describe('ngInclude', function() {    it('should trust and use trusted urls', inject(function($rootScope, $httpBackend, $compile, $sce) { -    element = $compile('<div ng-include="fooUrl"></div>')($rootScope); +    element = $compile('<div><div ng-include="fooUrl"></div></div>')($rootScope);      $httpBackend.expect('GET', 'http://foo.bar/url').respond('template text');      $rootScope.fooUrl = $sce.trustAsResourceUrl('http://foo.bar/url');      $rootScope.$digest(); @@ -39,20 +39,21 @@ describe('ngInclude', function() {    it('should include an external file', inject(putIntoCache('myUrl', '{{name}}'),        function($rootScope, $compile) { -    element = jqLite('<ng:include src="url"></ng:include>'); -    jqLite(document.body).append(element); +    element = jqLite('<div><ng:include src="url"></ng:include></div>'); +    var body = jqLite(document.body); +    body.append(element);      element = $compile(element)($rootScope);      $rootScope.name = 'misko';      $rootScope.url = 'myUrl';      $rootScope.$digest(); -    expect(element.text()).toEqual('misko'); -    jqLite(document.body).html(''); +    expect(body.text()).toEqual('misko'); +    body.html('');    }));    it('should support ng-include="src" syntax', inject(putIntoCache('myUrl', '{{name}}'),        function($rootScope, $compile) { -    element = jqLite('<div ng-include="url"></div>'); +    element = jqLite('<div><div ng-include="url"></div></div>');      jqLite(document.body).append(element);      element = $compile(element)($rootScope);      $rootScope.name = 'Alibaba'; @@ -89,7 +90,7 @@ describe('ngInclude', function() {    it('should remove previously included text if a falsy value is bound to src', inject(          putIntoCache('myUrl', '{{name}}'),          function($rootScope, $compile) { -    element = jqLite('<ng:include src="url"></ng:include>'); +    element = jqLite('<div><ng:include src="url"></ng:include></div>');      element = $compile(element)($rootScope);      $rootScope.name = 'igor';      $rootScope.url = 'myUrl'; @@ -112,7 +113,7 @@ describe('ngInclude', function() {      $httpBackend.whenGET('url').respond('my partial');      $rootScope.$on('$includeContentRequested', contentRequestedSpy); -    element = $compile('<ng:include src="\'url\'"></ng:include>')($rootScope); +    element = $compile('<div><div><ng:include src="\'url\'"></ng:include></div></div>')($rootScope);      $rootScope.$digest();      expect(contentRequestedSpy).toHaveBeenCalledOnce(); @@ -130,7 +131,7 @@ describe('ngInclude', function() {      $templateCache.put('url', [200, 'partial content', {}]);      $rootScope.$on('$includeContentLoaded', contentLoadedSpy); -    element = $compile('<ng:include src="\'url\'"></ng:include>')($rootScope); +    element = $compile('<div><div><ng:include src="\'url\'"></ng:include></div></div>')($rootScope);      $rootScope.$digest();      expect(contentLoadedSpy).toHaveBeenCalledOnce(); @@ -140,7 +141,7 @@ describe('ngInclude', function() {    it('should evaluate onload expression when a partial is loaded', inject(        putIntoCache('myUrl', 'my partial'),        function($rootScope, $compile) { -    element = jqLite('<ng:include src="url" onload="loaded = true"></ng:include>'); +    element = jqLite('<div><div><ng:include src="url" onload="loaded = true"></ng:include></div></div>');      element = $compile(element)($rootScope);      expect($rootScope.loaded).not.toBeDefined(); @@ -158,7 +159,7 @@ describe('ngInclude', function() {      $httpBackend.whenGET('url1').respond('partial {{$parent.url}}');      $httpBackend.whenGET('url2').respond(404); -    element = $compile('<ng:include src="url"></ng:include>')($rootScope); +    element = $compile('<div><ng:include src="url"></ng:include></div>')($rootScope);      expect(element.children().scope()).toBeFalsy();      $rootScope.url = 'url1'; @@ -185,7 +186,7 @@ describe('ngInclude', function() {    it('should do xhr request and cache it',        inject(function($rootScope, $httpBackend, $compile) { -    element = $compile('<ng:include src="url"></ng:include>')($rootScope); +    element = $compile('<div><ng:include src="url"></ng:include></div>')($rootScope);      $httpBackend.expect('GET', 'myUrl').respond('my partial');      $rootScope.url = 'myUrl'; @@ -206,7 +207,7 @@ describe('ngInclude', function() {    it('should clear content when error during xhr request',        inject(function($httpBackend, $compile, $rootScope) { -    element = $compile('<ng:include src="url">content</ng:include>')($rootScope); +    element = $compile('<div><ng:include src="url">content</ng:include></div>')($rootScope);      $httpBackend.expect('GET', 'myUrl').respond(404, '');      $rootScope.url = 'myUrl'; @@ -220,7 +221,7 @@ describe('ngInclude', function() {    it('should be async even if served from cache', inject(          putIntoCache('myUrl', 'my partial'),          function($rootScope, $compile) { -    element = $compile('<ng:include src="url"></ng:include>')($rootScope); +    element = $compile('<div><ng:include src="url"></ng:include></div>')($rootScope);      $rootScope.url = 'myUrl'; @@ -237,7 +238,7 @@ describe('ngInclude', function() {    it('should discard pending xhr callbacks if a new template is requested before the current ' +        'finished loading', inject(function($rootScope, $compile, $httpBackend) { -    element = jqLite("<ng:include src='templateUrl'></ng:include>"); +    element = jqLite("<div><ng:include src='templateUrl'></ng:include></div>");      var log = {};      $rootScope.templateUrl = 'myUrl1'; @@ -273,6 +274,10 @@ describe('ngInclude', function() {        $rootScope.tpl = 'tpl.html';      });      expect(onload).toHaveBeenCalledOnce(); + +    $rootScope.tpl = ''; +    $rootScope.$digest(); +    dealoc(element);    })); @@ -308,14 +313,14 @@ describe('ngInclude', function() {      it('should call $anchorScroll if autoscroll attribute is present', inject( -        compileAndLink('<ng:include src="tpl" autoscroll></ng:include>'), +        compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),          changeTplAndValueTo('template.html'), function() {        expect(autoScrollSpy).toHaveBeenCalledOnce();      }));      it('should call $anchorScroll if autoscroll evaluates to true', inject( -        compileAndLink('<ng:include src="tpl" autoscroll="value"></ng:include>'), +        compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),          changeTplAndValueTo('template.html', true),          changeTplAndValueTo('another.html', 'some-string'),          changeTplAndValueTo('template.html', 100), function() { @@ -325,14 +330,14 @@ describe('ngInclude', function() {      it('should not call $anchorScroll if autoscroll attribute is not present', inject( -        compileAndLink('<ng:include src="tpl"></ng:include>'), +        compileAndLink('<div><ng:include src="tpl"></ng:include></div>'),          changeTplAndValueTo('template.html'), function() {        expect(autoScrollSpy).not.toHaveBeenCalled();      }));      it('should not call $anchorScroll if autoscroll evaluates to false', inject( -        compileAndLink('<ng:include src="tpl" autoscroll="value"></ng:include>'), +        compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),          changeTplAndValueTo('template.html', false),          changeTplAndValueTo('template.html', undefined),          changeTplAndValueTo('template.html', null), function() { @@ -377,13 +382,12 @@ describe('ngInclude animations', function() {        $templateCache.put('enter', [200, '<div>data</div>', {}]);        $rootScope.tpl = 'enter';        element = $compile(html( -        '<div ' + +        '<div><div ' +            'ng-include="tpl">' + -        '</div>' +        '</div></div>'        ))($rootScope);        $rootScope.$digest(); -      item = $animate.process('leave').element;        item = $animate.process('enter').element;        expect(item.text()).toBe('data');    })); @@ -394,13 +398,12 @@ describe('ngInclude animations', function() {        $templateCache.put('enter', [200, '<div>data</div>', {}]);        $rootScope.tpl = 'enter';        element = $compile(html( -        '<div ' + +        '<div><div ' +            'ng-include="tpl">' + -        '</div>' +        '</div></div>'        ))($rootScope);        $rootScope.$digest(); -      item = $animate.process('leave').element;        item = $animate.process('enter').element;        expect(item.text()).toBe('data'); @@ -411,4 +414,30 @@ describe('ngInclude animations', function() {        expect(item.text()).toBe('data');    })); +  it('should animate two separate ngInclude elements', +    inject(function($compile, $rootScope, $templateCache, $animate) { +      var item; +      $templateCache.put('one', [200, 'one', {}]); +      $templateCache.put('two', [200, 'two', {}]); +      $rootScope.tpl = 'one'; +      element = $compile(html( +        '<div><div ' + +          'ng-include="tpl">' + +        '</div></div>' +      ))($rootScope); +      $rootScope.$digest(); + +      item = $animate.process('enter').element; +      expect(item.text()).toBe('one'); + +      $rootScope.tpl = 'two'; +      $rootScope.$digest(); + +      var itemA = $animate.process('leave').element; +      var itemB = $animate.process('enter').element; +      expect(itemA.attr('ng-include')).toBe('tpl'); +      expect(itemB.attr('ng-include')).toBe('tpl'); +      expect(itemA).not.toEqual(itemB); +  })); +  });  | 
