User:Ladsgroup/pace.js

// From https://github.com/HubSpot/pace // License: MIT (function { var AjaxMonitor, Bar, DocumentMonitor, ElementMonitor, ElementTracker, EventLagMonitor, Evented, Events, NoTargetError, Pace, RequestIntercept, SOURCE_KEYS, Scaler, SocketRequestTracker, XHRRequestTracker, animation, avgAmplitude, bar, cancelAnimation, cancelAnimationFrame, defaultOptions, extend, extendNative, getFromDOM, getIntercept, handlePushState, ignoreStack, init, now, options, requestAnimationFrame, result, runAnimation, scalers, shouldIgnoreURL, shouldTrack, source, sources, uniScaler, _WebSocket, _XDomainRequest, _XMLHttpRequest, _i, _intercept, _len, _pushState, _ref, _ref1, _replaceState,    __slice = [].slice,    __hasProp = {}.hasOwnProperty,    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

defaultOptions = { catchupTime: 100, initialRate: .03, minTime: 250, ghostTime: 100, maxProgressPerFrame: 20, easeFactor: 1.25, startOnPageLoad: true, restartOnPushState: true, restartOnRequestAfter: 500, target: 'body', elements: { checkInterval: 100, selectors: ['body'] },   eventLag: { minSamples: 10, sampleCount: 3, lagThreshold: 3 },   ajax: { trackMethods: ['GET'], trackWebSockets: true, ignoreURLs: [] } };

now = function { var _ref; return (_ref = typeof performance !== "undefined" && performance !== null ? typeof performance.now === "function" ? performance.now : void 0 : void 0) != null ? _ref : +(new Date); };

requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;

cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;

if (requestAnimationFrame == null) { requestAnimationFrame = function(fn) { return setTimeout(fn, 50); };   cancelAnimationFrame = function(id) { return clearTimeout(id); }; }

runAnimation = function(fn) { var last, tick; last = now; tick = function { var diff; diff = now - last; if (diff >= 33) { last = now; return fn(diff, function {         return requestAnimationFrame(tick);        }); } else { return setTimeout(tick, 33 - diff); }   };    return tick; };

result = function { var args, key, obj; obj = arguments[0], key = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; if (typeof obj[key] === 'function') { return obj[key].apply(obj, args); } else { return obj[key]; } };

extend = function { var key, out, source, sources, val, _i, _len; out = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : []; for (_i = 0, _len = sources.length; _i < _len; _i++) { source = sources[_i]; if (source) { for (key in source) { if (!__hasProp.call(source, key)) continue; val = source[key]; if ((out[key] != null) && typeof out[key] === 'object' && (val != null) && typeof val === 'object') { extend(out[key], val); } else { out[key] = val; }       }      }    }    return out; };

avgAmplitude = function(arr) { var count, sum, v, _i, _len; sum = count = 0; for (_i = 0, _len = arr.length; _i < _len; _i++) { v = arr[_i]; sum += Math.abs(v); count++; }   return sum / count; };

getFromDOM = function(key, json) { var data, e, el; if (key == null) { key = 'options'; }   if (json == null) { json = true; }   el = document.querySelector("[data-pace-" + key + "]"); if (!el) { return; }   data = el.getAttribute("data-pace-" + key); if (!json) { return data; }   try { return JSON.parse(data); } catch (_error) { e = _error; return typeof console !== "undefined" && console !== null ? console.error("Error parsing inline pace options", e) : void 0; } };

Evented = (function {   function Evented {}

Evented.prototype.on = function(event, handler, ctx, once) { var _base; if (once == null) { once = false; }     if (this.bindings == null) { this.bindings = {}; }     if ((_base = this.bindings)[event] == null) { _base[event] = []; }     return this.bindings[event].push({        handler: handler,        ctx: ctx,        once: once      }); };

Evented.prototype.once = function(event, handler, ctx) { return this.on(event, handler, ctx, true); };

Evented.prototype.off = function(event, handler) { var i, _ref, _results; if (((_ref = this.bindings) != null ? _ref[event] : void 0) == null) { return; }     if (handler == null) { return delete this.bindings[event]; } else { i = 0; _results = []; while (i < this.bindings[event].length) { if (this.bindings[event][i].handler === handler) { _results.push(this.bindings[event].splice(i, 1)); } else { _results.push(i++); }       }        return _results; }   };

Evented.prototype.trigger = function { var args, ctx, event, handler, i, once, _ref, _ref1, _results; event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; if ((_ref = this.bindings) != null ? _ref[event] : void 0) { i = 0; _results = []; while (i < this.bindings[event].length) { _ref1 = this.bindings[event][i], handler = _ref1.handler, ctx = _ref1.ctx, once = _ref1.once; handler.apply(ctx != null ? ctx : this, args); if (once) { _results.push(this.bindings[event].splice(i, 1)); } else { _results.push(i++); }       }        return _results; }   };

return Evented;

});

