diff options
| author | Matias Niemelä | 2013-06-06 01:28:50 -0400 | 
|---|---|---|
| committer | Misko Hevery | 2013-06-17 22:00:54 -0700 | 
| commit | ef22968810d555f78d3bbf7b5428757690c8cc70 (patch) | |
| tree | 1a19f2649e07406bd1988c4d915deec87073c568 | |
| parent | 07ef1667db632d0fd75472f30343255edcebf43b (diff) | |
| download | angular.js-ef22968810d555f78d3bbf7b5428757690c8cc70.tar.bz2 | |
feat(ngdocs): support popover, foldouts and foldover annotations
| -rw-r--r-- | docs/component-spec/annotationsSpec.js | 186 | ||||
| -rw-r--r-- | docs/components/angular-bootstrap/bootstrap-prettify.js | 7 | ||||
| -rw-r--r-- | docs/components/angular-bootstrap/bootstrap.js | 173 | ||||
| -rw-r--r-- | docs/content/notes/empty.tmp | 0 | ||||
| -rw-r--r-- | docs/spec/ngdocSpec.js | 22 | ||||
| -rw-r--r-- | docs/src/dom.js | 7 | ||||
| -rwxr-xr-x | docs/src/gen-docs.js | 1 | ||||
| -rw-r--r-- | docs/src/ngdoc.js | 38 | ||||
| -rw-r--r-- | docs/src/templates/css/animations.css | 23 | ||||
| -rw-r--r-- | docs/src/templates/css/docs.css | 159 | ||||
| -rw-r--r-- | docs/src/templates/index.html | 10 | ||||
| -rw-r--r-- | docs/src/templates/js/docs.js | 12 | ||||
| -rw-r--r-- | src/ng/animator.js | 4 | 
13 files changed, 636 insertions, 6 deletions
| diff --git a/docs/component-spec/annotationsSpec.js b/docs/component-spec/annotationsSpec.js new file mode 100644 index 00000000..b4c8cd9d --- /dev/null +++ b/docs/component-spec/annotationsSpec.js @@ -0,0 +1,186 @@ +describe('Docs Annotations', function() { + +  beforeEach(module('docsApp')); + +  var body; +  beforeEach(function() { +    body = angular.element(document.body); +    body.html(''); +  }); + +  describe('popover directive', function() { + +    var $scope, element; +    beforeEach(inject(function($rootScope, $compile) { +      $scope = $rootScope.$new(); +      element = angular.element( +        '<div style="margin:200px;" data-title="title_text" data-content="content_text" popover></div>' +      ); +      element.attr('id','idx'); +      body.append(element); +      $compile(element)($scope); +      $scope.$apply(); +    })); + +    it('should be hidden by default', inject(function(popoverElement) { +      expect(popoverElement.visible()).toBe(false); +    })); + +    it('should capture the click event and set the title and content and position the tip', inject(function(popoverElement) { +      element.triggerHandler('click'); +      expect(popoverElement.isSituatedAt(element)).toBe(true); +      expect(popoverElement.visible()).toBe(true); +      expect(popoverElement.title()).toBe('title_text'); +      expect(popoverElement.content()).toContain('content_text'); +      expect(popoverElement.besideElement.attr('id')).toBe('idx'); +    })); + +    it('should hide and clear the title and content if the same element is clicked again', inject(function(popoverElement) { +      //show the element +      element.triggerHandler('click'); +      expect(popoverElement.isSituatedAt(element)).toBe(true); + +      //hide the element +      element.triggerHandler('click'); +      expect(popoverElement.isSituatedAt(element)).toBe(false); +      expect(popoverElement.visible()).toBe(false); +      expect(popoverElement.title()).toBe(''); +      expect(popoverElement.content()).toBe(''); +    })); + +    it('should parse markdown content', inject(function(popoverElement, $compile) { +      element = angular.element( +        '<div style="margin:200px;" data-title="#title_text" data-content="#heading" popover></div>' +      ); +      body.append(element); +      $compile(element)($scope); +      $scope.$apply(); +      element.triggerHandler('click'); +      expect(popoverElement.title()).toBe('#title_text'); +      expect(popoverElement.content()).toBe('<h1 id="heading">heading</h1>'); +    })); + +  }); + + +  describe('foldout directive', function() { + +    var $scope, parent, element, url, window; +    beforeEach(function() { +      module(function($provide, $animationProvider) { +        $provide.value('$window', window = angular.mock.createMockWindow()); +        $animationProvider.register('foldout-enter', function($window) { +          return { +            start : function(element, done) { +              $window.setTimeout(done, 1000); +            } +          } +        }); +        $animationProvider.register('foldout-hide', function($window) { +          return { +            start : function(element, done) { +              $window.setTimeout(done, 500); +            } +          } +        }); +        $animationProvider.register('foldout-show', function($window) { +          return { +            start : function(element, done) { +              $window.setTimeout(done, 200); +            } +          } +        }); +      }); +      inject(function($rootScope, $compile, $templateCache) { +        url = '/page.html'; +        $scope = $rootScope.$new(); +        parent = angular.element('<div class="parent"></div>'); +        element = angular.element('<div data-url="' + url + '" foldout></div>'); +        body.append(parent); +        parent.append(element); +        $compile(parent)($scope); +        $scope.$apply(); +      }); +    }); + +    it('should inform that it is loading', inject(function($httpBackend) { +      $httpBackend.expect('GET', url).respond('hello'); +      element.triggerHandler('click'); + +      var kids = body.children(); +      var foldout = angular.element(kids[kids.length-1]); +      expect(foldout.html()).toContain('loading'); +    })); + +    it('should download a foldout HTML page and animate the contents', inject(function($httpBackend) { +      $httpBackend.expect('GET', url).respond('hello'); + +      element.triggerHandler('click'); +      $httpBackend.flush(); + +      window.setTimeout.expect(1).process(); +      window.setTimeout.expect(1000).process(); + +      var kids = body.children(); +      var foldout = angular.element(kids[kids.length-1]); +      expect(foldout.text()).toContain('hello'); +    })); + +    it('should hide then show when clicked again', inject(function($httpBackend) { +      $httpBackend.expect('GET', url).respond('hello'); + +      //enter +      element.triggerHandler('click'); +      $httpBackend.flush(); +      window.setTimeout.expect(1).process(); +      window.setTimeout.expect(1000).process(); + +      //hide +      element.triggerHandler('click'); +      window.setTimeout.expect(1).process(); +      window.setTimeout.expect(500).process(); + +      //show +      element.triggerHandler('click'); +      window.setTimeout.expect(1).process(); +      window.setTimeout.expect(200).process(); +    })); + +  }); + +  describe('DocsController fold', function() { + +    var window, $scope, ctrl; +    beforeEach(function() { +      module(function($provide, $animationProvider) { +        $provide.value('$window', window = angular.mock.createMockWindow()); +      }); +      inject(function($rootScope, $controller, $location, $cookies, sections) { +        $scope = $rootScope.$new(); +        ctrl = $controller('DocsController',{ +          $scope : $scope, +          $location : $location, +          $window : window, +          $cookies : $cookies, +          sections : sections +        }); +      }); +    }); + +    it('should download and reveal the foldover container', inject(function($compile, $httpBackend) { +      var url = '/page.html'; +      var fullUrl = '/notes/' + url; +      $httpBackend.expect('GET', fullUrl).respond('hello'); + +      var element = angular.element('<div ng-include="docs_fold"></div>'); +      $compile(element)($scope); +      $scope.$apply(); + +      $scope.fold(url); + +      $httpBackend.flush(); +    })); + +  }); + +}); diff --git a/docs/components/angular-bootstrap/bootstrap-prettify.js b/docs/components/angular-bootstrap/bootstrap-prettify.js index f1c3fccb..dc2a34e2 100644 --- a/docs/components/angular-bootstrap/bootstrap-prettify.js +++ b/docs/components/angular-bootstrap/bootstrap-prettify.js @@ -96,9 +96,12 @@ directive.code = function() {  directive.prettyprint = ['reindentCode', function(reindentCode) {    return {      restrict: 'C', -    terminal: true,      compile: function(element) { -      element.html(window.prettyPrintOne(reindentCode(element.html()), undefined, true)); +      var html = element.html(); +      //ensure that angular won't compile {{ curly }} values +      html = html.replace(/\{\{/g, '<span>{{</span>') +                 .replace(/\}\}/g, '<span>}}</span>'); +      element.html(window.prettyPrintOne(reindentCode(html), undefined, true));      }    };  }]; diff --git a/docs/components/angular-bootstrap/bootstrap.js b/docs/components/angular-bootstrap/bootstrap.js index 3e1c8d00..3bcc18fa 100644 --- a/docs/components/angular-bootstrap/bootstrap.js +++ b/docs/components/angular-bootstrap/bootstrap.js @@ -198,6 +198,133 @@ directive.table = function() {    };  }; +var popoverElement = function() { +  var object = { +    init : function() { +      this.element = angular.element( +        '<div class="popover popover-incode top">' + +          '<div class="arrow"></div>' + +          '<div class="popover-inner">' + +            '<div class="popover-title"><code></code></div>' + +            '<div class="popover-content"></div>' + +          '</div>' + +        '</div>' +      ); +      this.node = this.element[0]; +      this.element.css({ +        'display':'block', +        'position':'absolute' +      }); +      angular.element(document.body).append(this.element); + +      var inner = this.element.children()[1]; +      this.titleElement   = angular.element(inner.childNodes[0].firstChild); +      this.contentElement = angular.element(inner.childNodes[1]); + +      //stop the click on the tooltip +      this.element.bind('click', function(event) { +        event.preventDefault(); +        event.stopPropagation(); +      }); + +      var self = this; +      angular.element(document.body).bind('click',function(event) { +        if(self.visible()) self.hide(); +      }); +    }, + +    show : function(x,y) { +      this.element.addClass('visible'); +      this.position(x || 0, y || 0); +    }, + +    hide : function() { +      this.element.removeClass('visible'); +      this.position(-9999,-9999); +    }, + +    visible : function() { +      return this.position().y >= 0; +    }, + +    isSituatedAt : function(element) { +      return this.besideElement ? element[0] == this.besideElement[0] : false; +    }, + +    title : function(value) { +      return this.titleElement.html(value); +    }, + +    content : function(value) {  +      if(value && value.length > 0) { +        value = new Showdown.converter().makeHtml(value); +      } +      return this.contentElement.html(value); +    }, + +    positionArrow : function(position) { +      this.node.className = 'popover ' + position; +    }, + +    positionAway : function() { +      this.besideElement = null; +      this.hide(); +    }, + +    positionBeside : function(element) { +      this.besideElement = element; + +      var elm = element[0]; +      var x = elm.offsetLeft; +      var y = elm.offsetTop; +      x -= 30; +      y -= this.node.offsetHeight + 10; +      this.show(x,y); +    }, + +    position : function(x,y) { +      if(x != null && y != null) { +        this.element.css('left',x + 'px'); +        this.element.css('top', y + 'px'); +      } +      else { +        return { +          x : this.node.offsetLeft, +          y : this.node.offsetTop +        }; +      } +    } +  }; + +  object.init(); +  object.hide(); + +  return object; +}; + +directive.popover = ['popoverElement', function(popover) { +  return { +    restrict: 'A', +    priority : 500, +    link: function(scope, element, attrs) { +      element.bind('click',function(event) { +        event.preventDefault(); +        event.stopPropagation(); +        if(popover.isSituatedAt(element) && popover.visible()) { +          popover.title(''); +          popover.content(''); +          popover.positionAway(); +        } +        else { +          popover.title(attrs.title); +          popover.content(attrs.content); +          popover.positionBeside(element); +        } +      }); +    } +  } +}]; +  directive.tabPane = function() {    return {      require: '^tabbable', @@ -208,5 +335,49 @@ directive.tabPane = function() {    };  }; +directive.foldout = ['$http', '$animator','$window', function($http, $animator, $window) { +  return { +    restrict: 'A', +    priority : 500, +    link: function(scope, element, attrs) { +      var animator = $animator(scope, { ngAnimate: "'foldout'" }); +      var container, loading, url = attrs.url; +      if(/\/build\//.test($window.location.href)) { +        url = '/build/docs' + url; +      } +      element.bind('click',function() { +        scope.$apply(function() { +          if(!container) { +            if(loading) return; + +            loading = true; +            var par = element.parent(); +            container = angular.element('<div class="foldout">loading...</div>'); +            animator.enter(container, null, par); + +            $http.get(url, { cache : true }).success(function(html) { +              loading = false; + +              html = '<div class="foldout-inner">' + +                      '<div calss="foldout-arrow"></div>' + +                      html + +                     '</div>'; +              container.html(html); + +              //avoid showing the element if the user has already closed it +              if(container.css('display') == 'block') { +                container.css('display','none'); +                animator.show(container); +              } +            }); +          } +          else { +            container.css('display') == 'none' ? animator.show(container) : animator.hide(container); +          } +        }); +      }); +    } +  } +}]; -angular.module('bootstrap', []).directive(directive); +angular.module('bootstrap', []).directive(directive).factory('popoverElement', popoverElement); diff --git a/docs/content/notes/empty.tmp b/docs/content/notes/empty.tmp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/docs/content/notes/empty.tmp diff --git a/docs/spec/ngdocSpec.js b/docs/spec/ngdocSpec.js index 9eed24ca..7a038e89 100644 --- a/docs/spec/ngdocSpec.js +++ b/docs/spec/ngdocSpec.js @@ -196,6 +196,28 @@ describe('ngdoc', function() {      }); +    describe('inline annotations', function() { +      it('should convert inline docs annotations into proper HTML', function() { +        expect(new Doc().markdown( +          "<pre>\n//!annotate supertext\n<br />\n</pre>" +          ) +        ).toContain('data-popover data-content="supertext"') +      }); + +      it('should allow for a custom regular expression for matching', function() { +        expect(new Doc().markdown( +          "<pre>\n//!annotate=\"soon\" supertext\n<p>soon</p>\n</pre>" +          ) +        ).toContain('data-popover data-content="supertext" data-title="Info">soon</div>') +      }); + +      it('should allow for a custom title to be set', function() { +        expect(new Doc().markdown( +          "<pre>\n//!annotate=\"soon\" coming soon|supertext\n<p>soon</p>\n</pre>" +          ) +        ).toContain('data-popover data-content="supertext" data-title="coming soon">soon</div>') +      }); +    });    });    describe('trim', function() { diff --git a/docs/src/dom.js b/docs/src/dom.js index 94048120..897a1831 100644 --- a/docs/src/dom.js +++ b/docs/src/dom.js @@ -8,7 +8,12 @@ exports.htmlEscape = htmlEscape;  //////////////////////////////////////////////////////////  function htmlEscape(text){ -  return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); +  return text +          .replace(/&/g, '&') +          .replace(/</g, '<') +          .replace(/>/g, '>') +          .replace(/\{\{/g, '<span>{{</span>') +          .replace(/\}\}/g, '<span>}}</span>');  } diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index 4fd3d4f2..52d1f629 100755 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -44,6 +44,7 @@ writer.makeDir('build/docs/', true).then(function() {  function writeTheRest(writesFuture) {    var metadata = ngdoc.metadata(docs); +  writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));    writesFuture.push(writer.symlinkTemplate('css', 'dir'));    writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));    writesFuture.push(writer.symlinkTemplate('js', 'dir')); diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js index c34b8475..1870f87c 100644 --- a/docs/src/ngdoc.js +++ b/docs/src/ngdoc.js @@ -225,6 +225,44 @@ Doc.prototype = {      text = text.replace(/(?:<p>)?(REPLACEME\d+)(?:<\/p>)?/g, function(_, id) {        return placeholderMap[id];      }); + +    //!annotate CONTENT +    //!annotate="REGEX" CONTENT +    //!annotate="REGEX" TITLE|CONTENT +    text = text.replace(/\n?\/\/!annotate\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, +      function(_, pattern, content, line) { +        var pattern = new RegExp(pattern || '.+'); +        var title, text, split = content.split(/\|/); +        if(split.length > 1) { +          text = split[1]; +          title = split[0]; +        } +        else { +          title = 'Info'; +          text = content; +        } +        return "\n" + line.replace(pattern, function(match) { +          return '<div class="nocode nocode-content" data-popover ' +  +                   'data-content="' + text + '" ' +  +                   'data-title="' + title + '">' + +                      match + +                 '</div>'; +        }); +      } +    ); + +    //!details /path/to/local/docs/file.html +    //!details="REGEX" /path/to/local/docs/file.html +    text = text.replace(/\/\/!details\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, +      function(_, pattern, url, line) { +        url = '/notes/' + url; +        var pattern = new RegExp(pattern || '.+'); +        return line.replace(pattern, function(match) { +          return '<div class="nocode nocode-content" data-foldout data-url="' + url + '">' + match + '</div>'; +        }); +      } +    ); +      return text;    }, diff --git a/docs/src/templates/css/animations.css b/docs/src/templates/css/animations.css index d8c983a3..2d54bbfb 100644 --- a/docs/src/templates/css/animations.css +++ b/docs/src/templates/css/animations.css @@ -79,3 +79,26 @@    -o-transition: color 0 ease-in; /* opera is special :) */    transition: none;  } + +.foldout-show, .foldout-enter, .foldout-hide { +  -webkit-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  -moz-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  -o-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +} + +.foldout-show, .foldout-enter { +  opacity:0; +} + +.foldout-show.foldout-show-active, .foldout-hide.foldout-hide-active { +  opacity:1; +} + +.foldout-hide { +  opacity:1; +} + +.foldout-hide.foldout-hide-active { +  opacity:0; +} diff --git a/docs/src/templates/css/docs.css b/docs/src/templates/css/docs.css index a98f7429..1b87c551 100644 --- a/docs/src/templates/css/docs.css +++ b/docs/src/templates/css/docs.css @@ -303,3 +303,162 @@ ul.events > li > h3 {    top:0;    right:0;  } + +.nocode-content { +  cursor:pointer; +  display:inline-block; +  -webkit-border-radius: 3px; +  -moz-border-radius: 3px; +  border-radius: 3px; + +  -webkit-transition:0.5s linear all; +  -moz-transition:0.5s linear all; +  -o-transition:0.5s linear all; +  transition:0.5s linear all; +  color: #223f7a; +  background:#ddd; +  border: 1px solid #ccc; +} + +.nocode-content:hover { +  background-color: #99c2ff; +  border: 1px solid #e1e1e8; +} + +.popover-incode .popover-inner { +  width:auto; +  min-width:200px; +  max-width:500px; +} + +.popover-incode { +  -webkit-transition:0.2s linear opacity; +  -moz-transition:0.2s linear opacity; +  -o-transition:0.2s linear opacity; +  transition:0.2s linear opacity; +  opacity:0; +} + +.popover-incode.visible { +  opacity:1; +} + +.popover-incode code,  +.popover-incode pre { +  white-space:nowrap; +} + +.popover-incode .arrow { +  left:50px!important; +} + +.foldover-content { +  display:none; +} + +.foldout:after { +  content:""; +  position:absolute; +  left:50%; +  top:-1px; +  margin-left:-10px; +  border-width:10px; +  border-style:solid; +  border-color:#f7f7f9 transparent transparent; +} + +.foldout:before { +  content:""; +  position:absolute; +  left:50%; +  top:0px; +  margin-left:-10px; +  border-width:10px; +  border-style:solid; +  border-color:#bbb transparent transparent; +} + +.foldout { +  padding:8px 15px 5px; +  position:relative; +  background:#eee; +  white-space:normal; +  box-shadow:inset 0 0 20px #ccc; +  border-top:1px solid #bbb; +} + +.prettyprint { +  padding-right:0!important; +  padding-bottom:0!important; +} + +pre ol li { +  padding-bottom:2px; +  padding-right:5px; +} + +#docs-fold { +  position:absolute; +  top:0; +  right:0; +  width:500px; +  min-height:100%; +  padding-top:50px; +  padding:50px 20px 20px 20px; +  background:white; +  border-left:1px solid #999; +  box-shadow:0 0 10px #555; +  z-index:1002; +} + +#docs-fold.fold-show { +  -webkit-transition:0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  -moz-transition:0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  -o-transition:0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +  transition:0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) all; +} + +#docs-fold.fold-show { +  right:-200px; +  opacity:0; +} + +#docs-fold.fold-show.fold-show-active { +  right:0; +  opacity:1; +} + +#docs-fold-overlay { +  background:rgba(255,255,255,0.5); +  position:fixed; +  left:0; +  bottom:0; +  right:0; +  top:0; +  z-index:1001; +  cursor:pointer; +} + +.fixed_body { +  position:fixed; +  top:0; +  z-index:1000; +  left:0; +  right:0; +} + +#docs-fold-close { +  z-index: 1029; +  position: absolute; +  left: -30px; +  top: 60px; +  cursor:pointer; +  text-align: center; +  width:50px; +  line-height:50px; +  font-size: 2em; +  background: #fff; +  box-shadow:-6px 0 5px #555; +  display:block; +  border-radius:10px; +} diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html index 3b75207e..8e2fbc37 100644 --- a/docs/src/templates/index.html +++ b/docs/src/templates/index.html @@ -198,6 +198,15 @@      </div>    </header> + <div id="docs-fold-overlay" ng-show="docs_fold" ng-click="fold(null)"></div> + <div id="docs-fold" ng-show="docs_fold" ng-animate="'fold'"> +   <div id="docs-fold-close" ng-click="fold(null)"> +     <span class="icon-remove-sign"></span> +   </div> +   <div ng-include="docs_fold"></div> + </div> + +<div ng-class="{fixed_body:docs_fold}">    <div role="main" class="container">      <div class="row clear-navbar"></div> @@ -359,6 +368,7 @@        </p>      </div>    </footer> +</div>  </body>  </html> diff --git a/docs/src/templates/js/docs.js b/docs/src/templates/js/docs.js index 63ad31f4..97fea067 100644 --- a/docs/src/templates/js/docs.js +++ b/docs/src/templates/js/docs.js @@ -411,6 +411,18 @@ docsApp.serviceFactory.sections = function sections() {  docsApp.controller.DocsController = function($scope, $location, $window, $cookies, sections) { +  $scope.fold = function(url) { +    if(url) { +      $scope.docs_fold = '/notes/' + url; +      if(/\/build/.test($window.location.href)) { +        $scope.docs_fold = '/build/docs' + $scope.docs_fold; +      } +      window.scrollTo(0,0); +    } +    else { +      $scope.docs_fold = null; +    } +  };    var OFFLINE_COOKIE_NAME = 'ng-offline',        DOCS_PATH = /^\/(api)|(guide)|(cookbook)|(misc)|(tutorial)/,        INDEX_PATH = /^(\/|\/index[^\.]*.html)$/, diff --git a/src/ng/animator.js b/src/ng/animator.js index d8495f2d..5ad0535f 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -33,11 +33,11 @@   * <ANY ng-directive ng-animate="{event1: 'animation-name', event2: 'animation-name-2'}"></ANY>   *   * <!-- you can also use a short hand --> + * //!annotate="animation" ngAnimate|This *expands* to `{ enter: 'animation-enter', leave: 'animation-leave', ...}`</strong>   * <ANY ng-directive ng-animate=" 'animation' "></ANY> - * <!-- which expands to --> - * <ANY ng-directive ng-animate="{ enter: 'animation-enter', leave: 'animation-leave', ...}"></ANY>   *   * <!-- keep in mind that ng-animate can take expressions --> + * //!annotate="computeCurrentAnimation\(\)" Scope Function|This will be called each time the scope changes...   * <ANY ng-directive ng-animate=" computeCurrentAnimation() "></ANY>   * </pre>   * | 
