123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', { value: true });
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
- var resolvePathname = _interopDefault(require('resolve-pathname'));
- var valueEqual = _interopDefault(require('value-equal'));
- var warning = _interopDefault(require('tiny-warning'));
- var invariant = _interopDefault(require('tiny-invariant'));
- function _extends() {
- _extends = Object.assign || function (target) {
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i];
- for (var key in source) {
- if (Object.prototype.hasOwnProperty.call(source, key)) {
- target[key] = source[key];
- }
- }
- }
- return target;
- };
- return _extends.apply(this, arguments);
- }
- function addLeadingSlash(path) {
- return path.charAt(0) === '/' ? path : '/' + path;
- }
- function stripLeadingSlash(path) {
- return path.charAt(0) === '/' ? path.substr(1) : path;
- }
- function hasBasename(path, prefix) {
- return path.toLowerCase().indexOf(prefix.toLowerCase()) === 0 && '/?#'.indexOf(path.charAt(prefix.length)) !== -1;
- }
- function stripBasename(path, prefix) {
- return hasBasename(path, prefix) ? path.substr(prefix.length) : path;
- }
- function stripTrailingSlash(path) {
- return path.charAt(path.length - 1) === '/' ? path.slice(0, -1) : path;
- }
- function parsePath(path) {
- var pathname = path || '/';
- var search = '';
- var hash = '';
- var hashIndex = pathname.indexOf('#');
- if (hashIndex !== -1) {
- hash = pathname.substr(hashIndex);
- pathname = pathname.substr(0, hashIndex);
- }
- var searchIndex = pathname.indexOf('?');
- if (searchIndex !== -1) {
- search = pathname.substr(searchIndex);
- pathname = pathname.substr(0, searchIndex);
- }
- return {
- pathname: pathname,
- search: search === '?' ? '' : search,
- hash: hash === '#' ? '' : hash
- };
- }
- function createPath(location) {
- var pathname = location.pathname,
- search = location.search,
- hash = location.hash;
- var path = pathname || '/';
- if (search && search !== '?') path += search.charAt(0) === '?' ? search : "?" + search;
- if (hash && hash !== '#') path += hash.charAt(0) === '#' ? hash : "#" + hash;
- return path;
- }
- function createLocation(path, state, key, currentLocation) {
- var location;
- if (typeof path === 'string') {
- // Two-arg form: push(path, state)
- location = parsePath(path);
- location.state = state;
- } else {
- // One-arg form: push(location)
- location = _extends({}, path);
- if (location.pathname === undefined) location.pathname = '';
- if (location.search) {
- if (location.search.charAt(0) !== '?') location.search = '?' + location.search;
- } else {
- location.search = '';
- }
- if (location.hash) {
- if (location.hash.charAt(0) !== '#') location.hash = '#' + location.hash;
- } else {
- location.hash = '';
- }
- if (state !== undefined && location.state === undefined) location.state = state;
- }
- try {
- location.pathname = decodeURI(location.pathname);
- } catch (e) {
- if (e instanceof URIError) {
- throw new URIError('Pathname "' + location.pathname + '" could not be decoded. ' + 'This is likely caused by an invalid percent-encoding.');
- } else {
- throw e;
- }
- }
- if (key) location.key = key;
- if (currentLocation) {
- // Resolve incomplete/relative pathname relative to current location.
- if (!location.pathname) {
- location.pathname = currentLocation.pathname;
- } else if (location.pathname.charAt(0) !== '/') {
- location.pathname = resolvePathname(location.pathname, currentLocation.pathname);
- }
- } else {
- // When there is no prior location and pathname is empty, set it to /
- if (!location.pathname) {
- location.pathname = '/';
- }
- }
- return location;
- }
- function locationsAreEqual(a, b) {
- return a.pathname === b.pathname && a.search === b.search && a.hash === b.hash && a.key === b.key && valueEqual(a.state, b.state);
- }
- function createTransitionManager() {
- var prompt = null;
- function setPrompt(nextPrompt) {
- warning(prompt == null, 'A history supports only one prompt at a time');
- prompt = nextPrompt;
- return function () {
- if (prompt === nextPrompt) prompt = null;
- };
- }
- function confirmTransitionTo(location, action, getUserConfirmation, callback) {
- // TODO: If another transition starts while we're still confirming
- // the previous one, we may end up in a weird state. Figure out the
- // best way to handle this.
- if (prompt != null) {
- var result = typeof prompt === 'function' ? prompt(location, action) : prompt;
- if (typeof result === 'string') {
- if (typeof getUserConfirmation === 'function') {
- getUserConfirmation(result, callback);
- } else {
- warning(false, 'A history needs a getUserConfirmation function in order to use a prompt message');
- callback(true);
- }
- } else {
- // Return false from a transition hook to cancel the transition.
- callback(result !== false);
- }
- } else {
- callback(true);
- }
- }
- var listeners = [];
- function appendListener(fn) {
- var isActive = true;
- function listener() {
- if (isActive) fn.apply(void 0, arguments);
- }
- listeners.push(listener);
- return function () {
- isActive = false;
- listeners = listeners.filter(function (item) {
- return item !== listener;
- });
- };
- }
- function notifyListeners() {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- listeners.forEach(function (listener) {
- return listener.apply(void 0, args);
- });
- }
- return {
- setPrompt: setPrompt,
- confirmTransitionTo: confirmTransitionTo,
- appendListener: appendListener,
- notifyListeners: notifyListeners
- };
- }
- var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
- function getConfirmation(message, callback) {
- callback(window.confirm(message)); // eslint-disable-line no-alert
- }
- /**
- * Returns true if the HTML5 history API is supported. Taken from Modernizr.
- *
- * https://github.com/Modernizr/Modernizr/blob/master/LICENSE
- * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js
- * changed to avoid false negatives for Windows Phones: https://github.com/reactjs/react-router/issues/586
- */
- function supportsHistory() {
- var ua = window.navigator.userAgent;
- if ((ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) && ua.indexOf('Mobile Safari') !== -1 && ua.indexOf('Chrome') === -1 && ua.indexOf('Windows Phone') === -1) return false;
- return window.history && 'pushState' in window.history;
- }
- /**
- * Returns true if browser fires popstate on hash change.
- * IE10 and IE11 do not.
- */
- function supportsPopStateOnHashChange() {
- return window.navigator.userAgent.indexOf('Trident') === -1;
- }
- /**
- * Returns false if using go(n) with hash history causes a full page reload.
- */
- function supportsGoWithoutReloadUsingHash() {
- return window.navigator.userAgent.indexOf('Firefox') === -1;
- }
- /**
- * Returns true if a given popstate event is an extraneous WebKit event.
- * Accounts for the fact that Chrome on iOS fires real popstate events
- * containing undefined state when pressing the back button.
- */
- function isExtraneousPopstateEvent(event) {
- return event.state === undefined && navigator.userAgent.indexOf('CriOS') === -1;
- }
- var PopStateEvent = 'popstate';
- var HashChangeEvent = 'hashchange';
- function getHistoryState() {
- try {
- return window.history.state || {};
- } catch (e) {
- // IE 11 sometimes throws when accessing window.history.state
- // See https://github.com/ReactTraining/history/pull/289
- return {};
- }
- }
- /**
- * Creates a history object that uses the HTML5 history API including
- * pushState, replaceState, and the popstate event.
- */
- function createBrowserHistory(props) {
- if (props === void 0) {
- props = {};
- }
- !canUseDOM ? invariant(false, 'Browser history needs a DOM') : void 0;
- var globalHistory = window.history;
- var canUseHistory = supportsHistory();
- var needsHashChangeListener = !supportsPopStateOnHashChange();
- var _props = props,
- _props$forceRefresh = _props.forceRefresh,
- forceRefresh = _props$forceRefresh === void 0 ? false : _props$forceRefresh,
- _props$getUserConfirm = _props.getUserConfirmation,
- getUserConfirmation = _props$getUserConfirm === void 0 ? getConfirmation : _props$getUserConfirm,
- _props$keyLength = _props.keyLength,
- keyLength = _props$keyLength === void 0 ? 6 : _props$keyLength;
- var basename = props.basename ? stripTrailingSlash(addLeadingSlash(props.basename)) : '';
- function getDOMLocation(historyState) {
- var _ref = historyState || {},
- key = _ref.key,
- state = _ref.state;
- var _window$location = window.location,
- pathname = _window$location.pathname,
- search = _window$location.search,
- hash = _window$location.hash;
- var path = pathname + search + hash;
- warning(!basename || hasBasename(path, basename), 'You are attempting to use a basename on a page whose URL path does not begin ' + 'with the basename. Expected path "' + path + '" to begin with "' + basename + '".');
- if (basename) path = stripBasename(path, basename);
- return createLocation(path, state, key);
- }
- function createKey() {
- return Math.random().toString(36).substr(2, keyLength);
- }
- var transitionManager = createTransitionManager();
- function setState(nextState) {
- _extends(history, nextState);
- history.length = globalHistory.length;
- transitionManager.notifyListeners(history.location, history.action);
- }
- function handlePopState(event) {
- // Ignore extraneous popstate events in WebKit.
- if (isExtraneousPopstateEvent(event)) return;
- handlePop(getDOMLocation(event.state));
- }
- function handleHashChange() {
- handlePop(getDOMLocation(getHistoryState()));
- }
- var forceNextPop = false;
- function handlePop(location) {
- if (forceNextPop) {
- forceNextPop = false;
- setState();
- } else {
- var action = 'POP';
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (ok) {
- setState({
- action: action,
- location: location
- });
- } else {
- revertPop(location);
- }
- });
- }
- }
- function revertPop(fromLocation) {
- var toLocation = history.location; // TODO: We could probably make this more reliable by
- // keeping a list of keys we've seen in sessionStorage.
- // Instead, we just default to 0 for keys we don't know.
- var toIndex = allKeys.indexOf(toLocation.key);
- if (toIndex === -1) toIndex = 0;
- var fromIndex = allKeys.indexOf(fromLocation.key);
- if (fromIndex === -1) fromIndex = 0;
- var delta = toIndex - fromIndex;
- if (delta) {
- forceNextPop = true;
- go(delta);
- }
- }
- var initialLocation = getDOMLocation(getHistoryState());
- var allKeys = [initialLocation.key]; // Public interface
- function createHref(location) {
- return basename + createPath(location);
- }
- function push(path, state) {
- warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to push when the 1st ' + 'argument is a location-like object that already has state; it is ignored');
- var action = 'PUSH';
- var location = createLocation(path, state, createKey(), history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- var href = createHref(location);
- var key = location.key,
- state = location.state;
- if (canUseHistory) {
- globalHistory.pushState({
- key: key,
- state: state
- }, null, href);
- if (forceRefresh) {
- window.location.href = href;
- } else {
- var prevIndex = allKeys.indexOf(history.location.key);
- var nextKeys = allKeys.slice(0, prevIndex + 1);
- nextKeys.push(location.key);
- allKeys = nextKeys;
- setState({
- action: action,
- location: location
- });
- }
- } else {
- warning(state === undefined, 'Browser history cannot push state in browsers that do not support HTML5 history');
- window.location.href = href;
- }
- });
- }
- function replace(path, state) {
- warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to replace when the 1st ' + 'argument is a location-like object that already has state; it is ignored');
- var action = 'REPLACE';
- var location = createLocation(path, state, createKey(), history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- var href = createHref(location);
- var key = location.key,
- state = location.state;
- if (canUseHistory) {
- globalHistory.replaceState({
- key: key,
- state: state
- }, null, href);
- if (forceRefresh) {
- window.location.replace(href);
- } else {
- var prevIndex = allKeys.indexOf(history.location.key);
- if (prevIndex !== -1) allKeys[prevIndex] = location.key;
- setState({
- action: action,
- location: location
- });
- }
- } else {
- warning(state === undefined, 'Browser history cannot replace state in browsers that do not support HTML5 history');
- window.location.replace(href);
- }
- });
- }
- function go(n) {
- globalHistory.go(n);
- }
- function goBack() {
- go(-1);
- }
- function goForward() {
- go(1);
- }
- var listenerCount = 0;
- function checkDOMListeners(delta) {
- listenerCount += delta;
- if (listenerCount === 1 && delta === 1) {
- window.addEventListener(PopStateEvent, handlePopState);
- if (needsHashChangeListener) window.addEventListener(HashChangeEvent, handleHashChange);
- } else if (listenerCount === 0) {
- window.removeEventListener(PopStateEvent, handlePopState);
- if (needsHashChangeListener) window.removeEventListener(HashChangeEvent, handleHashChange);
- }
- }
- var isBlocked = false;
- function block(prompt) {
- if (prompt === void 0) {
- prompt = false;
- }
- var unblock = transitionManager.setPrompt(prompt);
- if (!isBlocked) {
- checkDOMListeners(1);
- isBlocked = true;
- }
- return function () {
- if (isBlocked) {
- isBlocked = false;
- checkDOMListeners(-1);
- }
- return unblock();
- };
- }
- function listen(listener) {
- var unlisten = transitionManager.appendListener(listener);
- checkDOMListeners(1);
- return function () {
- checkDOMListeners(-1);
- unlisten();
- };
- }
- var history = {
- length: globalHistory.length,
- action: 'POP',
- location: initialLocation,
- createHref: createHref,
- push: push,
- replace: replace,
- go: go,
- goBack: goBack,
- goForward: goForward,
- block: block,
- listen: listen
- };
- return history;
- }
- var HashChangeEvent$1 = 'hashchange';
- var HashPathCoders = {
- hashbang: {
- encodePath: function encodePath(path) {
- return path.charAt(0) === '!' ? path : '!/' + stripLeadingSlash(path);
- },
- decodePath: function decodePath(path) {
- return path.charAt(0) === '!' ? path.substr(1) : path;
- }
- },
- noslash: {
- encodePath: stripLeadingSlash,
- decodePath: addLeadingSlash
- },
- slash: {
- encodePath: addLeadingSlash,
- decodePath: addLeadingSlash
- }
- };
- function stripHash(url) {
- var hashIndex = url.indexOf('#');
- return hashIndex === -1 ? url : url.slice(0, hashIndex);
- }
- function getHashPath() {
- // We can't use window.location.hash here because it's not
- // consistent across browsers - Firefox will pre-decode it!
- var href = window.location.href;
- var hashIndex = href.indexOf('#');
- return hashIndex === -1 ? '' : href.substring(hashIndex + 1);
- }
- function pushHashPath(path) {
- window.location.hash = path;
- }
- function replaceHashPath(path) {
- window.location.replace(stripHash(window.location.href) + '#' + path);
- }
- function createHashHistory(props) {
- if (props === void 0) {
- props = {};
- }
- !canUseDOM ? invariant(false, 'Hash history needs a DOM') : void 0;
- var globalHistory = window.history;
- var canGoWithoutReload = supportsGoWithoutReloadUsingHash();
- var _props = props,
- _props$getUserConfirm = _props.getUserConfirmation,
- getUserConfirmation = _props$getUserConfirm === void 0 ? getConfirmation : _props$getUserConfirm,
- _props$hashType = _props.hashType,
- hashType = _props$hashType === void 0 ? 'slash' : _props$hashType;
- var basename = props.basename ? stripTrailingSlash(addLeadingSlash(props.basename)) : '';
- var _HashPathCoders$hashT = HashPathCoders[hashType],
- encodePath = _HashPathCoders$hashT.encodePath,
- decodePath = _HashPathCoders$hashT.decodePath;
- function getDOMLocation() {
- var path = decodePath(getHashPath());
- warning(!basename || hasBasename(path, basename), 'You are attempting to use a basename on a page whose URL path does not begin ' + 'with the basename. Expected path "' + path + '" to begin with "' + basename + '".');
- if (basename) path = stripBasename(path, basename);
- return createLocation(path);
- }
- var transitionManager = createTransitionManager();
- function setState(nextState) {
- _extends(history, nextState);
- history.length = globalHistory.length;
- transitionManager.notifyListeners(history.location, history.action);
- }
- var forceNextPop = false;
- var ignorePath = null;
- function locationsAreEqual$$1(a, b) {
- return a.pathname === b.pathname && a.search === b.search && a.hash === b.hash;
- }
- function handleHashChange() {
- var path = getHashPath();
- var encodedPath = encodePath(path);
- if (path !== encodedPath) {
- // Ensure we always have a properly-encoded hash.
- replaceHashPath(encodedPath);
- } else {
- var location = getDOMLocation();
- var prevLocation = history.location;
- if (!forceNextPop && locationsAreEqual$$1(prevLocation, location)) return; // A hashchange doesn't always == location change.
- if (ignorePath === createPath(location)) return; // Ignore this change; we already setState in push/replace.
- ignorePath = null;
- handlePop(location);
- }
- }
- function handlePop(location) {
- if (forceNextPop) {
- forceNextPop = false;
- setState();
- } else {
- var action = 'POP';
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (ok) {
- setState({
- action: action,
- location: location
- });
- } else {
- revertPop(location);
- }
- });
- }
- }
- function revertPop(fromLocation) {
- var toLocation = history.location; // TODO: We could probably make this more reliable by
- // keeping a list of paths we've seen in sessionStorage.
- // Instead, we just default to 0 for paths we don't know.
- var toIndex = allPaths.lastIndexOf(createPath(toLocation));
- if (toIndex === -1) toIndex = 0;
- var fromIndex = allPaths.lastIndexOf(createPath(fromLocation));
- if (fromIndex === -1) fromIndex = 0;
- var delta = toIndex - fromIndex;
- if (delta) {
- forceNextPop = true;
- go(delta);
- }
- } // Ensure the hash is encoded properly before doing anything else.
- var path = getHashPath();
- var encodedPath = encodePath(path);
- if (path !== encodedPath) replaceHashPath(encodedPath);
- var initialLocation = getDOMLocation();
- var allPaths = [createPath(initialLocation)]; // Public interface
- function createHref(location) {
- var baseTag = document.querySelector('base');
- var href = '';
- if (baseTag && baseTag.getAttribute('href')) {
- href = stripHash(window.location.href);
- }
- return href + '#' + encodePath(basename + createPath(location));
- }
- function push(path, state) {
- warning(state === undefined, 'Hash history cannot push state; it is ignored');
- var action = 'PUSH';
- var location = createLocation(path, undefined, undefined, history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- var path = createPath(location);
- var encodedPath = encodePath(basename + path);
- var hashChanged = getHashPath() !== encodedPath;
- if (hashChanged) {
- // We cannot tell if a hashchange was caused by a PUSH, so we'd
- // rather setState here and ignore the hashchange. The caveat here
- // is that other hash histories in the page will consider it a POP.
- ignorePath = path;
- pushHashPath(encodedPath);
- var prevIndex = allPaths.lastIndexOf(createPath(history.location));
- var nextPaths = allPaths.slice(0, prevIndex + 1);
- nextPaths.push(path);
- allPaths = nextPaths;
- setState({
- action: action,
- location: location
- });
- } else {
- warning(false, 'Hash history cannot PUSH the same path; a new entry will not be added to the history stack');
- setState();
- }
- });
- }
- function replace(path, state) {
- warning(state === undefined, 'Hash history cannot replace state; it is ignored');
- var action = 'REPLACE';
- var location = createLocation(path, undefined, undefined, history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- var path = createPath(location);
- var encodedPath = encodePath(basename + path);
- var hashChanged = getHashPath() !== encodedPath;
- if (hashChanged) {
- // We cannot tell if a hashchange was caused by a REPLACE, so we'd
- // rather setState here and ignore the hashchange. The caveat here
- // is that other hash histories in the page will consider it a POP.
- ignorePath = path;
- replaceHashPath(encodedPath);
- }
- var prevIndex = allPaths.indexOf(createPath(history.location));
- if (prevIndex !== -1) allPaths[prevIndex] = path;
- setState({
- action: action,
- location: location
- });
- });
- }
- function go(n) {
- warning(canGoWithoutReload, 'Hash history go(n) causes a full page reload in this browser');
- globalHistory.go(n);
- }
- function goBack() {
- go(-1);
- }
- function goForward() {
- go(1);
- }
- var listenerCount = 0;
- function checkDOMListeners(delta) {
- listenerCount += delta;
- if (listenerCount === 1 && delta === 1) {
- window.addEventListener(HashChangeEvent$1, handleHashChange);
- } else if (listenerCount === 0) {
- window.removeEventListener(HashChangeEvent$1, handleHashChange);
- }
- }
- var isBlocked = false;
- function block(prompt) {
- if (prompt === void 0) {
- prompt = false;
- }
- var unblock = transitionManager.setPrompt(prompt);
- if (!isBlocked) {
- checkDOMListeners(1);
- isBlocked = true;
- }
- return function () {
- if (isBlocked) {
- isBlocked = false;
- checkDOMListeners(-1);
- }
- return unblock();
- };
- }
- function listen(listener) {
- var unlisten = transitionManager.appendListener(listener);
- checkDOMListeners(1);
- return function () {
- checkDOMListeners(-1);
- unlisten();
- };
- }
- var history = {
- length: globalHistory.length,
- action: 'POP',
- location: initialLocation,
- createHref: createHref,
- push: push,
- replace: replace,
- go: go,
- goBack: goBack,
- goForward: goForward,
- block: block,
- listen: listen
- };
- return history;
- }
- function clamp(n, lowerBound, upperBound) {
- return Math.min(Math.max(n, lowerBound), upperBound);
- }
- /**
- * Creates a history object that stores locations in memory.
- */
- function createMemoryHistory(props) {
- if (props === void 0) {
- props = {};
- }
- var _props = props,
- getUserConfirmation = _props.getUserConfirmation,
- _props$initialEntries = _props.initialEntries,
- initialEntries = _props$initialEntries === void 0 ? ['/'] : _props$initialEntries,
- _props$initialIndex = _props.initialIndex,
- initialIndex = _props$initialIndex === void 0 ? 0 : _props$initialIndex,
- _props$keyLength = _props.keyLength,
- keyLength = _props$keyLength === void 0 ? 6 : _props$keyLength;
- var transitionManager = createTransitionManager();
- function setState(nextState) {
- _extends(history, nextState);
- history.length = history.entries.length;
- transitionManager.notifyListeners(history.location, history.action);
- }
- function createKey() {
- return Math.random().toString(36).substr(2, keyLength);
- }
- var index = clamp(initialIndex, 0, initialEntries.length - 1);
- var entries = initialEntries.map(function (entry) {
- return typeof entry === 'string' ? createLocation(entry, undefined, createKey()) : createLocation(entry, undefined, entry.key || createKey());
- }); // Public interface
- var createHref = createPath;
- function push(path, state) {
- warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to push when the 1st ' + 'argument is a location-like object that already has state; it is ignored');
- var action = 'PUSH';
- var location = createLocation(path, state, createKey(), history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- var prevIndex = history.index;
- var nextIndex = prevIndex + 1;
- var nextEntries = history.entries.slice(0);
- if (nextEntries.length > nextIndex) {
- nextEntries.splice(nextIndex, nextEntries.length - nextIndex, location);
- } else {
- nextEntries.push(location);
- }
- setState({
- action: action,
- location: location,
- index: nextIndex,
- entries: nextEntries
- });
- });
- }
- function replace(path, state) {
- warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to replace when the 1st ' + 'argument is a location-like object that already has state; it is ignored');
- var action = 'REPLACE';
- var location = createLocation(path, state, createKey(), history.location);
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (!ok) return;
- history.entries[history.index] = location;
- setState({
- action: action,
- location: location
- });
- });
- }
- function go(n) {
- var nextIndex = clamp(history.index + n, 0, history.entries.length - 1);
- var action = 'POP';
- var location = history.entries[nextIndex];
- transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {
- if (ok) {
- setState({
- action: action,
- location: location,
- index: nextIndex
- });
- } else {
- // Mimic the behavior of DOM histories by
- // causing a render after a cancelled POP.
- setState();
- }
- });
- }
- function goBack() {
- go(-1);
- }
- function goForward() {
- go(1);
- }
- function canGo(n) {
- var nextIndex = history.index + n;
- return nextIndex >= 0 && nextIndex < history.entries.length;
- }
- function block(prompt) {
- if (prompt === void 0) {
- prompt = false;
- }
- return transitionManager.setPrompt(prompt);
- }
- function listen(listener) {
- return transitionManager.appendListener(listener);
- }
- var history = {
- length: entries.length,
- action: 'POP',
- location: entries[index],
- index: index,
- entries: entries,
- createHref: createHref,
- push: push,
- replace: replace,
- go: go,
- goBack: goBack,
- goForward: goForward,
- canGo: canGo,
- block: block,
- listen: listen
- };
- return history;
- }
- exports.createBrowserHistory = createBrowserHistory;
- exports.createHashHistory = createHashHistory;
- exports.createMemoryHistory = createMemoryHistory;
- exports.createLocation = createLocation;
- exports.locationsAreEqual = locationsAreEqual;
- exports.parsePath = parsePath;
- exports.createPath = createPath;
|