(function() { var AjaxMonitor, Bar, DocumentMonitor, ElementMonitor, ElementTracker, EventLagMonitor, Events, RequestIntercept, SOURCE_KEYS, Scaler, SocketRequestTracker, XHRRequestTracker, animation, bar, cancelAnimation, cancelAnimationFrame, defaultOptions, extend, extendNative, firstLoad, getFromDOM, handlePushState, init, intercept, now, options, requestAnimationFrame, result, runAnimation, scalers, sources, uniScaler, _WebSocket, _XDomainRequest, _XMLHttpRequest, _pushState, _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: 500, initialRate: .03, minTime: 500, ghostTime: 250, maxProgressPerFrame: 10, easeFactor: 1.25, startOnPageLoad: true, restartOnPushState: true, restartOnBackboneRoute: true, target: 'body', elements: { checkInterval: 100, selectors: ['body'] }, eventLag: { minSamples: 10 }, ajax: { trackMethods: ['GET'], trackWebSockets: true } }; 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; last = now(); return fn(diff, function() { return requestAnimationFrame(tick); }); }; 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; }; 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; } }; if (window.Pace == null) { window.Pace = {}; } options = Pace.options = extend(defaultOptions, window.paceOptions, getFromDOM()); Bar = (function() { function Bar() { this.progress = 0; } Bar.prototype.getElement = function() { var targetElement; if (this.el == null) { this.el = document.createElement('div'); this.el.className = "pace pace-active"; this.el.innerHTML = '
\n
\n
\n
'; targetElement = document.querySelector(options.target); 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', ''); return el.className += ' pace-inactive'; }; Bar.prototype.update = function(prog) { this.progress = prog; return this.render(); }; Bar.prototype.destroy = function() { this.getElement().parentNode.removeChild(this.getElement()); return this.el = void 0; }; Bar.prototype.render = function() { var el, progressStr; if (document.querySelector(options.target) == null) { return false; } el = this.getElement(); el.children[0].style.width = "" + this.progress + "%"; if (!this.lastRenderedProgress || this.lastRenderedProgress | 0 !== this.progress | 0) { el.setAttribute('data-progress-text', "" + (this.progress | 0) + "%"); if (this.progress >= 100) { progressStr = '99'; } else { progressStr = this.progress < 10 ? "0" : ""; progressStr += this.progress | 0; } el.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, _i, _len, _ref, _results; if (this.bindings[name] != null) { _ref = this.bindings[name]; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { binding = _ref[_i]; _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, val, _results; _results = []; for (key in from.prototype) { try { val = from.prototype[key]; if ((to[key] == null) && typeof val !== 'function') { _results.push(to[key] = val); } else { _results.push(void 0); } } catch (_error) { e = _error; } } return _results; }; 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) { var _ref; if (_ref = (type != null ? type : 'GET').toUpperCase(), __indexOf.call(options.ajax.trackMethods, _ref) >= 0) { _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; }; extendNative(window.XMLHttpRequest, _XMLHttpRequest); if (_XDomainRequest != null) { window.XDomainRequest = function() { var req; req = new _XDomainRequest; monitorXHR(req); return req; }; extendNative(window.XDomainRequest, _XDomainRequest); } if ((_WebSocket != null) && options.ajax.trackWebSockets) { window.WebSocket = function(url, protocols) { var req; req = new _WebSocket(url, protocols); _this.trigger('request', { type: 'socket', url: url, protocols: protocols, request: req }); return req; }; extendNative(window.WebSocket, _WebSocket); } } return RequestIntercept; })(Events); intercept = new RequestIntercept; AjaxMonitor = (function() { function AjaxMonitor() { var _this = this; this.elements = []; intercept.on('request', function() { return _this.watch.apply(_this, arguments); }); } AjaxMonitor.prototype.watch = function(_arg) { var request, tracker, type; type = _arg.type, request = _arg.request; 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, _i, _len, _onreadystatechange, _ref, _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; } }); _ref = ['load', 'abort', 'timeout', 'error']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; request.addEventListener(event, function() { return _this.progress = 100; }); } } else { _onreadystatechange = request.onreadystatechange; request.onreadystatechange = function() { var _ref1; if ((_ref1 = request.readyState) === 0 || _ref1 === 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, _i, _len, _ref, _this = this; this.progress = 0; _ref = ['error', 'open']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { event = _ref[_i]; request.addEventListener(event, function() { return _this.progress = 100; }); } } return SocketRequestTracker; })(); ElementMonitor = (function() { function ElementMonitor(options) { var selector, _i, _len, _ref; if (options == null) { options = {}; } this.elements = []; if (options.selectors == null) { options.selectors = []; } _ref = options.selectors; for (_i = 0, _len = _ref.length; _i < _len; _i++) { selector = _ref[_i]; 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, _ref, _this = this; this.progress = (_ref = this.states[document.readyState]) != null ? _ref : 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, last, points, _this = this; this.progress = 0; avg = 0; points = 0; last = now(); setInterval(function() { var diff; diff = now() - last - 50; last = now(); avg = avg + (diff - avg) / 15; if (points++ > options.eventLag.minSamples && Math.abs(avg) < 3) { avg = 0; } 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; 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); }; } firstLoad = true; if (options.restartOnBackboneRoute) { setTimeout(function() { if (window.Backbone == null) { return; } return Backbone.history.on('route', function(router, name) { var routeName, rule, _i, _len, _results; if (!(rule = options.restartOnBackboneRoute)) { return; } if (firstLoad) { firstLoad = false; return; } if (typeof rule === 'object') { _results = []; for (_i = 0, _len = rule.length; _i < _len; _i++) { routeName = rule[_i]; if (!(routeName === name)) { continue; } Pace.restart(); break; } return _results; } else { return Pace.restart(); } }); }, 0); } SOURCE_KEYS = { ajax: AjaxMonitor, elements: ElementMonitor, document: DocumentMonitor, eventLag: EventLagMonitor }; (init = function() { var source, type, _i, _j, _len, _len1, _ref, _ref1, _ref2; Pace.sources = sources = []; _ref = ['ajax', 'elements', 'document', 'eventLag']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { type = _ref[_i]; if (options[type] !== false) { sources.push(new SOURCE_KEYS[type](options[type])); } } _ref2 = (_ref1 = options.extraSources) != null ? _ref1 : []; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { source = _ref2[_j]; sources.push(new source(options)); } Pace.bar = bar = new Bar; scalers = []; return uniScaler = new Scaler; })(); Pace.stop = function() { bar.destroy(); cancelAnimation = true; if (animation != null) { if (typeof cancelAnimationFrame === "function") { cancelAnimationFrame(animation); } animation = null; } return init(); }; Pace.restart = function() { Pace.stop(); return Pace.go(); }; Pace.go = function() { bar.render(); cancelAnimation = false; return animation = runAnimation(function(frameTime, enqueueNextFrame) { var avg, count, done, element, elements, i, j, remaining, scaler, scalerList, source, start, sum, _i, _j, _len, _len1, _ref; remaining = 100 - bar.progress; count = sum = 0; done = true; for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) { source = sources[i]; scalerList = scalers[i] != null ? scalers[i] : scalers[i] = []; elements = (_ref = source.elements) != null ? _ref : [source]; for (j = _j = 0, _len1 = elements.length; _j < _len1; j = ++_j) { 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)); start = now(); if (bar.done() || done || cancelAnimation) { bar.update(100); return setTimeout(function() { return bar.finish(); }, Math.max(options.ghostTime, Math.min(options.minTime, now() - start))); } else { return enqueueNextFrame(); } }); }; Pace.start = function(_options) { extend(options, _options); bar.render(); if (!document.querySelector('.pace')) { return setTimeout(Pace.start, 50); } else { return Pace.go(); } }; if (typeof define === 'function' && define.amd) { define(function() { return Pace; }); } else if (typeof exports === 'object') { module.exports = Pace; } else { if (options.startOnPageLoad) { Pace.start(); } } }).call(this);