PageSourceSearch

https://maku.net/static/nprogress/nprogress.js

js maku.net collected 2026-09-25 21:49:57 UTC 11,565 bytes, 476 lines download raw bytes

vendor: 11,565 bytes, lines 1-476
1/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
2 * @license MIT */
3
4;(function(root, factory) {
5
6  if (typeof define === 'function' && define.amd) {
7    define(factory);
8  } else if (typeof exports === 'object') {
9    module.exports = factory();
10  } else {
11    root.NProgress = factory();
12  }
13
14})(this, function() {
15  var NProgress = {};
16
17  NProgress.version = '0.2.0';
18
19  var Settings = NProgress.settings = {
20    minimum: 0.08,
21    easing: 'ease',
22    positionUsing: '',
23    speed: 200,
24    trickle: true,
25    trickleRate: 0.02,
26    trickleSpeed: 800,
27    showSpinner: true,
28    barSelector: '[role="bar"]',
29    spinnerSelector: '[role="spinner"]',
30    parent: 'body',
31    template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
32  };
33
34  /**
35   * Updates configuration.
36   *
37   *     NProgress.configure({
38   *       minimum: 0.1
39   *     });
40   */
41  NProgress.configure = function(options) {
42    var key, value;
43    for (key in options) {
44      value = options[key];
45      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
46    }
47
48    return this;
49  };
50
51  /**
52   * Last number.
53   */
54
55  NProgress.status = null;
56
57  /**
58   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
59   *
60   *     NProgress.set(0.4);
61   *     NProgress.set(1.0);
62   */
63
64  NProgress.set = function(n) {
65    var started = NProgress.isStarted();
66
67    n = clamp(n, Settings.minimum, 1);
68    NProgress.status = (n === 1 ? null : n);
69
70    var progress = NProgress.render(!started),
71        bar      = progress.querySelector(Settings.barSelector),
72        speed    = Settings.speed,
73        ease     = Settings.easing;
74
75    progress.offsetWidth; /* Repaint */
76
77    queue(function(next) {
78      // Set positionUsing if it hasn't already been set
79      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();
80
81      // Add transition
82      css(bar, barPositionCSS(n, speed, ease));
83
84      if (n === 1) {
85        // Fade out
86        css(progress, { 
87          transition: 'none', 
88          opacity: 1 
89        });
90        progress.offsetWidth; /* Repaint */
91
92        setTimeout(function() {
93          css(progress, { 
94            transition: 'all ' + speed + 'ms linear', 
95            opacity: 0 
96          });
97          setTimeout(function() {
98            NProgress.remove();
99            next();
100          }, speed);
101        }, speed);
102      } else {
103        setTimeout(next, speed);
104      }
105    });
106
107    return this;
108  };
109
110  NProgress.isStarted = function() {
111    return typeof NProgress.status === 'number';
112  };
113
114  /**
115   * Shows the progress bar.
116   * This is the same as setting the status to 0%, except that it doesn't go backwards.
117   *
118   *     NProgress.start();
119   *
120   */
121  NProgress.start = function() {
122    if (!NProgress.status) NProgress.set(0);
123
124    var work = function() {
125      setTimeout(function() {
126        if (!NProgress.status) return;
127        NProgress.trickle();
128        work();
129      }, Settings.trickleSpeed);
130    };
131
132    if (Settings.trickle) work();
133
134    return this;
135  };
136
137  /**
138   * Hides the progress bar.
139   * This is the *sort of* the same as setting the status to 100%, with the
140   * difference being `done()` makes some placebo effect of some realistic motion.
141   *
142   *     NProgress.done();
143   *
144   * If `true` is passed, it will show the progress bar even if its hidden.
145   *
146   *     NProgress.done(true);
147   */
148
149  NProgress.done = function(force) {
150    if (!force && !NProgress.status) return this;
151
152    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
153  };
154
155  /**
156   * Increments by a random amount.
157   */
158
159  NProgress.inc = function(amount) {
160    var n = NProgress.status;
161
162    if (!n) {
163      return NProgress.start();
164    } else {
165      if (typeof amount !== 'number') {
166        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);
167      }
168
169      n = clamp(n + amount, 0, 0.994);
170      return NProgress.set(n);
171    }
172  };
173
174  NProgress.trickle = function() {
175    return NProgress.inc(Math.random() * Settings.trickleRate);
176  };
177
178  /**
179   * Waits for all supplied jQuery promises and
180   * increases the progress as the promises resolve.
181   *
182   * @param $promise jQUery Promise
183   */
184  (function() {
185    var initial = 0, current = 0;
186
187    NProgress.promise = function($promise) {
188      if (!$promise || $promise.state() === "resolved") {
189        return this;
190      }
191
192      if (current === 0) {
193        NProgress.start();
194      }
195
196      initial++;
197      current++;
198
199      $promise.always(function() {
200        current--;
201        if (current === 0) {
202            initial = 0;
203            NProgress.done();
204        } else {
205            NProgress.set((initial - current) / initial);
206        }
207      });
208
209      return this;
210    };
211
212  })();
213
214  /**
215   * (Internal) renders the progress bar markup based on the `template`
216   * setting.
217   */
218
219  NProgress.render = function(fromStart) {
220    if (NProgress.isRendered()) return document.getElementById('nprogress');
221
222    addClass(document.documentElement, 'nprogress-busy');
223    
224    var progress = document.createElement('div');
225    progress.id = 'nprogress';
226    progress.innerHTML = Settings.template;
227
228    var bar      = progress.querySelector(Settings.barSelector),
229        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
230        parent   = document.querySelector(Settings.parent),
231        spinner;
232    
233    css(bar, {
234      transition: 'all 0 linear',
235      transform: 'translate3d(' + perc + '%,0,0)'
236    });
237
238    if (!Settings.showSpinner) {
239      spinner = progress.querySelector(Settings.spinnerSelector);
240      spinner && removeElement(spinner);
241    }
242
243    if (parent != document.body) {
244      addClass(parent, 'nprogress-custom-parent');
245    }
246
247    parent.appendChild(progress);
248    return progress;
249  };
250
251  /**
252   * Removes the element. Opposite of render().
253   */
254
255  NProgress.remove = function() {
256    removeClass(document.documentElement, 'nprogress-busy');
257    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');
258    var progress = document.getElementById('nprogress');
259    progress && removeElement(progress);
260  };
261
262  /**
263   * Checks if the progress bar is rendered.
264   */
265
266  NProgress.isRendered = function() {
267    return !!document.getElementById('nprogress');
268  };
269
270  /**
271   * Determine which positioning CSS rule to use.
272   */
273
274  NProgress.getPositioningCSS = function() {
275    // Sniff on document.body.style
276    var bodyStyle = document.body.style;
277
278    // Sniff prefixes
279    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
280                       ('MozTransform' in bodyStyle) ? 'Moz' :
281                       ('msTransform' in bodyStyle) ? 'ms' :
282                       ('OTransform' in bodyStyle) ? 'O' : '';
283
284    if (vendorPrefix + 'Perspective' in bodyStyle) {
285      // Modern browsers with 3D support, e.g. Webkit, IE10
286      return 'translate3d';
287    } else if (vendorPrefix + 'Transform' in bodyStyle) {
288      // Browsers without 3D support, e.g. IE9
289      return 'translate';
290    } else {
291      // Browsers without translate() support, e.g. IE7-8
292      return 'margin';
293    }
294  };
295
296  /**
297   * Helpers
298   */
299
300  function clamp(n, min, max) {
301    if (n < min) return min;
302    if (n > max) return max;
303    return n;
304  }
305
306  /**
307   * (Internal) converts a percentage (`0..1`) to a bar translateX
308   * percentage (`-100%..0%`).
309   */
310
311  function toBarPerc(n) {
312    return (-1 + n) * 100;
313  }
314
315
316  /**
317   * (Internal) returns the correct CSS for changing the bar's
318   * position given an n percentage, and speed and ease from Settings
319   */
320
321  function barPositionCSS(n, speed, ease) {
322    var barCSS;
323
324    if (Settings.positionUsing === 'translate3d') {
325      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
326    } else if (Settings.positionUsing === 'translate') {
327      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
328    } else {
329      barCSS = { 'margin-left': toBarPerc(n)+'%' };
330    }
331
332    barCSS.transition = 'all '+speed+'ms '+ease;
333
334    return barCSS;
335  }
336
337  /**
338   * (Internal) Queues a function to be executed.
339   */
340
341  var queue = (function() {
342    var pending = [];
343    
344    function next() {
345      var fn = pending.shift();
346      if (fn) {
347        fn(next);
348      }
349    }
350
351    return function(fn) {
352      pending.push(fn);
353      if (pending.length == 1) next();
354    };
355  })();
356
357  /**
358   * (Internal) Applies css properties to an element, similar to the jQuery 
359   * css method.
360   *
361   * While this helper does assist with vendor prefixed property names, it 
362   * does not perform any manipulation of values prior to setting styles.
363   */
364
365  var css = (function() {
366    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
367        cssProps    = {};
368
369    function camelCase(string) {
370      return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
371        return letter.toUpperCase();
372      });
373    }
374
375    function getVendorProp(name) {
376      var style = document.body.style;
377      if (name in style) return name;
378
379      var i = cssPrefixes.length,
380          capName = name.charAt(0).toUpperCase() + name.slice(1),
381          vendorName;
382      while (i--) {
383        vendorName = cssPrefixes[i] + capName;
384        if (vendorName in style) return vendorName;
385      }
386
387      return name;
388    }
389
390    function getStyleProp(name) {
391      name = camelCase(name);
392      return cssProps[name] || (cssProps[name] = getVendorProp(name));
393    }
394
395    function applyCss(element, prop, value) {
396      prop = getStyleProp(prop);
397      element.style[prop] = value;
398    }
399
400    return function(element, properties) {
401      var args = arguments,
402          prop, 
403          value;
404
405      if (args.length == 2) {
406        for (prop in properties) {
407          value = properties[prop];
408          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
409        }
410      } else {
411        applyCss(element, args[1], args[2]);
412      }
413    }
414  })();
415
416  /**
417   * (Internal) Determines if an element or space separated list of class names contains a class name.
418   */
419
420  function hasClass(element, name) {
421    var list = typeof element == 'string' ? element : classList(element);
422    return list.indexOf(' ' + name + ' ') >= 0;
423  }
424
425  /**
426   * (Internal) Adds a class to an element.
427   */
428
429  function addClass(element, name) {
430    var oldList = classList(element),
431        newList = oldList + name;
432
433    if (hasClass(oldList, name)) return; 
434
435    // Trim the opening space.
436    element.className = newList.substring(1);
437  }
438
439  /**
440   * (Internal) Removes a class from an element.
441   */
442
443  function removeClass(element, name) {
444    var oldList = classList(element),
445        newList;
446
447    if (!hasClass(element, name)) return;
448
449    // Replace the class name.
450    newList = oldList.replace(' ' + name + ' ', ' ');
451
452    // Trim the opening and closing spaces.
453    element.className = newList.substring(1, newList.length - 1);
454  }
455
456  /**
457   * (Internal) Gets a space separated list of the class names on the element. 
458   * The list is wrapped with a single space on each end to facilitate finding 
459   * matches within the list.
460   */
461
462  function classList(element) {
463    return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' ');
464  }
465
466  /**
467   * (Internal) Removes an element from the DOM.
468   */
469
470  function removeElement(element) {
471    element && element.parentNode && element.parentNode.removeChild(element);
472  }
473
474  return NProgress;
475});
476

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.