Pace = window.Pace || {};

window.Pace = Pace;

extend(Pace, Evented.prototype);

options = Pace.options = extend({}, defaultOptions, window.paceOptions, getFromDOM);

_ref = ['ajax', 'document', 'eventLag', 'elements']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { source = _ref[_i]; if (options[source] === true) { options[source] = defaultOptions[source]; } }

NoTargetError = (function(_super) {   __extends(NoTargetError, _super);

function NoTargetError { _ref1 = NoTargetError.__super__.constructor.apply(this, arguments); return _ref1; }

return NoTargetError;

})(Error);

Bar = (function {   function Bar {      this.progress = 0;    }

Bar.prototype.getElement = function { var targetElement; if (this.el == null) { targetElement = document.querySelector(options.target); if (!targetElement) { throw new NoTargetError; }       this.el = document.createElement('div'); this.el.className = "pace pace-active"; document.body.className = document.body.className.replace(/pace-done/g, ''); document.body.className += ' pace-running'; this.el.innerHTML = ' \n \n \n '; if (targetElement.firstChild != null) { targetElement.insertBefore(this.el, targetElement.firstChild); } else { targetElement.appendChild(this.el); }     }      return this.el; };

Bar.prototype.finish = function { var el; el = this.getElement; el.className = el.className.replace('pace-active', ''); el.className += ' pace-inactive'; document.body.className = document.body.className.replace('pace-running', ''); return document.body.className += ' pace-done'; };

Bar.prototype.update = function(prog) { this.progress = prog; return this.render; };

Bar.prototype.destroy = function { try { this.getElement.parentNode.removeChild(this.getElement); } catch (_error) { NoTargetError = _error; }     return this.el = void 0; };

Bar.prototype.render = function { var el, key, progressStr, transform, _j, _len1, _ref2; if (document.querySelector(options.target) == null) { return false; }     el = this.getElement; transform = "translate3d(" + this.progress + "%, 0, 0)"; _ref2 = ['webkitTransform', 'msTransform', 'transform']; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { key = _ref2[_j]; el.children[0].style[key] = transform; }     if (!this.lastRenderedProgress || this.lastRenderedProgress | 0 !== this.progress | 0) { el.children[0].setAttribute('data-progress-text', "" + (this.progress | 0) + "%"); if (this.progress >= 100) { progressStr = '99'; } else { progressStr = this.progress < 10 ? "0" : "";         progressStr += this.progress | 0; }       el.children[0].setAttribute('data-progress', "" + progressStr); }     return this.lastRenderedProgress = this.progress; };

Bar.prototype.done = function { return this.progress >= 100; };

return Bar;

});

Events = (function {   function Events {      this.bindings = {};    }

Events.prototype.trigger = function(name, val) { var binding, _j, _len1, _ref2, _results; if (this.bindings[name] != null) { _ref2 = this.bindings[name]; _results = []; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { binding = _ref2[_j]; _results.push(binding.call(this, val)); }       return _results; }   };

Events.prototype.on = function(name, fn) { var _base; if ((_base = this.bindings)[name] == null) { _base[name] = []; }     return this.bindings[name].push(fn); };

return Events;

});

_XMLHttpRequest = window.XMLHttpRequest;

_XDomainRequest = window.XDomainRequest;

_WebSocket = window.WebSocket;

