/* * angular-loading-bar * * intercepts XHR requests and creates a loading bar. * Based on the excellent nprogress work by rstacruz (more info in readme) * * (c) 2013 Wes Cruver * License: MIT */ (function() { 'use strict'; // Alias the loading bar for various backwards compatibilities since the project has matured: angular.module('angular-loading-bar', ['cfp.loadingBarInterceptor']); angular.module('chieffancypants.loadingBar', ['cfp.loadingBarInterceptor']); /** * loadingBarInterceptor service * * Registers itself as an Angular interceptor and listens for XHR requests. */ angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar']) .config(['$httpProvider', function ($httpProvider) { var interceptor = ['$q', '$cacheFactory', '$timeout', '$rootScope', '$log', 'cfpLoadingBar', function ($q, $cacheFactory, $timeout, $rootScope, $log, cfpLoadingBar) { /** * The total number of requests made */ var reqsTotal = 0; /** * The number of requests completed (either successfully or not) */ var reqsCompleted = 0; /** * The amount of time spent fetching before showing the loading bar */ var latencyThreshold = cfpLoadingBar.latencyThreshold; /** * $timeout handle for latencyThreshold */ var startTimeout; /** * calls cfpLoadingBar.complete() which removes the * loading bar from the DOM. */ function setComplete() { $timeout.cancel(startTimeout); cfpLoadingBar.complete(); reqsCompleted = 0; reqsTotal = 0; } /** * Determine if the response has already been cached * @param {Object} config the config option from the request * @return {Boolean} retrns true if cached, otherwise false */ function isCached(config) { var cache; var defaultCache = $cacheFactory.get('$http'); var defaults = $httpProvider.defaults; // Choose the proper cache source. Borrowed from angular: $http service if ((config.cache || defaults.cache) && config.cache !== false && (config.method === 'GET' || config.method === 'JSONP')) { cache = angular.isObject(config.cache) ? config.cache : angular.isObject(defaults.cache) ? defaults.cache : defaultCache; } var cached = cache !== undefined ? cache.get(config.url) !== undefined : false; if (config.cached !== undefined && cached !== config.cached) { return config.cached; } config.cached = cached; return cached; } return { 'request': function(config) { // Check to make sure this request hasn't already been cached and that // the requester didn't explicitly ask us to ignore this request: if (!config.ignoreLoadingBar && !isCached(config)) { $rootScope.$broadcast('cfpLoadingBar:loading', {url: config.url}); if (reqsTotal === 0) { startTimeout = $timeout(function() { cfpLoadingBar.start(); }, latencyThreshold); } reqsTotal++; cfpLoadingBar.set(reqsCompleted / reqsTotal); } return config; }, 'response': function(response) { if (!response || !response.config) { $log.error('Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50'); return response; } if (!response.config.ignoreLoadingBar && !isCached(response.config)) { reqsCompleted++; $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response}); if (reqsCompleted >= reqsTotal) { setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); } } return response; }, 'responseError': function(rejection) { if (!rejection || !rejection.config) { $log.error('Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50'); return $q.reject(rejection); } if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) { reqsCompleted++; $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection}); if (reqsCompleted >= reqsTotal) { setComplete(); } else { cfpLoadingBar.set(reqsCompleted / reqsTotal); } } return $q.reject(rejection); } }; }]; $httpProvider.interceptors.push(interceptor); }]); /** * Loading Bar * * This service handles adding and removing the actual element in the DOM. * Generally, best practices for DOM manipulation is to take place in a * directive, but because the element itself is injected in the DOM only upon * XHR requests, and it's likely needed on every view, the best option is to * use a service. */ angular.module('cfp.loadingBar', []) .provider('cfpLoadingBar', function() { this.autoIncrement = true; this.includeSpinner = true; this.includeBar = true; this.latencyThreshold = 100; this.startSize = 0.02; this.parentSelector = 'body'; this.spinnerTemplate = '