Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Services.WebApp/3.3/WebApp/libs/angularjs/loading-bar/loading-bar.js @ 13792

Last change on this file since 13792 was 12428, checked in by ascheibe, 10 years ago

#2394 added web app and status page to trunk

File size: 12.2 KB
Line 
1/*
2 * angular-loading-bar
3 *
4 * intercepts XHR requests and creates a loading bar.
5 * Based on the excellent nprogress work by rstacruz (more info in readme)
6 *
7 * (c) 2013 Wes Cruver
8 * License: MIT
9 */
10
11
12(function () {
13
14    'use strict';
15
16    // Alias the loading bar for various backwards compatibilities since the project has matured:
17    angular.module('angular-loading-bar', ['cfp.loadingBarInterceptor']);
18    angular.module('chieffancypants.loadingBar', ['cfp.loadingBarInterceptor']);
19
20
21    /**
22     * loadingBarInterceptor service
23     *
24     * Registers itself as an Angular interceptor and listens for XHR requests.
25     */
26    angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar'])
27      .config(['$httpProvider', function ($httpProvider) {
28
29          var interceptor = ['$q', '$cacheFactory', '$timeout', '$rootScope', '$log', 'cfpLoadingBar', function ($q, $cacheFactory, $timeout, $rootScope, $log, cfpLoadingBar) {
30
31              /**
32               * The total number of requests made
33               */
34              var reqsTotal = 0;
35
36              /**
37               * The number of requests completed (either successfully or not)
38               */
39              var reqsCompleted = 0;
40
41              /**
42               * The amount of time spent fetching before showing the loading bar
43               */
44              var latencyThreshold = cfpLoadingBar.latencyThreshold;
45
46              /**
47               * $timeout handle for latencyThreshold
48               */
49              var startTimeout;
50
51
52              /**
53               * calls cfpLoadingBar.complete() which removes the
54               * loading bar from the DOM.
55               */
56              function setComplete() {
57                  $timeout.cancel(startTimeout);
58                  cfpLoadingBar.complete();
59                  reqsCompleted = 0;
60                  reqsTotal = 0;
61              }
62
63              /**
64               * Determine if the response has already been cached
65               * @param  {Object}  config the config option from the request
66               * @return {Boolean} retrns true if cached, otherwise false
67               */
68              function isCached(config) {
69                  var cache;
70                  var defaultCache = $cacheFactory.get('$http');
71                  var defaults = $httpProvider.defaults;
72
73                  // Choose the proper cache source. Borrowed from angular: $http service
74                  if ((config.cache || defaults.cache) && config.cache !== false &&
75                    (config.method === 'GET' || config.method === 'JSONP')) {
76                      cache = angular.isObject(config.cache) ? config.cache
77                        : angular.isObject(defaults.cache) ? defaults.cache
78                        : defaultCache;
79                  }
80
81                  var cached = cache !== undefined ?
82                    cache.get(config.url) !== undefined : false;
83
84                  if (config.cached !== undefined && cached !== config.cached) {
85                      return config.cached;
86                  }
87                  config.cached = cached;
88                  return cached;
89              }
90
91
92              return {
93                  'request': function (config) {
94                      // Check to make sure this request hasn't already been cached and that
95                      // the requester didn't explicitly ask us to ignore this request:
96                      if (!config.ignoreLoadingBar && !isCached(config)) {
97                          $rootScope.$broadcast('cfpLoadingBar:loading', { url: config.url });
98                          if (reqsTotal === 0) {
99                              startTimeout = $timeout(function () {
100                                  cfpLoadingBar.start();
101                              }, latencyThreshold);
102                          }
103                          reqsTotal++;
104                          cfpLoadingBar.set(reqsCompleted / reqsTotal);
105                      }
106                      return config;
107                  },
108
109                  'response': function (response) {
110                      if (!response || !response.config) {
111                          $log.error('Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
112                          return response;
113                      }
114
115                      if (!response.config.ignoreLoadingBar && !isCached(response.config)) {
116                          reqsCompleted++;
117                          $rootScope.$broadcast('cfpLoadingBar:loaded', { url: response.config.url, result: response });
118                          if (reqsCompleted >= reqsTotal) {
119                              setComplete();
120                          } else {
121                              cfpLoadingBar.set(reqsCompleted / reqsTotal);
122                          }
123                      }
124                      return response;
125                  },
126
127                  'responseError': function (rejection) {
128                      if (!rejection || !rejection.config) {
129                          $log.error('Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
130                          return $q.reject(rejection);
131                      }
132
133                      if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) {
134                          reqsCompleted++;
135                          $rootScope.$broadcast('cfpLoadingBar:loaded', { url: rejection.config.url, result: rejection });
136                          if (reqsCompleted >= reqsTotal) {
137                              setComplete();
138                          } else {
139                              cfpLoadingBar.set(reqsCompleted / reqsTotal);
140                          }
141                      }
142                      return $q.reject(rejection);
143                  }
144              };
145          }];
146
147          $httpProvider.interceptors.push(interceptor);
148      }]);
149
150
151    /**
152     * Loading Bar
153     *
154     * This service handles adding and removing the actual element in the DOM.
155     * Generally, best practices for DOM manipulation is to take place in a
156     * directive, but because the element itself is injected in the DOM only upon
157     * XHR requests, and it's likely needed on every view, the best option is to
158     * use a service.
159     */
160    angular.module('cfp.loadingBar', [])
161      .provider('cfpLoadingBar', function () {
162
163          this.includeSpinner = false;
164          this.includeBar = true;
165          this.latencyThreshold = 150;
166          this.startSize = 0.02;
167          this.parentSelector = '#view';
168          this.spinnerTemplate = '<div id="loading-bar-spinner"><div class="spinner-icon"></div></div>';
169          this.loadingBarTemplate = '<div id="loading-bar"><div class="bar"><div class="peg"></div></div></div>';
170
171          this.$get = ['$injector', '$document', '$timeout', '$rootScope', function ($injector, $document, $timeout, $rootScope) {
172              var $animate;
173              var $parentSelector = this.parentSelector,
174                loadingBarContainer = angular.element(this.loadingBarTemplate),
175                loadingBar = loadingBarContainer.find('div').eq(0),
176                spinner = angular.element(this.spinnerTemplate);
177
178              var incTimeout,
179                completeTimeout,
180                started = false,
181                status = 0;
182
183              var includeSpinner = this.includeSpinner;
184              var includeBar = this.includeBar;
185              var startSize = this.startSize;
186
187              /**
188               * Inserts the loading bar element into the dom, and sets it to 2%
189               */
190              function _start() {
191                  if (!$animate) {
192                      $animate = $injector.get('$animate');
193                  }
194
195                  var $parent = $document.find($parentSelector).eq(0);
196                  $timeout.cancel(completeTimeout);
197
198                  // do not continually broadcast the started event:
199                  if (started) {
200                      return;
201                  }
202
203                  $rootScope.$broadcast('cfpLoadingBar:started');
204                  started = true;
205
206                  if (includeBar) {
207                      $animate.enter(loadingBarContainer, $parent);
208                  }
209
210                  if (includeSpinner) {
211                      $animate.enter(spinner, $parent);
212                  }
213
214                  _set(startSize);
215              }
216
217              /**
218               * Set the loading bar's width to a certain percent.
219               *
220               * @param n any value between 0 and 1
221               */
222              function _set(n) {
223                  if (!started) {
224                      return;
225                  }
226                  var pct = (n * 100) + '%';
227                  loadingBar.css('width', pct);
228                  status = n;
229
230                  // increment loadingbar to give the illusion that there is always
231                  // progress but make sure to cancel the previous timeouts so we don't
232                  // have multiple incs running at the same time.
233                  $timeout.cancel(incTimeout);
234                  incTimeout = $timeout(function () {
235                      _inc();
236                  }, 250);
237              }
238
239              /**
240               * Increments the loading bar by a random amount
241               * but slows down as it progresses
242               */
243              function _inc() {
244                  if (_status() >= 1) {
245                      return;
246                  }
247
248                  var rnd = 0;
249
250                  // TODO: do this mathmatically instead of through conditions
251
252                  var stat = _status();
253                  if (stat >= 0 && stat < 0.25) {
254                      // Start out between 3 - 6% increments
255                      rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
256                  } else if (stat >= 0.25 && stat < 0.65) {
257                      // increment between 0 - 3%
258                      rnd = (Math.random() * 3) / 100;
259                  } else if (stat >= 0.65 && stat < 0.9) {
260                      // increment between 0 - 2%
261                      rnd = (Math.random() * 2) / 100;
262                  } else if (stat >= 0.9 && stat < 0.99) {
263                      // finally, increment it .5 %
264                      rnd = 0.005;
265                  } else {
266                      // after 99%, don't increment:
267                      rnd = 0;
268                  }
269
270                  var pct = _status() + rnd;
271                  _set(pct);
272              }
273
274              function _status() {
275                  return status;
276              }
277
278              function _completeAnimation() {
279                  status = 0;
280                  started = false;
281              }
282
283              function _complete() {
284                  if (!$animate) {
285                      $animate = $injector.get('$animate');
286                  }
287
288                  $rootScope.$broadcast('cfpLoadingBar:completed');
289                  _set(1);
290
291                  $timeout.cancel(completeTimeout);
292
293                  // Attempt to aggregate any start/complete calls within 500ms:
294                  completeTimeout = $timeout(function () {
295                      var promise = $animate.leave(loadingBarContainer, _completeAnimation);
296                      if (promise && promise.then) {
297                          promise.then(_completeAnimation);
298                      }
299                      $animate.leave(spinner);
300                  }, 500);
301              }
302
303              return {
304                  start: _start,
305                  set: _set,
306                  status: _status,
307                  inc: _inc,
308                  complete: _complete,
309                  includeSpinner: this.includeSpinner,
310                  latencyThreshold: this.latencyThreshold,
311                  parentSelector: this.parentSelector,
312                  startSize: this.startSize
313              };
314
315
316          }];     //
317      });       // wtf javascript. srsly
318})();       //
Note: See TracBrowser for help on using the repository browser.