extendNative = function(to, from) { var e, key, _results; _results = []; for (key in from.prototype) { try { if ((to[key] == null) && typeof from[key] !== 'function') { if (typeof Object.defineProperty === 'function') { _results.push(Object.defineProperty(to, key, { get: function { return from.prototype[key]; },             configurable: true, enumerable: true }));         } else { _results.push(to[key] = from.prototype[key]); }       } else { _results.push(void 0); }     } catch (_error) { e = _error; }   }    return _results; };

ignoreStack = [];

Pace.ignore = function { var args, fn, ret; fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; ignoreStack.unshift('ignore'); ret = fn.apply(null, args); ignoreStack.shift; return ret; };

Pace.track = function { var args, fn, ret; fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; ignoreStack.unshift('track'); ret = fn.apply(null, args); ignoreStack.shift; return ret; };

shouldTrack = function(method) { var _ref2; if (method == null) { method = 'GET'; }   if (ignoreStack[0] === 'track') { return 'force'; }   if (!ignoreStack.length && options.ajax) { if (method === 'socket' && options.ajax.trackWebSockets) { return true; } else if (_ref2 = method.toUpperCase, __indexOf.call(options.ajax.trackMethods, _ref2) >= 0) { return true; }   }    return false; };

RequestIntercept = (function(_super) {   __extends(RequestIntercept, _super);

function RequestIntercept { var monitorXHR, _this = this; RequestIntercept.__super__.constructor.apply(this, arguments); monitorXHR = function(req) { var _open; _open = req.open; return req.open = function(type, url, async) { if (shouldTrack(type)) { _this.trigger('request', {             type: type,              url: url,              request: req            }); }         return _open.apply(req, arguments); };     };      window.XMLHttpRequest = function(flags) { var req; req = new _XMLHttpRequest(flags); monitorXHR(req); return req; };     try { extendNative(window.XMLHttpRequest, _XMLHttpRequest); } catch (_error) {} if (_XDomainRequest != null) { window.XDomainRequest = function { var req; req = new _XDomainRequest; monitorXHR(req); return req; };       try { extendNative(window.XDomainRequest, _XDomainRequest); } catch (_error) {} }     if ((_WebSocket != null) && options.ajax.trackWebSockets) { window.WebSocket = function(url, protocols) { var req; if (protocols != null) { req = new _WebSocket(url, protocols); } else { req = new _WebSocket(url); }         if (shouldTrack('socket')) { _this.trigger('request', {             type: 'socket',              url: url,              protocols: protocols,              request: req            }); }         return req; };       try { extendNative(window.WebSocket, _WebSocket); } catch (_error) {} }   }

return RequestIntercept;

})(Events);

_intercept = null;

getIntercept = function { if (_intercept == null) { _intercept = new RequestIntercept; }   return _intercept; };

shouldIgnoreURL = function(url) { var pattern, _j, _len1, _ref2; _ref2 = options.ajax.ignoreURLs; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { pattern = _ref2[_j]; if (typeof pattern === 'string') { if (url.indexOf(pattern) !== -1) { return true; }     } else { if (pattern.test(url)) { return true; }     }    }    return false; };

getIntercept.on('request', function(_arg) {   var after, args, request, type, url;    type = _arg.type, request = _arg.request, url = _arg.url;    if (shouldIgnoreURL(url)) {      return;    }    if (!Pace.running && (options.restartOnRequestAfter !== false || shouldTrack(type) === 'force')) {      args = arguments;      after = options.restartOnRequestAfter || 0;      if (typeof after === 'boolean') {        after = 0;      }      return setTimeout(function { var stillActive, _j, _len1, _ref2, _ref3, _results; if (type === 'socket') { stillActive = request.readyState < 2; } else { stillActive = (0 < (_ref2 = request.readyState) && _ref2 < 4); }       if (stillActive) { Pace.restart; _ref3 = Pace.sources; _results = []; for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { source = _ref3[_j]; if (source instanceof AjaxMonitor) { source.watch.apply(source, args); break; } else { _results.push(void 0); }         }          return _results; }     }, after);    }  });

AjaxMonitor = (function {   function AjaxMonitor {      var _this = this;      this.elements = [];      getIntercept.on('request', function { return _this.watch.apply(_this, arguments); });   }

AjaxMonitor.prototype.watch = function(_arg) { var request, tracker, type, url; type = _arg.type, request = _arg.request, url = _arg.url; if (shouldIgnoreURL(url)) { return; }     if (type === 'socket') { tracker = new SocketRequestTracker(request); } else { tracker = new XHRRequestTracker(request); }     return this.elements.push(tracker); };

return AjaxMonitor;

});

