diff --git a/bower.json b/bower.json
index f1d1f7a..9dab976 100644
--- a/bower.json
+++ b/bower.json
@@ -20,10 +20,7 @@
"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.4": "angular-animate#1.4"
+ "angular-mocks-1.4": "angular-mocks#1.4"
},
"resolutions": {
"angular": "~1.2.23"
diff --git a/src/loading-bar.css b/src/loading-bar.css
index 3ee0618..69af12c 100644
--- a/src/loading-bar.css
+++ b/src/loading-bar.css
@@ -4,31 +4,29 @@
#loading-bar-spinner {
pointer-events: none;
-webkit-pointer-events: none;
- -webkit-transition: 350ms linear all;
- -moz-transition: 350ms linear all;
- -o-transition: 350ms linear all;
- transition: 350ms linear all;
-}
-#loading-bar.ng-enter,
-#loading-bar.ng-leave.ng-leave-active,
-#loading-bar-spinner.ng-enter,
-#loading-bar-spinner.ng-leave.ng-leave-active {
- opacity: 0;
+ -webkit-animation: fade linear 350ms;
+ -moz-animation: fade linear 350ms;
+ -ms-animation: fade linear 350ms;
+ -o-animation: fade linear 350ms;
+ animation: fade linear 350ms;
+
+ -webkit-transition: opacity 350ms linear;
+ -moz-transition: opacity 350ms linear;
+ -o-transition: opacity 350ms linear;
+ transition: opacity 350ms linear;
}
-#loading-bar.ng-enter.ng-enter-active,
-#loading-bar.ng-leave,
-#loading-bar-spinner.ng-enter.ng-enter-active,
-#loading-bar-spinner.ng-leave {
- opacity: 1;
+#loading-bar.out,
+#loading-bar-spinner.out {
+ opacity: 0;
}
#loading-bar .bar {
- -webkit-transition: width 350ms;
- -moz-transition: width 350ms;
- -o-transition: width 350ms;
- transition: width 350ms;
+ -webkit-transition: width 350ms linear;
+ -moz-transition: width 350ms linear;
+ -o-transition: width 350ms linear;
+ transition: width 350ms linear;
background: #29d;
position: fixed;
@@ -102,3 +100,24 @@
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
+
+@-webkit-keyframes fade {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+@-moz-keyframes fade {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+@-o-keyframes fade {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+@-ms-keyframes fade {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+@keyframes fade {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
diff --git a/src/loading-bar.js b/src/loading-bar.js
index 44e092a..bf5b780 100644
--- a/src/loading-bar.js
+++ b/src/loading-bar.js
@@ -168,75 +168,49 @@ angular.module('cfp.loadingBar', [])
this.parentSelector = 'body';
this.spinnerTemplate = '
';
this.loadingBarTemplate = '';
+ this.fadeOutDuration = 350;
- this.$get = ['$injector', '$document', '$timeout', '$rootScope', function ($injector, $document, $timeout, $rootScope) {
- var $animate;
- var $parentSelector = this.parentSelector,
- loadingBarContainer = angular.element(this.loadingBarTemplate),
- loadingBar = loadingBarContainer.find('div').eq(0),
- spinner = angular.element(this.spinnerTemplate);
-
+ function LoadingBar($document, $timeout, options) {
+ var _this = this;
+ var loadingBarContainer = angular.element(options.loadingBarTemplate);
+ var loadingBar = loadingBarContainer.find('div').eq(0);
+ var spinner = angular.element(options.spinnerTemplate);
var incTimeout,
- completeTimeout,
- started = false,
status = 0;
- var autoIncrement = this.autoIncrement;
- var includeSpinner = this.includeSpinner;
- var includeBar = this.includeBar;
- var startSize = this.startSize;
-
- /**
- * Inserts the loading bar element into the dom, and sets it to 2%
- */
- function _start() {
- if (!$animate) {
- $animate = $injector.get('$animate');
- }
-
- $timeout.cancel(completeTimeout);
-
- // do not continually broadcast the started event:
- if (started) {
- return;
- }
-
+ var init = function() {
var document = $document[0];
var parent = document.querySelector ?
- document.querySelector($parentSelector)
- : $document.find($parentSelector)[0]
- ;
+ document.querySelector(options.parentSelector)
+ : $document.find(options.parentSelector)[0]
+ ;
- if (! parent) {
+ 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, $after);
+ if(options.includeBar) {
+ $parent.append(loadingBarContainer);
}
- if (includeSpinner) {
- $animate.enter(spinner, $parent, loadingBarContainer);
+ if(options.includeSpinner) {
+ $parent.append(spinner);
}
+ };
- _set(startSize);
- }
+ init();
- /**
- * Set the loading bar's width to a certain percent.
- *
- * @param n any value between 0 and 1
- */
- function _set(n) {
- if (!started) {
- return;
- }
+ this.activate = function() {
+ _this.set(options.startSize);
+ };
+
+ this.status = function() {
+ return status;
+ };
+
+ this.set = function(n) {
var pct = (n * 100) + '%';
loadingBar.css('width', pct);
status = n;
@@ -244,20 +218,17 @@ angular.module('cfp.loadingBar', [])
// increment loadingbar to give the illusion that there is always
// progress but make sure to cancel the previous timeouts so we don't
// have multiple incs running at the same time.
- if (autoIncrement) {
+ if (options.autoIncrement) {
$timeout.cancel(incTimeout);
+
incTimeout = $timeout(function() {
- _inc();
+ _this.inc();
}, 250);
}
- }
+ };
- /**
- * Increments the loading bar by a random amount
- * but slows down as it progresses
- */
- function _inc() {
- if (_status() >= 1) {
+ this.inc = function() {
+ if (_this.status() >= 1) {
return;
}
@@ -265,7 +236,7 @@ angular.module('cfp.loadingBar', [])
// TODO: do this mathmatically instead of through conditions
- var stat = _status();
+ var stat = _this.status();
if (stat >= 0 && stat < 0.25) {
// Start out between 3 - 6% increments
rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
@@ -283,22 +254,79 @@ angular.module('cfp.loadingBar', [])
rnd = 0;
}
- var pct = _status() + rnd;
- _set(pct);
+ var pct = _this.status() + rnd;
+ _this.set(pct);
+ };
+
+ this.cleanup = function() {
+ spinner.addClass('out');
+ loadingBarContainer.addClass('out');
+
+ $timeout(function() {
+ spinner.remove();
+ loadingBarContainer.remove();
+ }, options.fadeOutDuration);
+ };
+ }
+
+ this.$get = ['$injector', '$document', '$timeout', '$rootScope', function ($injector, $document, $timeout, $rootScope) {
+ var _this = this;
+
+ var options = {
+ parentSelector: _this.parentSelector,
+ loadingBarTemplate: _this.loadingBarTemplate,
+ spinnerTemplate: _this.spinnerTemplate,
+ autoIncrement: _this.autoIncrement,
+ includeSpinner: _this.includeSpinner,
+ includeBar: _this.includeBar,
+ startSize: _this.startSize,
+ fadeOutDuration: _this.fadeOutDuration
+ };
+
+ var completeTimeout,
+ currentBar = null;
+
+ /**
+ * Inserts the loading bar element into the dom, and sets it to 2%
+ */
+ function _start() {
+ $timeout.cancel(completeTimeout);
+
+ // do not continually broadcast the started event:
+ if (currentBar) {
+ return;
+ }
+
+ currentBar = new LoadingBar($document, $timeout, options);
+ currentBar.activate();
+
+ $rootScope.$broadcast('cfpLoadingBar:started');
}
- function _status() {
- return status;
+ /**
+ * Set the loading bar's width to a certain percent.
+ *
+ * @param n any value between 0 and 1
+ */
+ function _set(n) {
+ if (currentBar) currentBar.set(n);
}
- function _completeAnimation() {
- status = 0;
- started = false;
+ /**
+ * Increments the loading bar by a random amount
+ * but slows down as it progresses
+ */
+ function _inc() {
+ if (currentBar) currentBar.inc();
+ }
+
+ function _status() {
+ return currentBar ? currentBar.status() : 0;
}
function _complete() {
- if (!$animate) {
- $animate = $injector.get('$animate');
+ if (!currentBar) {
+ return;
}
_set(1);
@@ -306,11 +334,8 @@ angular.module('cfp.loadingBar', [])
// Attempt to aggregate any start/complete calls within 500ms:
completeTimeout = $timeout(function() {
- var promise = $animate.leave(loadingBarContainer, _completeAnimation);
- if (promise && promise.then) {
- promise.then(_completeAnimation);
- }
- $animate.leave(spinner);
+ currentBar.cleanup();
+ currentBar = null;
$rootScope.$broadcast('cfpLoadingBar:completed');
}, 500);
}
diff --git a/test/loading-bar-interceptor-config.coffee b/test/loading-bar-interceptor-config.coffee
index f29ab1e..3380f7c 100644
--- a/test/loading-bar-interceptor-config.coffee
+++ b/test/loading-bar-interceptor-config.coffee
@@ -10,6 +10,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(spinner).toBeNull
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should show the spinner if configured', ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -21,6 +22,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(spinner).not.toBeNull
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should hide the loadingBar if configured', ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -32,6 +34,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(spinner).toBeNull
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should show the loadingBar if configured', ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -43,6 +46,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(spinner).not.toBeNull
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should not auto increment loadingBar if configured', (done) ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -66,6 +70,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(cfpLoadingBar.status()).toBe .5;
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should auto increment loadingBar if configured', ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -79,6 +84,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(cfpLoadingBar.status()).toBeGreaterThan .5
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should append the loadingbar as the first child of the parent container if empty', ->
emptyEl = angular.element ''
@@ -96,6 +102,7 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(children[1].id).toBe 'loading-bar-spinner'
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should append the loading bar to the body if parentSelector is empty', ->
module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
@@ -112,3 +119,4 @@ describe 'loadingBarInterceptor Service - config options', ->
expect(spinner.length).toBe 1
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
diff --git a/test/loading-bar-interceptor.coffee b/test/loading-bar-interceptor.coffee
index 241967f..1848881 100644
--- a/test/loading-bar-interceptor.coffee
+++ b/test/loading-bar-interceptor.coffee
@@ -7,31 +7,23 @@ isLoadingBarInjected = (doc) ->
break
return injected
-flush = null
-
describe 'loadingBarInterceptor Service', ->
- $http = $httpBackend = $document = $timeout = result = loadingBar = $animate = null
+ $http = $httpBackend = $document = $timeout = result = loadingBar = null
response = {message:'OK'}
endpoint = '/service'
beforeEach ->
- module 'ngAnimateMock', 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
+ module 'chieffancypants.loadingBar', (cfpLoadingBarProvider) ->
loadingBar = cfpLoadingBarProvider
return
result = null
- inject (_$http_, _$httpBackend_, _$document_, _$timeout_, _$animate_) ->
+ inject (_$http_, _$httpBackend_, _$document_, _$timeout_) ->
$http = _$http_
$httpBackend = _$httpBackend_
$document = _$document_
$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
@@ -46,6 +38,7 @@ describe 'loadingBarInterceptor Service', ->
afterEach ->
$httpBackend.verifyNoOutstandingRequest()
$timeout.verifyNoPendingTasks()
+ expect(isLoadingBarInjected($document)).toBe false, "Loading bar not cleaned up!"
it 'should not increment if the response is cached in a cacheFactory', inject (cfpLoadingBar, $cacheFactory) ->
@@ -61,8 +54,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
cfpLoadingBar.complete() # set as complete
$timeout.flush()
- flush()
-
+ $timeout.flush()
$http.get(endpoint, cache: cache).then (data) ->
result = data
@@ -84,7 +76,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
cfpLoadingBar.complete() # set as complete
$timeout.flush()
- flush()
+ $timeout.flush()
$http.get(endpoint).then (data) ->
@@ -106,7 +98,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
cfpLoadingBar.complete() # set as complete
$timeout.flush()
- flush()
+ $timeout.flush()
$http.get(endpoint, cache: true).then (data) ->
@@ -130,7 +122,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
cfpLoadingBar.complete() # set as complete
$timeout.flush()
- flush()
+ $timeout.flush()
$http.get(endpoint).then (data) ->
@@ -151,7 +143,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush(1)
expect(cfpLoadingBar.status()).toBe 1
$timeout.flush()
- flush()
+ $timeout.flush()
$httpBackend.expectPOST(endpoint).respond response
@@ -164,6 +156,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush()
expect(cfpLoadingBar.status()).toBe 1
$timeout.flush()
+ $timeout.flush()
it 'should increment the loading bar when not all requests have been recieved', inject (cfpLoadingBar) ->
@@ -183,6 +176,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush()
expect(cfpLoadingBar.status()).toBe 1
$timeout.flush() # loading bar is animated, so flush timeout
+ $timeout.flush()
it 'should count http errors as responses so the loading bar can complete', inject (cfpLoadingBar) ->
# $httpBackend.expectGET(endpoint).respond response
@@ -198,7 +192,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 0.5
$httpBackend.flush()
expect(cfpLoadingBar.status()).toBe 1
-
+ $timeout.flush()
$timeout.flush()
it 'should insert the loadingbar into the DOM when a request is sent', inject (cfpLoadingBar) ->
@@ -214,6 +208,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush()
$timeout.flush()
+ $timeout.flush()
it 'should insert the loadingbar as the last children of the parent container', inject (cfpLoadingBar) ->
$httpBackend.expectGET(endpoint).respond response
@@ -231,6 +226,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush()
$timeout.flush()
+ $timeout.flush()
it 'should remove the loading bar when all requests have been received', inject (cfpLoadingBar) ->
$httpBackend.expectGET(endpoint).respond response
@@ -245,6 +241,7 @@ describe 'loadingBarInterceptor Service', ->
$httpBackend.flush()
$timeout.flush()
+ $timeout.flush()
expect(isLoadingBarInjected($document.find(cfpLoadingBar.parentSelector))).toBe false
@@ -261,6 +258,7 @@ describe 'loadingBarInterceptor Service', ->
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should increment things randomly', inject (cfpLoadingBar) ->
cfpLoadingBar.start()
@@ -345,6 +343,7 @@ describe 'loadingBarInterceptor Service', ->
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should not set the status if the loading bar has not yet been started', inject (cfpLoadingBar) ->
cfpLoadingBar.set(0.5)
@@ -358,6 +357,7 @@ describe 'loadingBarInterceptor Service', ->
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should broadcast started and completed events', inject (cfpLoadingBar, $rootScope) ->
startedEventCalled = false
@@ -377,6 +377,7 @@ describe 'loadingBarInterceptor Service', ->
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
expect(completedEventCalled).toBe true
it 'should debounce the calls to start()', inject (cfpLoadingBar, $rootScope) ->
@@ -390,13 +391,14 @@ describe 'loadingBarInterceptor Service', ->
expect(startedEventCalled).toBe 1 # Should still be one, as complete was never called:
cfpLoadingBar.complete()
$timeout.flush()
- flush()
+ $timeout.flush()
cfpLoadingBar.start()
expect(startedEventCalled).toBe 2
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
it 'should ignore requests when ignoreLoadingBar is true', inject (cfpLoadingBar) ->
$httpBackend.expectGET(endpoint).respond response
@@ -424,6 +426,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
$timeout.flush() # loading bar is animated, so flush timeout
+ $timeout.flush()
it 'should ignore errors when ignoreLoadingBar is true (#70)', inject (cfpLoadingBar) ->
$httpBackend.expectGET(endpoint).respond 400
@@ -441,6 +444,7 @@ describe 'loadingBarInterceptor Service', ->
expect(cfpLoadingBar.status()).toBe 1
$timeout.flush() # loading bar is animated, so flush timeout
+ $timeout.flush()
@@ -474,6 +478,7 @@ describe 'LoadingBar only', ->
# test the complete call, which should remove it from the DOM
cfpLoadingBar.complete()
$timeout.flush()
+ $timeout.flush()
expect(isLoadingBarInjected($document.find(cfpLoadingBar.parentSelector))).toBe false
it 'should start after multiple calls to complete()', ->
@@ -490,7 +495,7 @@ describe 'LoadingBar only', ->
cfpLoadingBar.complete()
$timeout.flush()
- flush()
+ $timeout.flush()
expect(isLoadingBarInjected($document.find(cfpLoadingBar.parentSelector))).toBe false