diff --git a/src/auto/injector.js b/src/auto/injector.js index b2795693634c..6b2865efa6c0 100644 --- a/src/auto/injector.js +++ b/src/auto/injector.js @@ -597,7 +597,10 @@ function createInjector(modulesToLoad) { invoke: invoke, instantiate: instantiate, get: getService, - annotate: annotate + annotate: annotate, + has: function(name) { + return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); + } }; } } diff --git a/src/ng/animation.js b/src/ng/animation.js index 9a5a5a95882a..76cf943efb94 100644 --- a/src/ng/animation.js +++ b/src/ng/animation.js @@ -51,13 +51,9 @@ function $AnimationProvider($provide) { */ return function $animation(name) { if (name) { - try { - return $injector.get(camelCase(name) + suffix); - } catch (e) { - //TODO(misko): this is a hack! we should have a better way to test if the injector has a given key. - // The issue is that the animations are optional, and if not present they should be silently ignored. - // The proper way to fix this is to add API onto the injector so that we can ask to see if a given - // animation is supported. + var animationName = camelCase(name) + suffix; + if ($injector.has(animationName)) { + return $injector.get(animationName); } } } diff --git a/src/ng/animator.js b/src/ng/animator.js index 536c93c13b7d..f2143f59dc16 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -147,8 +147,6 @@ var $AnimatorProvider = function() { * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods. */ var AnimatorService = function(scope, attrs) { - var ngAnimateAttr = attrs.ngAnimate; - var ngAnimateValue = ngAnimateAttr && scope.$eval(ngAnimateAttr); var animator = {}; /** @@ -223,24 +221,22 @@ var $AnimatorProvider = function() { return animator; function animateActionFactory(type, beforeFn, afterFn) { - var className = ngAnimateAttr - ? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type - : ''; - var animationPolyfill = $animation(className); - - var polyfillSetup = animationPolyfill && animationPolyfill.setup; - var polyfillStart = animationPolyfill && animationPolyfill.start; - - if (!className) { - return function(element, parent, after) { + return function(element, parent, after) { + var ngAnimateValue = scope.$eval(attrs.ngAnimate); + var className = ngAnimateValue + ? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type + : ''; + var animationPolyfill = $animation(className); + var polyfillSetup = animationPolyfill && animationPolyfill.setup; + var polyfillStart = animationPolyfill && animationPolyfill.start; + + if (!className) { beforeFn(element, parent, after); afterFn(element, parent, after); - } - } else { - var setupClass = className + '-setup'; - var startClass = className + '-start'; - - return function(element, parent, after) { + } else { + var setupClass = className + '-setup'; + var startClass = className + '-start'; + if (!parent) { parent = after ? after.parent() : element.parent(); } @@ -255,45 +251,48 @@ var $AnimatorProvider = function() { element.addClass(setupClass); beforeFn(element, parent, after); if (element.length == 0) return done(); - + var memento = (polyfillSetup || noop)(element); - + // $window.setTimeout(beginAnimation, 0); this was causing the element not to animate // keep at 1 for animation dom rerender $window.setTimeout(beginAnimation, 1); - - function beginAnimation() { - element.addClass(startClass); - if (polyfillStart) { - polyfillStart(element, done, memento); - } else if (isFunction($window.getComputedStyle)) { - var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; - var w3cTransitionProp = 'transition'; //one day all browsers will have this - - var durationKey = 'Duration'; - var duration = 0; - //we want all the styles defined before and after - forEach(element, function(element) { + }; + + function beginAnimation() { + element.addClass(startClass); + if (polyfillStart) { + polyfillStart(element, done, memento); + } else if (isFunction($window.getComputedStyle)) { + var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; + var w3cTransitionProp = 'transition'; //one day all browsers will have this + + var durationKey = 'Duration'; + var duration = 0; + + //we want all the styles defined before and after + forEach(element, function(element) { + if (element.nodeType == 1) { var globalStyles = $window.getComputedStyle(element) || {}; duration = Math.max( parseFloat(globalStyles[w3cTransitionProp + durationKey]) || parseFloat(globalStyles[vendorTransitionProp + durationKey]) || 0, duration); - }); - $window.setTimeout(done, duration * 1000); - } else { - done(); - } - } - - function done() { - afterFn(element, parent, after); - element.removeClass(setupClass); - element.removeClass(startClass); - element.removeData(NG_ANIMATE_CONTROLLER); + } + }); + $window.setTimeout(done, duration * 1000); + } else { + done(); } } + + function done() { + afterFn(element, parent, after); + element.removeClass(setupClass); + element.removeClass(startClass); + element.removeData(NG_ANIMATE_CONTROLLER); + } } } diff --git a/src/ng/directive/ngView.js b/src/ng/directive/ngView.js index d5ef2c71ad48..b553544c4237 100644 --- a/src/ng/directive/ngView.js +++ b/src/ng/directive/ngView.js @@ -194,9 +194,10 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c if (template) { clearContent(); - animate.enter(jqLite('
').html(template).contents(), element); + var enterElements = jqLite('').html(template).contents(); + animate.enter(enterElements, element); - var link = $compile(element.contents()), + var link = $compile(enterElements), current = $route.current, controller; diff --git a/src/ng/location.js b/src/ng/location.js index b6d14e1ac39c..1a7f42088e69 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -528,12 +528,14 @@ function $LocationProvider(){ rewrittenUrl = $location.$$rewrite(absHref); if (absHref && !elm.attr('target') && rewrittenUrl) { - // update location manually - $location.$$parse(rewrittenUrl); - $rootScope.$apply(); event.preventDefault(); - // hack to work around FF6 bug 684208 when scenario runner clicks on links - window.angular['ff-684208-preventDefault'] = true; + if (rewrittenUrl != initialUrl) { + // update location manually + $location.$$parse(rewrittenUrl); + $rootScope.$apply(); + // hack to work around FF6 bug 684208 when scenario runner clicks on links + window.angular['ff-684208-preventDefault'] = true; + } } }); diff --git a/test/auto/injectorSpec.js b/test/auto/injectorSpec.js index 6f84897bc900..8fd03be48cbb 100644 --- a/test/auto/injectorSpec.js +++ b/test/auto/injectorSpec.js @@ -58,6 +58,15 @@ describe('injector', function() { }); + it('should allow query names', function() { + providers('abc', function () { return ''; }); + + expect(injector.has('abc')).toBe(true); + expect(injector.has('xyz')).toBe(false); + expect(injector.has('$injector')).toBe(true); + }); + + it('should provide useful message if no provider', function() { expect(function() { injector.get('idontexist'); diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js index 1b393e9114f3..daab9721ea47 100644 --- a/test/ng/animatorSpec.js +++ b/test/ng/animatorSpec.js @@ -336,10 +336,29 @@ describe("$animator", function() { })); }); - it("should throw an error when an invalid ng-animate syntax is provided", inject(function($compile, $rootScope) { + describe('anmation evaluation', function () { + it('should re-evaluate the animation expression on each animation', inject(function($animator, $rootScope) { + var parent = jqLite('