diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..d5d452e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,17 @@ + + +**What version of angular-loading-bar are you using?** + +**What version of AngularJS are you using?** + +**What browsers are affected?** + +**Please provide either a JSFiddle, Plunkr example that replicates the issue** + +**Please describe the issue** + +**What did you expect to happen?** + +**What actually happened?** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..3c9e4b6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ + + +**What issue is this PR resolving? Alternatively, please describe the bugfix/enhancement this PR aims to provide** + + +**Have you provided unit tests that either prove the bugfix or cover the enhancement?** + +**Related issues** + diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe594c..8d124d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ Changelog ========== +## 0.9.0 +- resolved issue with parentSelector when parent has no children +([#244](https://github.com/chieffancypants/angular-loading-bar/pull/244)) +([#251](https://github.com/chieffancypants/angular-loading-bar/issues/251)) +([#239](https://github.com/chieffancypants/angular-loading-bar/issues/239)) +([#179](https://github.com/chieffancypants/angular-loading-bar/issues/179)) +- added style property to package.json +([#271](https://github.com/chieffancypants/angular-loading-bar/pull/271)) +([#231](https://github.com/chieffancypants/angular-loading-bar/pull/231)) +- Removed duplicated property declaration in CSS +([#226](https://github.com/chieffancypants/angular-loading-bar/pull/226)) + + + ## 0.8.0 - auto incrementing is now configurable ([#209](https://github.com/chieffancypants/angular-loading-bar/pull/209)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..aada2cc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +### Submitting a PR +Excellent! You've chosen to help advance the project by either fixing a bug, or implementing a new feature. Before you put forth any work on a PR, please follow these steps: + +1. Ensure a similar PR has not already been opened or closed. +1. Clearly define the intent of the PR. The more detail, the more likelihood of it getting merged. +1. Is this a feature that would benefit the **majority** of users? This is a small library, and it intends to stay that way. If you do not believe most users of the project will benefit from your work, it should probably be added in your own application. +1. Be sure to include test cases that cover all newly introduced code. This part is essential, as any PRs without tests will be closed. +1. Link any [issues](https://github.com/chieffancypants/angular-loading-bar/issues) that are addressed by the PR. + +### Submitting a bug report +If you believe you've found a bug in the source code, and are unable to fix it yourself (by submitting a PR) please follow these steps: + +1. Ensure the bug has not already been reported by searching the [issues](https://github.com/chieffancypants/angular-loading-bar/issues) +1. Submit a reduced test case that clearly demonstrates the bug. This means submitting a plunker or jsfiddle with the bare minimum of code necessary to reproduce the bug. Without this, your issue may be closed as invalid. +1. Include any relevant browser information +1. If you're unable to fix this bug yourself, but can point to why it is occuring, please send that information along (line# or commit) + diff --git a/Gruntfile.js b/Gruntfile.js index d412686..d23ddf1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -51,6 +51,14 @@ module.exports = function(grunt) { dir: 'coverage/' } }, + unit14: { + configFile: 'test/karma-angular-1.4.conf.js', + singleRun: true, + coverageReporter: { + type: 'text', + dir: 'coverage/' + } + }, watch: { configFile: 'test/karma-angular-1.2.conf.js', singleRun: false, @@ -87,7 +95,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-karma'); - grunt.registerTask('default', ['jshint', 'karma:unit', 'karma:unit13', 'uglify', 'cssmin', 'concat:build']); + grunt.registerTask('default', ['jshint', 'karma:unit', 'karma:unit13', 'karma:unit14', 'uglify', 'cssmin', 'concat:build']); grunt.registerTask('test', ['karma:watch']); grunt.registerTask('build', ['default']); diff --git a/README.md b/README.md index 65c20b9..cb409bd 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This is mostly cool because you simply include it in your app, and it works. Th ```js angular.module('myApp', ['angular-loading-bar', 'ngAnimate']) ``` - + 2. include the supplied JS and CSS file (or create your own CSS to override defaults). ```html @@ -38,12 +38,12 @@ $ npm install angular-loading-bar #### via CDN: ```html - - + + ``` ## Why I created this -There are a couple projects similar to this out there, but none were ideal for me. All implementations I've seen require that you maintain state on behalf of the loading bar. In other words, you're setting the value of the loading/progress bar manually from potentially many different locations. This becomes complicated when you have a very large application with several services all making independant XHR requests. It becomes even more complicated if you want these services to be loosly coupled. +There are a couple projects similar to this out there, but none were ideal for me. All implementations I've seen require that you maintain state on behalf of the loading bar. In other words, you're setting the value of the loading/progress bar manually from potentially many different locations. This becomes complicated when you have a very large application with several services all making independent XHR requests. It becomes even more complicated if you want these services to be loosly coupled. Additionally, Angular was created as a highly testable framework, so it pains me to see Angular modules without tests. That is not the case here as this loading bar ships with 100% code coverage. @@ -89,6 +89,27 @@ angular.module('myApp', ['angular-loading-bar']) }]) ``` +#### Position the template: +If you'd like to position the loadingBar or spinner, provide a CSS selector to the element you'd like the template injected into. The default is the `` element: + +```js +angular.module('myApp', ['angular-loading-bar']) + .config(['cfpLoadingBarProvider', function(cfpLoadingBarProvider) { + cfpLoadingBarProvider.parentSelector = '#loading-bar-container'; + cfpLoadingBarProvider.spinnerTemplate = '
Custom Loading Message...
'; + }]) +``` +```html +
+``` + +Also keep in mind you'll likely want to change the CSS to reflect it's new position, so you'll need to override the default CSS: +```css +#loading-bar .bar { + position: relative; +} +``` + #### Latency Threshold By default, the loading bar will only display after it has been waiting for a response for over 100ms. This helps keep things feeling snappy, and avoids the annoyingness of showing a loading bar every few seconds on really chatty applications. This threshold is totally configurable: @@ -161,7 +182,7 @@ cfpLoadingBar.inc(); // increments the loading bar by a random amount. // It is important to note that the auto incrementing will begin to slow down as // the progress increases. This is to prevent the loading bar from appearing -// completed (or almost complete) before the XHR request has responded. +// completed (or almost complete) before the XHR request has responded. cfpLoadingBar.set(0.3) // Set the loading bar to 30% cfpLoadingBar.status() // Returns the loading bar's progress. @@ -183,7 +204,7 @@ The loading bar broadcasts the following events over $rootScope allowing further **`cfpLoadingBar:completed`** triggered once when the all XHR requests have returned (either successfully or not) -## Credits: +## Credits: Credit goes to [rstacruz](https://github.com/rstacruz) for his excellent [nProgress](https://github.com/rstacruz/nprogress). ## License: diff --git a/bower.json b/bower.json index c168bfe..f1d1f7a 100644 --- a/bower.json +++ b/bower.json @@ -17,10 +17,13 @@ "devDependencies": { "angular": "~1.2.23", "angular-1.3": "angular#1.3", + "angular-1.4": "angular#1.4", "angular-mocks": "~1.2.9", "angular-mocks-1.3": "angular-mocks#1.3", + "angular-mocks-1.4": "angular-mocks#1.4", "angular-animate": "~1.2.9", - "angular-animate-1.3": "angular-animate#1.3" + "angular-animate-1.3": "angular-animate#1.3", + "angular-animate-1.4": "angular-animate#1.4" }, "resolutions": { "angular": "~1.2.23" diff --git a/build/loading-bar.css b/build/loading-bar.css index ccc0cac..72408d1 100644 --- a/build/loading-bar.css +++ b/build/loading-bar.css @@ -1,7 +1,7 @@ /*! - * angular-loading-bar v0.8.0 + * angular-loading-bar v0.9.0 * https://chieffancypants.github.io/angular-loading-bar - * Copyright (c) 2015 Wes Cruver + * Copyright (c) 2016 Wes Cruver * License: MIT */ @@ -105,6 +105,6 @@ 100% { -ms-transform: rotate(360deg); transform: rotate(360deg); } } @keyframes loading-bar-spinner { - 0% { transform: rotate(0deg); transform: rotate(0deg); } - 100% { transform: rotate(360deg); transform: rotate(360deg); } + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } diff --git a/build/loading-bar.js b/build/loading-bar.js index 9542938..01630c0 100644 --- a/build/loading-bar.js +++ b/build/loading-bar.js @@ -1,7 +1,7 @@ /*! - * angular-loading-bar v0.8.0 + * angular-loading-bar v0.9.0 * https://chieffancypants.github.io/angular-loading-bar - * Copyright (c) 2015 Wes Cruver + * Copyright (c) 2016 Wes Cruver * License: MIT */ /* @@ -120,8 +120,8 @@ angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar']) if (!response.config.ignoreLoadingBar && !isCached(response.config)) { reqsCompleted++; - $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response}); if (reqsCompleted >= reqsTotal) { + $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response}); setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); @@ -138,8 +138,8 @@ angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar']) if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) { reqsCompleted++; - $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection}); if (reqsCompleted >= reqsTotal) { + $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection}); setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); @@ -200,7 +200,6 @@ angular.module('cfp.loadingBar', []) $animate = $injector.get('$animate'); } - var $parent = $document.find($parentSelector).eq(0); $timeout.cancel(completeTimeout); // do not continually broadcast the started event: @@ -208,15 +207,28 @@ angular.module('cfp.loadingBar', []) return; } + var document = $document[0]; + var parent = document.querySelector ? + document.querySelector($parentSelector) + : $document.find($parentSelector)[0] + ; + + if (! parent) { + parent = document.getElementsByTagName('body')[0]; + } + + var $parent = angular.element(parent); + var $after = parent.lastChild && angular.element(parent.lastChild); + $rootScope.$broadcast('cfpLoadingBar:started'); started = true; if (includeBar) { - $animate.enter(loadingBarContainer, $parent, angular.element($parent[0].lastChild)); + $animate.enter(loadingBarContainer, $parent, $after); } if (includeSpinner) { - $animate.enter(spinner, $parent, angular.element($parent[0].lastChild)); + $animate.enter(spinner, $parent, loadingBarContainer); } _set(startSize); @@ -295,9 +307,7 @@ angular.module('cfp.loadingBar', []) $animate = $injector.get('$animate'); } - $rootScope.$broadcast('cfpLoadingBar:completed'); _set(1); - $timeout.cancel(completeTimeout); // Attempt to aggregate any start/complete calls within 500ms: @@ -307,6 +317,7 @@ angular.module('cfp.loadingBar', []) promise.then(_completeAnimation); } $animate.leave(spinner); + $rootScope.$broadcast('cfpLoadingBar:completed'); }, 500); } diff --git a/build/loading-bar.min.js b/build/loading-bar.min.js index 5026baf..e4b18ad 100644 --- a/build/loading-bar.min.js +++ b/build/loading-bar.min.js @@ -1,7 +1,7 @@ /*! - * angular-loading-bar v0.8.0 + * angular-loading-bar v0.9.0 * https://chieffancypants.github.io/angular-loading-bar - * Copyright (c) 2015 Wes Cruver + * Copyright (c) 2016 Wes Cruver * License: MIT */ -!function(){"use strict";angular.module("angular-loading-bar",["cfp.loadingBarInterceptor"]),angular.module("chieffancypants.loadingBar",["cfp.loadingBarInterceptor"]),angular.module("cfp.loadingBarInterceptor",["cfp.loadingBar"]).config(["$httpProvider",function(a){var b=["$q","$cacheFactory","$timeout","$rootScope","$log","cfpLoadingBar",function(b,c,d,e,f,g){function h(){d.cancel(j),g.complete(),l=0,k=0}function i(b){var d,e=c.get("$http"),f=a.defaults;!b.cache&&!f.cache||b.cache===!1||"GET"!==b.method&&"JSONP"!==b.method||(d=angular.isObject(b.cache)?b.cache:angular.isObject(f.cache)?f.cache:e);var g=void 0!==d?void 0!==d.get(b.url):!1;return void 0!==b.cached&&g!==b.cached?b.cached:(b.cached=g,g)}var j,k=0,l=0,m=g.latencyThreshold;return{request:function(a){return a.ignoreLoadingBar||i(a)||(e.$broadcast("cfpLoadingBar:loading",{url:a.url}),0===k&&(j=d(function(){g.start()},m)),k++,g.set(l/k)),a},response:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),l>=k?h():g.set(l/k)),a):(f.error("Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),a)},responseError:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),l>=k?h():g.set(l/k)),b.reject(a)):(f.error("Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),b.reject(a))}}}];a.interceptors.push(b)}]),angular.module("cfp.loadingBar",[]).provider("cfpLoadingBar",function(){this.autoIncrement=!0,this.includeSpinner=!0,this.includeBar=!0,this.latencyThreshold=100,this.startSize=.02,this.parentSelector="body",this.spinnerTemplate='
',this.loadingBarTemplate='
',this.$get=["$injector","$document","$timeout","$rootScope",function(a,b,c,d){function e(){k||(k=a.get("$animate"));var e=b.find(n).eq(0);c.cancel(m),r||(d.$broadcast("cfpLoadingBar:started"),r=!0,v&&k.enter(o,e,angular.element(e[0].lastChild)),u&&k.enter(q,e,angular.element(e[0].lastChild)),f(w))}function f(a){if(r){var b=100*a+"%";p.css("width",b),s=a,t&&(c.cancel(l),l=c(function(){g()},250))}}function g(){if(!(h()>=1)){var a=0,b=h();a=b>=0&&.25>b?(3*Math.random()+3)/100:b>=.25&&.65>b?3*Math.random()/100:b>=.65&&.9>b?2*Math.random()/100:b>=.9&&.99>b?.005:0;var c=h()+a;f(c)}}function h(){return s}function i(){s=0,r=!1}function j(){k||(k=a.get("$animate")),d.$broadcast("cfpLoadingBar:completed"),f(1),c.cancel(m),m=c(function(){var a=k.leave(o,i);a&&a.then&&a.then(i),k.leave(q)},500)}var k,l,m,n=this.parentSelector,o=angular.element(this.loadingBarTemplate),p=o.find("div").eq(0),q=angular.element(this.spinnerTemplate),r=!1,s=0,t=this.autoIncrement,u=this.includeSpinner,v=this.includeBar,w=this.startSize;return{start:e,set:f,status:h,inc:g,complete:j,autoIncrement:this.autoIncrement,includeSpinner:this.includeSpinner,latencyThreshold:this.latencyThreshold,parentSelector:this.parentSelector,startSize:this.startSize}}]})}(); \ No newline at end of file +!function(){"use strict";angular.module("angular-loading-bar",["cfp.loadingBarInterceptor"]),angular.module("chieffancypants.loadingBar",["cfp.loadingBarInterceptor"]),angular.module("cfp.loadingBarInterceptor",["cfp.loadingBar"]).config(["$httpProvider",function(a){var b=["$q","$cacheFactory","$timeout","$rootScope","$log","cfpLoadingBar",function(b,c,d,e,f,g){function h(){d.cancel(j),g.complete(),l=0,k=0}function i(b){var d,e=c.get("$http"),f=a.defaults;!b.cache&&!f.cache||b.cache===!1||"GET"!==b.method&&"JSONP"!==b.method||(d=angular.isObject(b.cache)?b.cache:angular.isObject(f.cache)?f.cache:e);var g=void 0!==d?void 0!==d.get(b.url):!1;return void 0!==b.cached&&g!==b.cached?b.cached:(b.cached=g,g)}var j,k=0,l=0,m=g.latencyThreshold;return{request:function(a){return a.ignoreLoadingBar||i(a)||(e.$broadcast("cfpLoadingBar:loading",{url:a.url}),0===k&&(j=d(function(){g.start()},m)),k++,g.set(l/k)),a},response:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,l>=k?(e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),h()):g.set(l/k)),a):(f.error("Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),a)},responseError:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,l>=k?(e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),h()):g.set(l/k)),b.reject(a)):(f.error("Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),b.reject(a))}}}];a.interceptors.push(b)}]),angular.module("cfp.loadingBar",[]).provider("cfpLoadingBar",function(){this.autoIncrement=!0,this.includeSpinner=!0,this.includeBar=!0,this.latencyThreshold=100,this.startSize=.02,this.parentSelector="body",this.spinnerTemplate='
',this.loadingBarTemplate='
',this.$get=["$injector","$document","$timeout","$rootScope",function(a,b,c,d){function e(){if(k||(k=a.get("$animate")),c.cancel(m),!r){var e=b[0],g=e.querySelector?e.querySelector(n):b.find(n)[0];g||(g=e.getElementsByTagName("body")[0]);var h=angular.element(g),i=g.lastChild&&angular.element(g.lastChild);d.$broadcast("cfpLoadingBar:started"),r=!0,v&&k.enter(o,h,i),u&&k.enter(q,h,o),f(w)}}function f(a){if(r){var b=100*a+"%";p.css("width",b),s=a,t&&(c.cancel(l),l=c(function(){g()},250))}}function g(){if(!(h()>=1)){var a=0,b=h();a=b>=0&&.25>b?(3*Math.random()+3)/100:b>=.25&&.65>b?3*Math.random()/100:b>=.65&&.9>b?2*Math.random()/100:b>=.9&&.99>b?.005:0;var c=h()+a;f(c)}}function h(){return s}function i(){s=0,r=!1}function j(){k||(k=a.get("$animate")),f(1),c.cancel(m),m=c(function(){var a=k.leave(o,i);a&&a.then&&a.then(i),k.leave(q),d.$broadcast("cfpLoadingBar:completed")},500)}var k,l,m,n=this.parentSelector,o=angular.element(this.loadingBarTemplate),p=o.find("div").eq(0),q=angular.element(this.spinnerTemplate),r=!1,s=0,t=this.autoIncrement,u=this.includeSpinner,v=this.includeBar,w=this.startSize;return{start:e,set:f,status:h,inc:g,complete:j,autoIncrement:this.autoIncrement,includeSpinner:this.includeSpinner,latencyThreshold:this.latencyThreshold,parentSelector:this.parentSelector,startSize:this.startSize}}]})}(); \ No newline at end of file diff --git a/example/index.html b/example/index.html index 0831237..ba46e39 100644 --- a/example/index.html +++ b/example/index.html @@ -2,8 +2,8 @@ - - + + diff --git a/package.json b/package.json index ef62d9b..6529008 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,13 @@ { "name": "angular-loading-bar", - "version": "0.8.0", + "version": "0.9.0", "description": "An automatic loading bar for AngularJS", "main": "index.js", + "files": [ + "build/loading-bar.js", + "build/loading-bar.css" + ], + "style": "build/loading-bar.css", "directories": { "example": "example", "test": "test" @@ -37,6 +42,5 @@ "grunt-contrib-cssmin": "~0.12.0", "grunt-karma": "~0.11.0", "grunt-contrib-concat": "^0.5.0" - }, - "style" : "build/loading-bar.css" + } } diff --git a/src/loading-bar.js b/src/loading-bar.js index 364ca82..44e092a 100644 --- a/src/loading-bar.js +++ b/src/loading-bar.js @@ -114,8 +114,8 @@ angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar']) if (!response.config.ignoreLoadingBar && !isCached(response.config)) { reqsCompleted++; - $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response}); if (reqsCompleted >= reqsTotal) { + $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response}); setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); @@ -132,8 +132,8 @@ angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar']) if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) { reqsCompleted++; - $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection}); if (reqsCompleted >= reqsTotal) { + $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection}); setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); @@ -194,7 +194,6 @@ angular.module('cfp.loadingBar', []) $animate = $injector.get('$animate'); } - var $parent = $document.find($parentSelector).eq(0); $timeout.cancel(completeTimeout); // do not continually broadcast the started event: @@ -202,15 +201,28 @@ angular.module('cfp.loadingBar', []) return; } + var document = $document[0]; + var parent = document.querySelector ? + document.querySelector($parentSelector) + : $document.find($parentSelector)[0] + ; + + if (! parent) { + parent = document.getElementsByTagName('body')[0]; + } + + var $parent = angular.element(parent); + var $after = parent.lastChild && angular.element(parent.lastChild); + $rootScope.$broadcast('cfpLoadingBar:started'); started = true; if (includeBar) { - $animate.enter(loadingBarContainer, $parent, angular.element($parent[0].lastChild)); + $animate.enter(loadingBarContainer, $parent, $after); } if (includeSpinner) { - $animate.enter(spinner, $parent, angular.element($parent[0].lastChild)); + $animate.enter(spinner, $parent, loadingBarContainer); } _set(startSize); @@ -289,9 +301,7 @@ angular.module('cfp.loadingBar', []) $animate = $injector.get('$animate'); } - $rootScope.$broadcast('cfpLoadingBar:completed'); _set(1); - $timeout.cancel(completeTimeout); // Attempt to aggregate any start/complete calls within 500ms: @@ -301,6 +311,7 @@ angular.module('cfp.loadingBar', []) promise.then(_completeAnimation); } $animate.leave(spinner); + $rootScope.$broadcast('cfpLoadingBar:completed'); }, 500); } diff --git a/test/karma-angular-1.4.conf.js b/test/karma-angular-1.4.conf.js new file mode 100644 index 0000000..8b0b8c5 --- /dev/null +++ b/test/karma-angular-1.4.conf.js @@ -0,0 +1,82 @@ +// Karma configuration +// Generated on Sun Sep 15 2013 20:18:09 GMT-0400 (EDT) + +module.exports = function(config) { + config.set({ + + // base path, that will be used to resolve files and exclude + basePath: '', + + + // frameworks to use + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + '../bower_components/angular-1.4/angular.js', + '../bower_components/angular-animate-1.4/angular-animate.js', + '../bower_components/angular-mocks-1.4/angular-mocks.js', + '../src/*.js', + '*.coffee' + ], + + + // list of files to exclude + exclude: [ + + ], + + + // test results reporter to use + // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' + reporters: ['progress', 'coverage'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['PhantomJS'], + + coverageReporter: { + type : 'html', + dir : 'coverage/', + }, + + preprocessors: { + '../src/*.js': ['coverage'], + '*.coffee': 'coffee' + }, + + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000, + + + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + }); +}; diff --git a/test/loading-bar-interceptor-config.coffee b/test/loading-bar-interceptor-config.coffee index d8713f5..f29ab1e 100644 --- a/test/loading-bar-interceptor-config.coffee +++ b/test/loading-bar-interceptor-config.coffee @@ -79,3 +79,36 @@ describe 'loadingBarInterceptor Service - config options', -> expect(cfpLoadingBar.status()).toBeGreaterThan .5 cfpLoadingBar.complete() $timeout.flush() + + it 'should append the loadingbar as the first child of the parent container if empty', -> + emptyEl = angular.element '
' + angular.element(document).find('body').eq(0).append emptyEl + + module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) -> + cfpLoadingBarProvider.parentSelector = '#empty' + return + inject ($timeout, $document, cfpLoadingBar) -> + cfpLoadingBar.start() + parent = $document[0].querySelector(cfpLoadingBar.parentSelector) + children = parent.childNodes + expect(children.length).toBe 2 + expect(children[0].id).toBe 'loading-bar' + expect(children[1].id).toBe 'loading-bar-spinner' + cfpLoadingBar.complete() + $timeout.flush() + + it 'should append the loading bar to the body if parentSelector is empty', -> + module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) -> + cfpLoadingBarProvider.parentSelector = '#doesnotexist' + return + inject ($timeout, $document, cfpLoadingBar) -> + parent = $document[0].querySelector(cfpLoadingBar.parentSelector) + expect(parent).toBeFalsy; + body = $document[0].querySelector 'body' + cfpLoadingBar.start() + bar = angular.element(body.querySelector '#loading-bar'); + spinner = angular.element(body.querySelector '#loading-bar-spinner'); + expect(bar.length).toBe 1 + expect(spinner.length).toBe 1 + cfpLoadingBar.complete() + $timeout.flush() diff --git a/test/loading-bar-interceptor.coffee b/test/loading-bar-interceptor.coffee index 8f38281..241967f 100644 --- a/test/loading-bar-interceptor.coffee +++ b/test/loading-bar-interceptor.coffee @@ -7,6 +7,8 @@ isLoadingBarInjected = (doc) -> break return injected +flush = null + describe 'loadingBarInterceptor Service', -> $http = $httpBackend = $document = $timeout = result = loadingBar = $animate = null @@ -26,6 +28,11 @@ describe 'loadingBarInterceptor Service', -> $timeout = _$timeout_ $animate = _$animate_ + # Angular 1.4 removed triggerCalbacks(), so try them both: + flush = () -> + $animate.flush && $animate.flush() + $animate.triggerCallbacks && $animate.triggerCallbacks() + beforeEach -> this.addMatchers toBeBetween: (high, low) -> @@ -54,7 +61,7 @@ describe 'loadingBarInterceptor Service', -> expect(cfpLoadingBar.status()).toBe 1 cfpLoadingBar.complete() # set as complete $timeout.flush() - $animate.triggerCallbacks() + flush() $http.get(endpoint, cache: cache).then (data) -> @@ -77,7 +84,7 @@ describe 'loadingBarInterceptor Service', -> expect(cfpLoadingBar.status()).toBe 1 cfpLoadingBar.complete() # set as complete $timeout.flush() - $animate.triggerCallbacks() + flush() $http.get(endpoint).then (data) -> @@ -99,7 +106,7 @@ describe 'loadingBarInterceptor Service', -> expect(cfpLoadingBar.status()).toBe 1 cfpLoadingBar.complete() # set as complete $timeout.flush() - $animate.triggerCallbacks() + flush() $http.get(endpoint, cache: true).then (data) -> @@ -123,7 +130,7 @@ describe 'loadingBarInterceptor Service', -> expect(cfpLoadingBar.status()).toBe 1 cfpLoadingBar.complete() # set as complete $timeout.flush() - $animate.triggerCallbacks() + flush() $http.get(endpoint).then (data) -> @@ -144,7 +151,7 @@ describe 'loadingBarInterceptor Service', -> $httpBackend.flush(1) expect(cfpLoadingBar.status()).toBe 1 $timeout.flush() - $animate.triggerCallbacks() + flush() $httpBackend.expectPOST(endpoint).respond response @@ -369,8 +376,8 @@ describe 'loadingBarInterceptor Service', -> expect(startedEventCalled).toBe true cfpLoadingBar.complete() - expect(completedEventCalled).toBe true $timeout.flush() + expect(completedEventCalled).toBe true it 'should debounce the calls to start()', inject (cfpLoadingBar, $rootScope) -> startedEventCalled = 0 @@ -383,7 +390,7 @@ describe 'loadingBarInterceptor Service', -> expect(startedEventCalled).toBe 1 # Should still be one, as complete was never called: cfpLoadingBar.complete() $timeout.flush() - $animate.triggerCallbacks() + flush() cfpLoadingBar.start() @@ -478,13 +485,12 @@ describe 'LoadingBar only', -> cfpLoadingBar.complete() cfpLoadingBar.start() $timeout.flush() - $animate.triggerCallbacks() expect(isLoadingBarInjected($document.find(cfpLoadingBar.parentSelector))).toBe true cfpLoadingBar.complete() $timeout.flush() - $animate.triggerCallbacks() + flush() expect(isLoadingBarInjected($document.find(cfpLoadingBar.parentSelector))).toBe false