balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

nprogress.js (11565B)


      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