XHRRequestTracker = (function {   function XHRRequestTracker(request) {      var event, size, _j, _len1, _onreadystatechange, _ref2,        _this = this;      this.progress = 0;      if (window.ProgressEvent != null) {        size = null;        request.addEventListener('progress', function(evt) { if (evt.lengthComputable) { return _this.progress = 100 * evt.loaded / evt.total; } else { return _this.progress = _this.progress + (100 - _this.progress) / 2; }       }, false);        _ref2 = ['load', 'abort', 'timeout', 'error'];        for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {          event = _ref2[_j];          request.addEventListener(event, function { return _this.progress = 100; }, false);       }      } else {        _onreadystatechange = request.onreadystatechange;        request.onreadystatechange = function {          var _ref3;          if ((_ref3 = request.readyState) === 0 || _ref3 === 4) {            _this.progress = 100;          } else if (request.readyState === 3) {            _this.progress = 50;          }          return typeof _onreadystatechange === "function" ? _onreadystatechange.apply(null, arguments) : void 0;        };      }    }

return XHRRequestTracker;

});

SocketRequestTracker = (function {   function SocketRequestTracker(request) {      var event, _j, _len1, _ref2,        _this = this;      this.progress = 0;      _ref2 = ['error', 'open'];      for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {        event = _ref2[_j];        request.addEventListener(event, function { return _this.progress = 100; }, false);     }    }

return SocketRequestTracker;

});

ElementMonitor = (function {   function ElementMonitor(options) {      var selector, _j, _len1, _ref2;      if (options == null) {        options = {};      }      this.elements = [];      if (options.selectors == null) {        options.selectors = [];      }      _ref2 = options.selectors;      for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {        selector = _ref2[_j];        this.elements.push(new ElementTracker(selector));      }    }

return ElementMonitor;

});

ElementTracker = (function {   function ElementTracker(selector) {      this.selector = selector;      this.progress = 0;      this.check;    }

ElementTracker.prototype.check = function { var _this = this; if (document.querySelector(this.selector)) { return this.done; } else { return setTimeout((function { return _this.check; }), options.elements.checkInterval); }   };

ElementTracker.prototype.done = function { return this.progress = 100; };

return ElementTracker;

});

DocumentMonitor = (function {   DocumentMonitor.prototype.states = {      loading: 0,      interactive: 50,      complete: 100    };

function DocumentMonitor { var _onreadystatechange, _ref2, _this = this; this.progress = (_ref2 = this.states[document.readyState]) != null ? _ref2 : 100; _onreadystatechange = document.onreadystatechange; document.onreadystatechange = function { if (_this.states[document.readyState] != null) { _this.progress = _this.states[document.readyState]; }       return typeof _onreadystatechange === "function" ? _onreadystatechange.apply(null, arguments) : void 0; };   }

return DocumentMonitor;

});

EventLagMonitor = (function {   function EventLagMonitor {      var avg, interval, last, points, samples,        _this = this;      this.progress = 0;      avg = 0;      samples = [];      points = 0;      last = now;      interval = setInterval(function { var diff; diff = now - last - 50; last = now; samples.push(diff); if (samples.length > options.eventLag.sampleCount) { samples.shift; }       avg = avgAmplitude(samples); if (++points >= options.eventLag.minSamples && avg < options.eventLag.lagThreshold) { _this.progress = 100; return clearInterval(interval); } else { return _this.progress = 100 * (3 / (avg + 3)); }     }, 50);    }

return EventLagMonitor;

});

