UNPKG

@hickory/browser

Version:

Hickory's browser history

142 lines (137 loc) 5.21 kB
'use strict'; 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;