@hickory/browser
Version:
Hickory's browser history
142 lines (137 loc) • 5.21 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var root = require('@hickory/root');
var domUtils = require('@hickory/dom-utils');
function noop() { }
function browser(fn, options) {
if (options === void 0) { options = {}; }
if (!domUtils.domExists()) {
throw new Error("Cannot use @hickory/browser without a DOM");
}
var utils = root.locationUtils(options);
var keygen = root.keyGenerator();
var _a = root.confirmation(), confirm = _a.confirm, confirmNavigation = _a.confirmNavigation;
function fromBrowser(providedState) {
var _a = window.location, pathname = _a.pathname, search = _a.search, hash = _a.hash;
var url = pathname + search + hash;
var _b = providedState || domUtils.getStateFromHistory(), key = _b.key, state = _b.state;
if (!key) {
key = keygen.major();
window.history.replaceState({ key: key, state: state }, "", url);
}
var location = utils.location({ url: url, state: state });
return utils.keyed(location, key);
}
function url(location) {
return utils.stringify(location);
}
// set action before location because fromBrowser enforces
// that the location has a key
var lastAction = domUtils.getStateFromHistory().key !== undefined ? "pop" : "push";
var _b = root.navigateWith({
responseHandler: fn,
utils: utils,
keygen: keygen,
current: function () { return browserHistory.location; },
push: {
finish: function (location) {
return function () {
var path = url(location);
var key = location.key, state = location.state;
try {
window.history.pushState({ key: key, state: state }, "", path);
}
catch (e) {
window.location.assign(path);
}
browserHistory.location = location;
lastAction = "push";
};
},
cancel: noop
},
replace: {
finish: function (location) {
return function () {
var path = url(location);
var key = location.key, state = location.state;
try {
window.history.replaceState({ key: key, state: state }, "", path);
}
catch (e) {
window.location.replace(path);
}
browserHistory.location = location;
lastAction = "replace";
};
},
cancel: noop
}
}), emitNavigation = _b.emitNavigation, cancelPending = _b.cancelPending, createNavigation = _b.createNavigation, prepare = _b.prepare;
// when true, pop will ignore the navigation
var reverting = false;
function popstate(event) {
if (reverting) {
reverting = false;
return;
}
if (domUtils.ignorablePopstateEvent(event)) {
return;
}
cancelPending("pop");
var location = fromBrowser(event.state);
var diff = browserHistory.location.key[0] - location.key[0];
var revert = function () {
reverting = true;
window.history.go(diff);
};
confirmNavigation({
to: location,
from: browserHistory.location,
action: "pop"
}, function () {
emitNavigation(createNavigation(location, "pop", function () {
browserHistory.location = location;
lastAction = "pop";
}, function (nextAction) {
if (nextAction !== "pop") {
revert();
}
}));
}, revert);
}
window.addEventListener("popstate", popstate, false);
var browserHistory = {
location: fromBrowser(),
current: function () {
emitNavigation(createNavigation(browserHistory.location, lastAction, noop, noop));
},
url: url,
navigate: function (to, navType) {
if (navType === void 0) { navType = "anchor"; }
var navigation = prepare(to, navType);
cancelPending(navigation.action);
confirmNavigation({
to: navigation.location,
from: browserHistory.location,
action: navigation.action
}, function () {
emitNavigation(navigation);
});
},
go: function (num) {
window.history.go(num);
},
confirm: confirm,
cancel: function () {
cancelPending();
},
destroy: function () {
window.removeEventListener("popstate", popstate);
emitNavigation = noop;
}
};
return browserHistory;
}
exports.createBase = root.createBase;
exports.browser = browser;