Scaler = (function {   function Scaler(source) {      this.source = source;      this.last = this.sinceLastUpdate = 0;      this.rate = options.initialRate;      this.catchup = 0;      this.progress = this.lastProgress = 0;      if (this.source != null) {        this.progress = result(this.source, 'progress');      }    }

Scaler.prototype.tick = function(frameTime, val) { var scaling; if (val == null) { val = result(this.source, 'progress'); }     if (val >= 100) { this.done = true; }     if (val === this.last) { this.sinceLastUpdate += frameTime; } else { if (this.sinceLastUpdate) { this.rate = (val - this.last) / this.sinceLastUpdate; }       this.catchup = (val - this.progress) / options.catchupTime; this.sinceLastUpdate = 0; this.last = val; }     if (val > this.progress) { this.progress += this.catchup * frameTime; }     scaling = 1 - Math.pow(this.progress / 100, options.easeFactor); this.progress += scaling * this.rate * frameTime; this.progress = Math.min(this.lastProgress + options.maxProgressPerFrame, this.progress); this.progress = Math.max(0, this.progress); this.progress = Math.min(100, this.progress); this.lastProgress = this.progress; return this.progress; };

return Scaler;

});

sources = null;

scalers = null;

bar = null;

uniScaler = null;

animation = null;

cancelAnimation = null;

Pace.running = false;

handlePushState = function { if (options.restartOnPushState) { return Pace.restart; } };

if (window.history.pushState != null) { _pushState = window.history.pushState; window.history.pushState = function { handlePushState; return _pushState.apply(window.history, arguments); }; }

if (window.history.replaceState != null) { _replaceState = window.history.replaceState; window.history.replaceState = function { handlePushState; return _replaceState.apply(window.history, arguments); }; }

SOURCE_KEYS = { ajax: AjaxMonitor, elements: ElementMonitor, document: DocumentMonitor, eventLag: EventLagMonitor };

(init = function {   var type, _j, _k, _len1, _len2, _ref2, _ref3, _ref4;    Pace.sources = sources = [];    _ref2 = ['ajax', 'elements', 'document', 'eventLag'];    for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {      type = _ref2[_j];      if (options[type] !== false) {        sources.push(new SOURCE_KEYS[type](options[type]));      }    }    _ref4 = (_ref3 = options.extraSources) != null ? _ref3 : [];    for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {      source = _ref4[_k];      sources.push(new source(options));    }    Pace.bar = bar = new Bar;    scalers = [];    return uniScaler = new Scaler;  });

Pace.stop = function { Pace.trigger('stop'); Pace.running = false; bar.destroy; cancelAnimation = true; if (animation != null) { if (typeof cancelAnimationFrame === "function") { cancelAnimationFrame(animation); }     animation = null; }   return init; };

Pace.restart = function { Pace.trigger('restart'); Pace.stop; return Pace.start; };

Pace.go = function { var start; Pace.running = true; bar.render; start = now; cancelAnimation = false; return animation = runAnimation(function(frameTime, enqueueNextFrame) {     var avg, count, done, element, elements, i, j, remaining, scaler, scalerList, sum, _j, _k, _len1, _len2, _ref2;      remaining = 100 - bar.progress;      count = sum = 0;      done = true;      for (i = _j = 0, _len1 = sources.length; _j < _len1; i = ++_j) {        source = sources[i];        scalerList = scalers[i] != null ? scalers[i] : scalers[i] = [];        elements = (_ref2 = source.elements) != null ? _ref2 : [source];        for (j = _k = 0, _len2 = elements.length; _k < _len2; j = ++_k) {          element = elements[j];          scaler = scalerList[j] != null ? scalerList[j] : scalerList[j] = new Scaler(element);          done &= scaler.done;          if (scaler.done) {            continue;          }          count++;          sum += scaler.tick(frameTime);        }      }      avg = sum / count;      bar.update(uniScaler.tick(frameTime, avg)); if (bar.done || done || cancelAnimation) { bar.update(100); Pace.trigger('done'); return setTimeout(function {         bar.finish;          Pace.running = false;          return Pace.trigger('hide');        }, Math.max(options.ghostTime, Math.max(options.minTime - (now - start), 0))); } else { return enqueueNextFrame; }   });  };

Pace.start = function(_options) { extend(options, _options); Pace.running = true; try { bar.render; } catch (_error) { NoTargetError = _error; }   if (!document.querySelector('.pace')) { return setTimeout(Pace.start, 50); } else { Pace.trigger('start'); return Pace.go; } };

if (typeof define === 'function' && define.amd) { define(['pace'], function {     return Pace;    }); } else if (typeof exports === 'object') { module.exports = Pace; } else { if (options.startOnPageLoad) { Pace.start; } }

}).call(this);