12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085 |
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
- (factory((global.History = {})));
- }(this, (function (exports) { 'use strict';
- 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 isAbsolute(pathname) {
- return pathname.charAt(0) === '/';
- }
- // About 1.5x faster than the two-arg version of Array#splice()
- function spliceOne(list, index) {
- for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) {
- list[i] = list[k];
- }
- list.pop();
- }
- // This implementation is based heavily on node's url.parse
- function resolvePathname(to, from) {
- if (from === undefined) from = '';
- var toParts = (to && to.split('/')) || [];
- var fromParts = (from && from.split('/')) || [];
- var isToAbs = to && isAbsolute(to);
- var isFromAbs = from && isAbsolute(from);
- var mustEndAbs = isToAbs || isFromAbs;
- if (to && isAbsolute(to)) {
- // to is absolute
- fromParts = toParts;
- } else if (toParts.length) {
- // to is relative, drop the filename
- fromParts.pop();
- fromParts = fromParts.concat(toParts);
- }
- if (!fromParts.length) return '/';
- var hasTrailingSlash;
- if (fromParts.length) {
- var last = fromParts[fromParts.length - 1];
- hasTrailingSlash = last === '.' || last === '..' || last === '';
- } else {
- hasTrailingSlash = false;
- }
- var up = 0;
- for (var i = fromParts.length; i >= 0; i--) {
- var part = fromParts[i];
- if (part === '.') {
- spliceOne(fromParts, i);
- } else if (part === '..') {
- spliceOne(fromParts, i);
- up++;
- } else if (up) {
- spliceOne(fromParts, i);
- up--;
- }
- }
- if (!mustEndAbs) for (; up--; up) fromParts.unshift('..');
- if (
- mustEndAbs &&
- fromParts[0] !== '' &&
- (!fromParts[0] || !isAbsolute(fromParts[0]))
- )
- fromParts.unshift('');
- var result = fromParts.join('/');
- if (hasTrailingSlash && result.substr(-1) !== '/') result += '/';
- return result;
- }
- function valueOf(obj) {
- return obj.valueOf ? obj.valueOf() : Object.prototype.valueOf.call(obj);
- }
- function valueEqual(a, b) {
- // Test for strict equality first.
- if (a === b) return true;
- // Otherwise, if either of them == null they are not equal.
- if (a == null || b == null) return false;
- if (Array.isArray(a)) {
- return (
- Array.isArray(b) &&
- a.length === b.length &&
- a.every(function(item, index) {
- return valueEqual(item, b[index]);
- })
- );
- }
- if (typeof a === 'object' || typeof b === 'object') {
- var aValue = valueOf(a);
- var bValue = valueOf(b);
- if (aValue !== a || bValue !== b) return valueEqual(aValue, bValue);
- return Object.keys(Object.assign({}, a, b)).every(function(key) {
- return valueEqual(a[key], b[key]);
- });
- }
- return false;
- }
- 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 warning(condition, message) {
- {
- if (condition) {
- return;
- }
- var text = "Warning: " + message;
- if (typeof console !== 'undefined') {
- console.warn(text);
- }
- try {
- throw Error(text);
- } catch (x) {}
- }
- }
- 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 prefix = 'Invariant failed';
- function invariant(condition, message) {
- if (condition) {
- return;
- }
- {
- throw new Error(prefix + ": " + (message || ''));
- }
- }
- 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;
- Object.defineProperty(exports, '__esModule', { value: true });
- })));
|