diff options
| -rwxr-xr-x | angularFiles.js | 1 | ||||
| -rw-r--r-- | src/AngularPublic.js | 5 | ||||
| -rw-r--r-- | src/ng/raf.js | 22 | ||||
| -rw-r--r-- | src/ngMock/angular-mocks.js | 29 | ||||
| -rw-r--r-- | test/ng/rafSpec.js | 47 |
5 files changed, 103 insertions, 1 deletions
diff --git a/angularFiles.js b/angularFiles.js index 225c2dec..3cbc7ece 100755 --- a/angularFiles.js +++ b/angularFiles.js @@ -26,6 +26,7 @@ angularFiles = { 'src/ng/log.js', 'src/ng/parse.js', 'src/ng/q.js', + 'src/ng/raf.js', 'src/ng/rootScope.js', 'src/ng/sanitizeUri.js', 'src/ng/sce.js', diff --git a/src/AngularPublic.js b/src/AngularPublic.js index 006de9ab..3870c519 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -72,6 +72,8 @@ $SnifferProvider, $TemplateCacheProvider, $TimeoutProvider, + $$RAFProvider, + $AsyncCallbackProvider, $WindowProvider */ @@ -211,7 +213,8 @@ function publishExternalAPI(angular){ $sniffer: $SnifferProvider, $templateCache: $TemplateCacheProvider, $timeout: $TimeoutProvider, - $window: $WindowProvider + $window: $WindowProvider, + $$rAF: $$RAFProvider }); } ]); diff --git a/src/ng/raf.js b/src/ng/raf.js new file mode 100644 index 00000000..f85ee12a --- /dev/null +++ b/src/ng/raf.js @@ -0,0 +1,22 @@ +'use strict'; + +function $$RAFProvider(){ //rAF + this.$get = ['$window', function($window) { + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame; + + var raf = function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + }; + + raf.supported = !!requestAnimationFrame; + + return raf; + }]; +} diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index 9a45939c..efde0f3a 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1656,6 +1656,34 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) { return $delegate; }; +angular.mock.$RAFDecorator = function($delegate) { + var queue = []; + var rafFn = function(fn) { + var index = queue.length; + queue.push(fn); + return function() { + queue.splice(index, 1); + }; + }; + + rafFn.supported = $delegate.supported; + + rafFn.flush = function() { + if(queue.length === 0) { + throw new Error('No rAF callbacks present'); + } + + var length = queue.length; + for(var i=0;i<length;i++) { + queue[i](); + } + + queue = []; + }; + + return rafFn; +}; + /** * */ @@ -1689,6 +1717,7 @@ angular.module('ngMock', ['ng']).provider({ $rootElement: angular.mock.$RootElementProvider }).config(['$provide', function($provide) { $provide.decorator('$timeout', angular.mock.$TimeoutDecorator); + $provide.decorator('$$rAF', angular.mock.$RAFDecorator); }]); /** diff --git a/test/ng/rafSpec.js b/test/ng/rafSpec.js new file mode 100644 index 00000000..6c15e2d2 --- /dev/null +++ b/test/ng/rafSpec.js @@ -0,0 +1,47 @@ +'use strict'; + +describe('$$rAF', function() { + it('should queue and block animation frames', inject(function($$rAF) { + if(!$$rAF.supported) return; + + var message; + $$rAF(function() { + message = 'yes'; + }); + + expect(message).toBeUndefined(); + $$rAF.flush(); + expect(message).toBe('yes'); + })); + + it('should provide a cancellation method', inject(function($$rAF) { + if(!$$rAF.supported) return; + + var present = true; + var cancel = $$rAF(function() { + present = false; + }); + + expect(present).toBe(true); + cancel(); + + try { + $$rAF.flush(); + } catch(e) {}; + expect(present).toBe(true); + })); + + describe('mocks', function() { + it('should throw an error if no frames are present', inject(function($$rAF) { + if($$rAF.supported) { + var failed = false; + try { + $$rAF.flush(); + } catch(e) { + failed = true; + } + expect(failed).toBe(true); + } + })); + }); +}); |
