source/js/_files/barba.js
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("Barba", [], factory);
else if(typeof exports === 'object')
exports["Barba"] = factory();
else
root["Barba"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "http://localhost:8080/dist";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
//Promise polyfill https://github.com/taylorhakes/promise-polyfill
if (typeof Promise !== 'function') {
window.Promise = __webpack_require__(1);
}
var Barba = {
version: '1.0.0',
BaseTransition: __webpack_require__(5),
BaseView: __webpack_require__(7),
BaseCache: __webpack_require__(9),
Dispatcher: __webpack_require__(8),
HistoryManager: __webpack_require__(10),
Pjax: __webpack_require__(11),
Prefetch: __webpack_require__(14),
Utils: __webpack_require__(6)
};
module.exports = Barba;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(setImmediate) {(function (root) {
// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;
function noop() {
}
// Use polyfill for setImmediate for performance gains
var asap = (typeof setImmediate === 'function' && setImmediate) ||
function (fn) {
setTimeoutFunc(fn, 0);
};
var onUnhandledRejection = function onUnhandledRejection(err) {
if (typeof console !== 'undefined' && console) {
console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
}
};
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function () {
fn.apply(thisArg, arguments);
};
}
function Promise(fn) {
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = 0;
this._handled = false;
this._value = undefined;
this._deferreds = [];
doResolve(fn, this);
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
asap(function () {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
}
function resolve(self, newValue) {
try {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
asap(function() {
if (!self._handled) {
onUnhandledRejection(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, self) {
var done = false;
try {
fn(function (value) {
if (done) return;
done = true;
resolve(self, value);
}, function (reason) {
if (done) return;
done = true;
reject(self, reason);
});
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
}
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function (onFulfilled, onRejected) {
var prom = new (this.constructor)(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.all = function (arr) {
var args = Array.prototype.slice.call(arr);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(val, function (val) {
res(i, val);
}, reject);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function (value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function (resolve) {
resolve(value);
});
};
Promise.reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
};
Promise.race = function (values) {
return new Promise(function (resolve, reject) {
for (var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
/**
* Set the immediate function to execute callbacks
* @param fn {function} Function to execute
* @private
*/
Promise._setImmediateFn = function _setImmediateFn(fn) {
asap = fn;
};
Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
onUnhandledRejection = fn;
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = Promise;
} else if (!root.Promise) {
root.Promise = Promise;
}
})(this);
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2).setImmediate))
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var apply = Function.prototype.apply;
// DOM APIs, for completeness
exports.setTimeout = function() {
return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
};
exports.setInterval = function() {
return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
};
exports.clearTimeout =
exports.clearInterval = function(timeout) {
if (timeout) {
timeout.close();
}
};
function Timeout(id, clearFn) {
this._id = id;
this._clearFn = clearFn;
}
Timeout.prototype.unref = Timeout.prototype.ref = function() {};
Timeout.prototype.close = function() {
this._clearFn.call(window, this._id);
};
// Does not start the time, just sets up the members needed.
exports.enroll = function(item, msecs) {
clearTimeout(item._idleTimeoutId);
item._idleTimeout = msecs;
};
exports.unenroll = function(item) {
clearTimeout(item._idleTimeoutId);
item._idleTimeout = -1;
};
exports._unrefActive = exports.active = function(item) {
clearTimeout(item._idleTimeoutId);
var msecs = item._idleTimeout;
if (msecs >= 0) {
item._idleTimeoutId = setTimeout(function onTimeout() {
if (item._onTimeout)
item._onTimeout();
}, msecs);
}
};
// setimmediate attaches itself to the global object
__webpack_require__(3);
exports.setImmediate = setImmediate;
exports.clearImmediate = clearImmediate;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) {
"use strict";
if (global.setImmediate) {
return;
}
var nextHandle = 1; // Spec says greater than zero
var tasksByHandle = {};
var currentlyRunningATask = false;
var doc = global.document;
var registerImmediate;
function setImmediate(callback) {
// Callback can either be a function or a string
if (typeof callback !== "function") {
callback = new Function("" + callback);
}
// Copy function arguments
var args = new Array(arguments.length - 1);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i + 1];
}
// Store and register the task
var task = { callback: callback, args: args };
tasksByHandle[nextHandle] = task;
registerImmediate(nextHandle);
return nextHandle++;
}
function clearImmediate(handle) {
delete tasksByHandle[handle];
}
function run(task) {
var callback = task.callback;
var args = task.args;
switch (args.length) {
case 0:
callback();
break;
case 1:
callback(args[0]);
break;
case 2:
callback(args[0], args[1]);
break;
case 3:
callback(args[0], args[1], args[2]);
break;
default:
callback.apply(undefined, args);
break;
}
}
function runIfPresent(handle) {
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
// So if we're currently running a task, we'll need to delay this invocation.
if (currentlyRunningATask) {
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
// "too much recursion" error.
setTimeout(runIfPresent, 0, handle);
} else {
var task = tasksByHandle[handle];
if (task) {
currentlyRunningATask = true;
try {
run(task);
} finally {
clearImmediate(handle);
currentlyRunningATask = false;
}
}
}
}
function installNextTickImplementation() {
registerImmediate = function(handle) {
process.nextTick(function () { runIfPresent(handle); });
};
}
function canUsePostMessage() {
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
// where `global.postMessage` means something completely different and can't be used for this purpose.
if (global.postMessage && !global.importScripts) {
var postMessageIsAsynchronous = true;
var oldOnMessage = global.onmessage;
global.onmessage = function() {
postMessageIsAsynchronous = false;
};
global.postMessage("", "*");
global.onmessage = oldOnMessage;
return postMessageIsAsynchronous;
}
}
function installPostMessageImplementation() {
// Installs an event handler on `global` for the `message` event: see
// * https://developer.mozilla.org/en/DOM/window.postMessage
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
var messagePrefix = "setImmediate$" + Math.random() + "$";
var onGlobalMessage = function(event) {
if (event.source === global &&
typeof event.data === "string" &&
event.data.indexOf(messagePrefix) === 0) {
runIfPresent(+event.data.slice(messagePrefix.length));
}
};
if (global.addEventListener) {
global.addEventListener("message", onGlobalMessage, false);
} else {
global.attachEvent("onmessage", onGlobalMessage);
}
registerImmediate = function(handle) {
global.postMessage(messagePrefix + handle, "*");
};
}
function installMessageChannelImplementation() {
var channel = new MessageChannel();
channel.port1.onmessage = function(event) {
var handle = event.data;
runIfPresent(handle);
};
registerImmediate = function(handle) {
channel.port2.postMessage(handle);
};
}
function installReadyStateChangeImplementation() {
var html = doc.documentElement;
registerImmediate = function(handle) {
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
var script = doc.createElement("script");
script.onreadystatechange = function () {
runIfPresent(handle);
script.onreadystatechange = null;
html.removeChild(script);
script = null;
};
html.appendChild(script);
};
}
function installSetTimeoutImplementation() {
registerImmediate = function(handle) {
setTimeout(runIfPresent, 0, handle);
};
}
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
// Don't get fooled by e.g. browserify environments.
if ({}.toString.call(global.process) === "[object process]") {
// For Node.js before 0.9
installNextTickImplementation();
} else if (canUsePostMessage()) {
// For non-IE10 modern browsers
installPostMessageImplementation();
} else if (global.MessageChannel) {
// For web workers, where supported
installMessageChannelImplementation();
} else if (doc && "onreadystatechange" in doc.createElement("script")) {
// For IE 6–8
installReadyStateChangeImplementation();
} else {
// For older browsers
installSetTimeoutImplementation();
}
attachTo.setImmediate = setImmediate;
attachTo.clearImmediate = clearImmediate;
}(typeof self === "undefined" ? typeof global === "undefined" ? this : global : self));
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(4)))
/***/ }),
/* 4 */
/***/ (function(module, exports) {
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
var Utils = __webpack_require__(6);
/**
* BaseTransition to extend
*
* @namespace Barba.BaseTransition
* @type {Object}
*/
var BaseTransition = {
/**
* @memberOf Barba.BaseTransition
* @type {HTMLElement}
*/
oldContainer: undefined,
/**
* @memberOf Barba.BaseTransition
* @type {HTMLElement}
*/
newContainer: undefined,
/**
* @memberOf Barba.BaseTransition
* @type {Promise}
*/
newContainerLoading: undefined,
/**
* Helper to extend the object
*
* @memberOf Barba.BaseTransition
* @param {Object} newObject
* @return {Object} newInheritObject
*/
extend: function(obj){
return Utils.extend(this, obj);
},
/**
* This function is called from Pjax module to initialize
* the transition.
*
* @memberOf Barba.BaseTransition
* @private
* @param {HTMLElement} oldContainer
* @param {Promise} newContainer
* @return {Promise}
*/
init: function(oldContainer, newContainer) {
var _this = this;
this.oldContainer = oldContainer;
this._newContainerPromise = newContainer;
this.deferred = Utils.deferred();
this.newContainerReady = Utils.deferred();
this.newContainerLoading = this.newContainerReady.promise;
this.start();
this._newContainerPromise.then(function(newContainer) {
_this.newContainer = newContainer;
_this.newContainerReady.resolve();
});
return this.deferred.promise;
},
/**
* This function needs to be called as soon the Transition is finished
*
* @memberOf Barba.BaseTransition
*/
done: function() {
this.oldContainer.parentNode.removeChild(this.oldContainer);
this.newContainer.style.visibility = 'visible';
this.deferred.resolve();
},
/**
* Constructor for your Transition
*
* @memberOf Barba.BaseTransition
* @abstract
*/
start: function() {},
};
module.exports = BaseTransition;
/***/ }),
/* 6 */
/***/ (function(module, exports) {
/**
* Just an object with some helpful functions
*
* @type {Object}
* @namespace Barba.Utils
*/
var Utils = {
/**
* 404 page setting, by default, the 404 page locates in /404/index.html, you can change the path by using `Barba.Utils.errorPageUrl = '/path/to/404'`
* @type {String}
* @default
*/
errorPageUrl: '/404/index.html',
/**
* Return the current url
*
* @memberOf Barba.Utils
* @return {String} currentUrl
*/
getCurrentUrl: function() {
return window.location.protocol + '//' +
window.location.host +
window.location.pathname +
window.location.search;
},
/**
* Given an url, return it without the hash
*
* @memberOf Barba.Utils
* @private
* @param {String} url
* @return {String} newCleanUrl
*/
cleanLink: function(url) {
return url.replace(/#.*/, '');
},
/**
* Time in millisecond after the xhr request goes in timeout
*
* @memberOf Barba.Utils
* @type {Number}
* @default
*/
xhrTimeout: 5000,
/**
* Start an XMLHttpRequest() and return a Promise
*
* @memberOf Barba.Utils
* @param {String} url
* @return {Promise}
*/
xhr: function(url) {
var deferred = this.deferred();
var req = new XMLHttpRequest();
const errorPageUrl = this.errorPageUrl
req.onreadystatechange = function() {
if (req.readyState === 4) {
if (req.status === 200) {
return deferred.resolve(req.responseText);
} else {
if (req.status === 404) {
/**
* if the status is 404, resend the
* XMLHttpRequest to get 404 page and prevent
* the 404 issue
*/
if (req.errorLoaded !== true) {
const errorUrl = window.location.protocol + '//' + window.location.host + errorPageUrl
req.errorLoaded = true
req.open('GET', errorUrl);
req.timeout = this.xhrTimeout;
req.setRequestHeader('x-barba', 'yes');
req.send();
} else {
alert('xhr: HTTP code is 404, but cannt find the 404 page')
window.history.back();
}
} else {
return deferred.reject(new Error('xhr: HTTP code is not 200'));
}
}
}
};
req.ontimeout = function() {
return deferred.reject(new Error('xhr: Timeout exceeded'));
};
req.open('GET', url);
req.timeout = this.xhrTimeout;
req.setRequestHeader('x-barba', 'yes');
req.send();
return deferred.promise;
},
/**
* Get obj and props and return a new object with the property merged
*
* @memberOf Barba.Utils
* @param {object} obj
* @param {object} props
* @return {object}
*/
extend: function(obj, props) {
var newObj = Object.create(obj);
for(var prop in props) {
if(props.hasOwnProperty(prop)) {
newObj[prop] = props[prop];
}
}
return newObj;
},
/**
* Return a new "Deferred" object
* https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
*
* @memberOf Barba.Utils
* @return {Deferred}
*/
deferred: function() {
return new function() {
this.resolve = null;
this.reject = null;
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this));
};
},
/**
* Return the port number normalized, eventually you can pass a string to be normalized.
*
* @memberOf Barba.Utils
* @private
* @param {String} p
* @return {Int} port
*/
getPort: function(p) {
var port = typeof p !== 'undefined' ? p : window.location.port;
var protocol = window.location.protocol;
if (port != '')
return parseInt(port);
if (protocol === 'http:')
return 80;
if (protocol === 'https:')
return 443;
}
};
module.exports = Utils;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
var Dispatcher = __webpack_require__(8);
var Utils = __webpack_require__(6);
/**
* BaseView to be extended
*
* @namespace Barba.BaseView
* @type {Object}
*/
var BaseView = {
/**
* Namespace of the view.
* (need to be associated with the data-namespace of the container)
*
* @memberOf Barba.BaseView
* @type {String}
*/
namespace: null,
/**
* Helper to extend the object
*
* @memberOf Barba.BaseView
* @param {Object} newObject
* @return {Object} newInheritObject
*/
extend: function(obj){
return Utils.extend(this, obj);
},
/**
* Init the view.
* P.S. Is suggested to init the view before starting Barba.Pjax.start(),
* in this way .onEnter() and .onEnterCompleted() will be fired for the current
* container when the page is loaded.
*
* @memberOf Barba.BaseView
*/
init: function() {
var _this = this;
Dispatcher.on('initStateChange',
function(newStatus, oldStatus) {
if (oldStatus && oldStatus.namespace === _this.namespace)
_this.onLeave();
}
);
Dispatcher.on('newPageReady',
function(newStatus, oldStatus, container) {
_this.container = container;
if (newStatus.namespace === _this.namespace)
_this.onEnter();
}
);
Dispatcher.on('transitionCompleted',
function(newStatus, oldStatus) {
if (newStatus.namespace === _this.namespace)
_this.onEnterCompleted();
if (oldStatus && oldStatus.namespace === _this.namespace)
_this.onLeaveCompleted();
}
);
},
/**
* This function will be fired when the container
* is ready and attached to the DOM.
*
* @memberOf Barba.BaseView
* @abstract
*/
onEnter: function() {},
/**
* This function will be fired when the transition
* to this container has just finished.
*
* @memberOf Barba.BaseView
* @abstract
*/
onEnterCompleted: function() {},
/**
* This function will be fired when the transition
* to a new container has just started.
*
* @memberOf Barba.BaseView
* @abstract
*/
onLeave: function() {},
/**
* This function will be fired when the container
* has just been removed from the DOM.
*
* @memberOf Barba.BaseView
* @abstract
*/
onLeaveCompleted: function() {}
}
module.exports = BaseView;
/***/ }),
/* 8 */
/***/ (function(module, exports) {
/**
* Little Dispatcher inspired by MicroEvent.js
*
* @namespace Barba.Dispatcher
* @type {Object}
*/
var Dispatcher = {
/**
* Object that keeps all the events
*
* @memberOf Barba.Dispatcher
* @readOnly
* @type {Object}
*/
events: {},
/**
* Bind a callback to an event
*
* @memberOf Barba.Dispatcher
* @param {String} eventName
* @param {Function} function
*/
on: function(e, f) {
this.events[e] = this.events[e] || [];
this.events[e].push(f);
},
/**
* Unbind event
*
* @memberOf Barba.Dispatcher
* @param {String} eventName
* @param {Function} function
*/
off: function(e, f) {
if(e in this.events === false)
return;
this.events[e].splice(this.events[e].indexOf(f), 1);
},
/**
* Fire the event running all the event associated to it
*
* @memberOf Barba.Dispatcher
* @param {String} eventName
* @param {...*} args
*/
trigger: function(e) {//e, ...args
if (e in this.events === false)
return;
for(var i = 0; i < this.events[e].length; i++){
this.events[e][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};
module.exports = Dispatcher;
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
var Utils = __webpack_require__(6);
/**
* BaseCache it's a simple static cache
*
* @namespace Barba.BaseCache
* @type {Object}
*/
var BaseCache = {
/**
* The Object that keeps all the key value information
*
* @memberOf Barba.BaseCache
* @type {Object}
*/
data: {},
/**
* Helper to extend this object
*
* @memberOf Barba.BaseCache
* @private
* @param {Object} newObject
* @return {Object} newInheritObject
*/
extend: function(obj) {
return Utils.extend(this, obj);
},
/**
* Set a key and value data, mainly Barba is going to save promises
*
* @memberOf Barba.BaseCache
* @param {String} key
* @param {*} value
*/
set: function(key, val) {
this.data[key] = val;
},
/**
* Retrieve the data using the key
*
* @memberOf Barba.BaseCache
* @param {String} key
* @return {*}
*/
get: function(key) {
return this.data[key];
},
/**
* Flush the cache
*
* @memberOf Barba.BaseCache
*/
reset: function() {
this.data = {};
}
};
module.exports = BaseCache;
/***/ }),
/* 10 */
/***/ (function(module, exports) {
/**
* HistoryManager helps to keep track of the navigation
*
* @namespace Barba.HistoryManager
* @type {Object}
*/
var HistoryManager = {
/**
* Keep track of the status in historic order
*
* @memberOf Barba.HistoryManager
* @readOnly
* @type {Array}
*/
history: [],
/**
* Add a new set of url and namespace
*
* @memberOf Barba.HistoryManager
* @param {String} url
* @param {String} namespace
* @private
*/
add: function(url, namespace) {
if (!namespace)
namespace = undefined;
this.history.push({
url: url,
namespace: namespace
});
},
/**
* Return information about the current status
*
* @memberOf Barba.HistoryManager
* @return {Object}
*/
currentStatus: function() {
return this.history[this.history.length - 1];
},
/**
* Return information about the previous status
*
* @memberOf Barba.HistoryManager
* @return {Object}
*/
prevStatus: function() {
var history = this.history;
if (history.length < 2)
return null;
return history[history.length - 2];
}
};
module.exports = HistoryManager;
/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {
var Utils = __webpack_require__(6);
var Dispatcher = __webpack_require__(8);
var HideShowTransition = __webpack_require__(12);
var BaseCache = __webpack_require__(9);
var HistoryManager = __webpack_require__(10);
var Dom = __webpack_require__(13);
/**
* Pjax is a static object with main function
*
* @namespace Barba.Pjax
* @borrows Dom as Dom
* @type {Object}
*/
var Pjax = {
Dom: Dom,
History: HistoryManager,
Cache: BaseCache,
/**
* Indicate wether or not use the cache
*
* @memberOf Barba.Pjax
* @type {Boolean}
* @default
*/
cacheEnabled: true,
/**
* Indicate if there is an animation in progress
*
* @memberOf Barba.Pjax
* @readOnly
* @type {Boolean}
*/
transitionProgress: false,
/**
* Class name used to ignore links
*
* @memberOf Barba.Pjax
* @type {String}
* @default
*/
ignoreClassLink: 'no-barba',
/**
* Function to be called to start Pjax
*
* @memberOf Barba.Pjax
*/
start: function() {
this.init();
},
/**
* Init the events
*
* @memberOf Barba.Pjax
* @private
*/
init: function() {
var container = this.Dom.getContainer();
var wrapper = this.Dom.getWrapper();
wrapper.setAttribute('aria-live', 'polite');
this.History.add(
this.getCurrentUrl(),
this.Dom.getNamespace(container)
);
//Fire for the current view.
Dispatcher.trigger('initStateChange', this.History.currentStatus());
Dispatcher.trigger('newPageReady',
this.History.currentStatus(),
{},
container,
this.Dom.currentHTML
);
Dispatcher.trigger('transitionCompleted', this.History.currentStatus());
this.bindEvents();
},
/**
* Attach the eventlisteners
*
* @memberOf Barba.Pjax
* @private
*/
bindEvents: function() {
document.addEventListener('click',
this.onLinkClick.bind(this)
);
window.addEventListener('popstate',
this.onStateChange.bind(this)
);
},
/**
* Return the currentURL cleaned
*
* @memberOf Barba.Pjax
* @return {String} currentUrl
*/
getCurrentUrl: function() {
return Utils.cleanLink(
Utils.getCurrentUrl()
);
},
/**
* Change the URL with pushstate and trigger the state change
*
* @memberOf Barba.Pjax
* @param {String} newUrl
*/
goTo: function(url) {
window.history.pushState(null, null, url);
this.onStateChange();
},
/**
* Force the browser to go to a certain url
*
* @memberOf Barba.Pjax
* @param {String} url
* @private
*/
forceGoTo: function(url) {
window.location = url;
},
/**
* Load an url, will start an xhr request or load from the cache
*
* @memberOf Barba.Pjax
* @private
* @param {String} url
* @return {Promise}
*/
load: function(url) {
var deferred = Utils.deferred();
var _this = this;
var xhr;
xhr = this.Cache.get(url);
if (!xhr) {
xhr = Utils.xhr(url);
this.Cache.set(url, xhr);
}
xhr.then(
function(data) {
var container = _this.Dom.parseResponse(data);
_this.Dom.putContainer(container);
if (!_this.cacheEnabled)
_this.Cache.reset();
deferred.resolve(container);
},
function() {
//Something went wrong (timeout, 404, 505...)
_this.forceGoTo(url);
deferred.reject();
}
);
return deferred.promise;
},
/**
* Get the .href parameter out of an element
* and handle special cases (like xlink:href)
*
* @private
* @memberOf Barba.Pjax
* @param {HTMLElement} el
* @return {String} href
*/
getHref: function(el) {
if (!el) {
return undefined;
}
if (el.getAttribute && typeof el.getAttribute('xlink:href') === 'string') {
return el.getAttribute('xlink:href');
}
if (typeof el.href === 'string') {
return el.href;
}
return undefined;
},
/**
* Callback called from click event
*
* @memberOf Barba.Pjax
* @private
* @param {MouseEvent} evt
*/
onLinkClick: function(evt) {
var el = evt.target;
//Go up in the nodelist until we
//find something with an href
while (el && !this.getHref(el)) {
el = el.parentNode;
}
if (this.preventCheck(evt, el)) {
evt.stopPropagation();
evt.preventDefault();
Dispatcher.trigger('linkClicked', el, evt);
var href = this.getHref(el);
this.goTo(href);
}
},
/**
* Determine if the link should be followed
*
* @memberOf Barba.Pjax
* @param {MouseEvent} evt
* @param {HTMLElement} element
* @return {Boolean}
*/
preventCheck: function(evt, element) {
if (!window.history.pushState)
return false;
var href = this.getHref(element);
//User
if (!element || !href)
return false;
//Middle click, cmd click, and ctrl click
if (evt.which > 1 || evt.metaKey || evt.ctrlKey || evt.shiftKey || evt.altKey)
return false;
//Ignore target with _blank target
if (element.target && element.target === '_blank')
return false;
//Check if it's the same domain
if (window.location.protocol !== element.protocol || window.location.hostname !== element.hostname)
return false;
//Check if the port is the same
if (Utils.getPort() !== Utils.getPort(element.port))
return false;
//Ignore case when a hash is being tacked on the current URL
if (href.indexOf('#') > -1)
return false;
//Ignore case where there is download attribute
if (element.getAttribute && typeof element.getAttribute('download') === 'string')
return false;
//In case you're trying to load the same page
if (Utils.cleanLink(href) == Utils.cleanLink(location.href))
return false;
if (element.classList.contains(this.ignoreClassLink))
return false;
return true;
},
/**
* Return a transition object
*
* @memberOf Barba.Pjax
* @return {Barba.Transition} Transition object
*/
getTransition: function() {
//User customizable
return HideShowTransition;
},
/**
* Method called after a 'popstate' or from .goTo()
*
* @memberOf Barba.Pjax
* @private
*/
onStateChange: function() {
var newUrl = this.getCurrentUrl();
if (this.transitionProgress)
this.forceGoTo(newUrl);
if (this.History.currentStatus().url === newUrl)
return false;
this.History.add(newUrl);
var newContainer = this.load(newUrl);
var transition = Object.create(this.getTransition());
this.transitionProgress = true;
Dispatcher.trigger('initStateChange',
this.History.currentStatus(),
this.History.prevStatus()
);
var transitionInstance = transition.init(
this.Dom.getContainer(),
newContainer
);
newContainer.then(
this.onNewContainerLoaded.bind(this)
);
transitionInstance.then(
this.onTransitionEnd.bind(this)
);
},
/**
* Function called as soon the new container is ready
*
* @memberOf Barba.Pjax
* @private
* @param {HTMLElement} container
*/
onNewContainerLoaded: function(container) {
var currentStatus = this.History.currentStatus();
currentStatus.namespace = this.Dom.getNamespace(container);
Dispatcher.trigger('newPageReady',
this.History.currentStatus(),
this.History.prevStatus(),
container,
this.Dom.currentHTML
);
},
/**
* Function called as soon the transition is finished
*
* @memberOf Barba.Pjax
* @private
*/
onTransitionEnd: function() {
this.transitionProgress = false;
Dispatcher.trigger('transitionCompleted',
this.History.currentStatus(),
this.History.prevStatus()
);
}
};
module.exports = Pjax;
/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {
var BaseTransition = __webpack_require__(5);
/**
* Basic Transition object, wait for the new Container to be ready,
* scroll top, and finish the transition (removing the old container and displaying the new one)
*
* @private
* @namespace Barba.HideShowTransition
* @augments Barba.BaseTransition
*/
var HideShowTransition = BaseTransition.extend({
start: function() {
this.newContainerLoading.then(this.finish.bind(this));
},
finish: function() {
document.body.scrollTop = 0;
this.done();
}
});
module.exports = HideShowTransition;
/***/ }),
/* 13 */
/***/ (function(module, exports) {
/**
* Object that is going to deal with DOM parsing/manipulation
*
* @namespace Barba.Pjax.Dom
* @type {Object}
*/
var Dom = {
/**
* The name of the data attribute on the container
*
* @memberOf Barba.Pjax.Dom
* @type {String}
* @default
*/
dataNamespace: 'namespace',
/**
* Id of the main wrapper
*
* @memberOf Barba.Pjax.Dom
* @type {String}
* @default
*/
wrapperId: 'barba-wrapper',
/**
* Class name used to identify the containers
*
* @memberOf Barba.Pjax.Dom
* @type {String}
* @default
*/
containerClass: 'barba-container',
/**
* Full HTML String of the current page.
* By default is the innerHTML of the initial loaded page.
*
* Each time a new page is loaded, the value is the response of the xhr call.
*
* @memberOf Barba.Pjax.Dom
* @type {String}
*/
currentHTML: document.documentElement.innerHTML,
/**
* Parse the responseText obtained from the xhr call
*
* @memberOf Barba.Pjax.Dom
* @private
* @param {String} responseText
* @return {HTMLElement}
*/
parseResponse: function(responseText) {
this.currentHTML = responseText;
var wrapper = document.createElement('div');
wrapper.innerHTML = responseText;
var titleEl = wrapper.querySelector('title');
if (titleEl)
document.title = titleEl.textContent;
return this.getContainer(wrapper);
},
/**
* Get the main barba wrapper by the ID `wrapperId`
*
* @memberOf Barba.Pjax.Dom
* @return {HTMLElement} element
*/
getWrapper: function() {
var wrapper = document.getElementById(this.wrapperId);
if (!wrapper)
throw new Error('Barba.js: wrapper not found!');
return wrapper;
},
/**
* Get the container on the current DOM,
* or from an HTMLElement passed via argument
*
* @memberOf Barba.Pjax.Dom
* @private
* @param {HTMLElement} element
* @return {HTMLElement}
*/
getContainer: function(element) {
if (!element)
element = document.body;
if (!element)
throw new Error('Barba.js: DOM not ready!');
var container = this.parseContainer(element);
if (container && container.jquery)
container = container[0];
if (!container)
throw new Error('Barba.js: no container found');
return container;
},
/**
* Get the namespace of the container
*
* @memberOf Barba.Pjax.Dom
* @private
* @param {HTMLElement} element
* @return {String}
*/
getNamespace: function(element) {
if (element && element.dataset) {
return element.dataset[this.dataNamespace];
} else if (element) {
return element.getAttribute('data-' + this.dataNamespace);
}
return null;
},
/**
* Put the container on the page
*
* @memberOf Barba.Pjax.Dom
* @private
* @param {HTMLElement} element
*/
putContainer: function(element) {
element.style.visibility = 'hidden';
var wrapper = this.getWrapper();
wrapper.appendChild(element);
},
/**
* Get container selector
*
* @memberOf Barba.Pjax.Dom
* @private
* @param {HTMLElement} element
* @return {HTMLElement} element
*/
parseContainer: function(element) {
return element.querySelector('.' + this.containerClass);
}
};
module.exports = Dom;
/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {
var Utils = __webpack_require__(6);
var Pjax = __webpack_require__(11);
/**
* Prefetch
*
* @namespace Barba.Prefetch
* @type {Object}
*/
var Prefetch = {
/**
* Class name used to ignore prefetch on links
*
* @memberOf Barba.Prefetch
* @type {String}
* @default
*/
ignoreClassLink: 'no-barba-prefetch',
/**
* Init the event listener on mouseover and touchstart
* for the prefetch
*
* @memberOf Barba.Prefetch
*/
init: function() {
if (!window.history.pushState) {
return false;
}
document.body.addEventListener('mouseover', this.onLinkEnter.bind(this));
document.body.addEventListener('touchstart', this.onLinkEnter.bind(this));
},
/**
* Callback for the mousehover/touchstart
*
* @memberOf Barba.Prefetch
* @private
* @param {Object} evt
*/
onLinkEnter: function(evt) {
var el = evt.target;
while (el && !Pjax.getHref(el)) {
el = el.parentNode;
}
if (!el || el.classList.contains(this.ignoreClassLink)) {
return;
}
var url = Pjax.getHref(el);
//Check if the link is elegible for Pjax
if (Pjax.preventCheck(evt, el) && !Pjax.Cache.get(url)) {
var xhr = Utils.xhr(url);
Pjax.Cache.set(url, xhr);
}
}
};
module.exports = Prefetch;
/***/ })
/******/ ])
});
;
//# sourceMappingURL=barba.js.map