history
Advanced tools
Comparing version 4.10.1 to 5.0.0-beta.0
1345
cjs/history.js
@@ -5,9 +5,2 @@ 'use strict'; | ||
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() { | ||
@@ -31,263 +24,185 @@ _extends = Object.assign || function (target) { | ||
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('#'); | ||
var PopAction = 'POP'; | ||
var PushAction = 'PUSH'; | ||
var ReplaceAction = 'REPLACE'; | ||
var BeforeUnloadEventType = 'beforeunload'; | ||
var PopStateEventType = 'popstate'; | ||
var HashChangeEventType = 'hashchange'; // There's some duplication in this code, but only one create* method | ||
// should ever be used in a given web page, so it's best for minifying | ||
// to just inline everything. | ||
if (hashIndex !== -1) { | ||
hash = pathname.substr(hashIndex); | ||
pathname = pathname.substr(0, hashIndex); | ||
} | ||
/** | ||
* Memory history stores the current location in memory. It is designed | ||
* for use in stateful non-browser environments like headless tests (in | ||
* node.js) and React Native. | ||
*/ | ||
var searchIndex = pathname.indexOf('?'); | ||
var createMemoryHistory = function createMemoryHistory(_temp) { | ||
var _ref = _temp === void 0 ? {} : _temp, | ||
_ref$initialEntries = _ref.initialEntries, | ||
initialEntries = _ref$initialEntries === void 0 ? ['/'] : _ref$initialEntries, | ||
_ref$initialIndex = _ref.initialIndex, | ||
initialIndex = _ref$initialIndex === void 0 ? 0 : _ref$initialIndex; | ||
if (searchIndex !== -1) { | ||
search = pathname.substr(searchIndex); | ||
pathname = pathname.substr(0, searchIndex); | ||
} | ||
var entries = initialEntries.map(function (entry) { | ||
var location = createReadOnlyObject(_extends({ | ||
pathname: '/', | ||
search: '', | ||
hash: '', | ||
state: null, | ||
key: createKey() | ||
}, typeof entry === 'string' ? parsePath(entry) : entry)); | ||
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; | ||
} | ||
{ | ||
if (location.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(entry); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + arg + ")"); | ||
} | ||
} | ||
function createLocation(path, state, key, currentLocation) { | ||
var location; | ||
return location; | ||
}); | ||
var index = clamp(initialIndex, 0, entries.length - 1); | ||
var action = PopAction; | ||
var location = entries[index]; | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
var createHref = createPath; | ||
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 = ''; | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
if (location.hash) { | ||
if (location.hash.charAt(0) !== '#') location.hash = '#' + location.hash; | ||
} else { | ||
location.hash = ''; | ||
} | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if (state !== undefined && location.state === undefined) location.state = state; | ||
} | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
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; | ||
} | ||
} | ||
var applyTx = function applyTx(nextAction, nextLocation) { | ||
action = nextAction; | ||
location = nextLocation; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
}; | ||
if (key) location.key = key; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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); | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().push(" + arg + ")"); | ||
} | ||
} | ||
} else { | ||
// When there is no prior location and pathname is empty, set it to / | ||
if (!location.pathname) { | ||
location.pathname = '/'; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index += 1; | ||
entries.splice(index, entries.length, nextLocation); | ||
applyTx(nextAction, nextLocation); | ||
} | ||
} | ||
}; | ||
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); | ||
} | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, 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; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
} | ||
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); | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().replace(" + arg + ")"); | ||
} | ||
} else { | ||
callback(true); | ||
} | ||
} | ||
var listeners = []; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
entries[index] = nextLocation; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
function appendListener(fn) { | ||
var isActive = true; | ||
var go = function go(n) { | ||
var nextIndex = clamp(index + n, 0, entries.length - 1); | ||
var nextAction = PopAction; | ||
var nextLocation = entries[nextIndex]; | ||
function listener() { | ||
if (isActive) fn.apply(void 0, arguments); | ||
} | ||
listeners.push(listener); | ||
return function () { | ||
isActive = false; | ||
listeners = listeners.filter(function (item) { | ||
return item !== listener; | ||
}); | ||
var retry = function retry() { | ||
go(n); | ||
}; | ||
} | ||
function notifyListeners() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index = nextIndex; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
listeners.forEach(function (listener) { | ||
return listener.apply(void 0, args); | ||
}); | ||
} | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
return { | ||
setPrompt: setPrompt, | ||
confirmTransitionTo: confirmTransitionTo, | ||
appendListener: appendListener, | ||
notifyListeners: notifyListeners | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
} | ||
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 | ||
*/ | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
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. | ||
*/ | ||
var block = function block(fn) { | ||
return blockers.push(fn); | ||
}; | ||
function supportsPopStateOnHashChange() { | ||
return window.navigator.userAgent.indexOf('Trident') === -1; | ||
} | ||
/** | ||
* Returns false if using go(n) with hash history causes a full page reload. | ||
*/ | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
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. | ||
*/ | ||
get location() { | ||
return location; | ||
}, | ||
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 {}; | ||
} | ||
} | ||
createHref: createHref, | ||
push: push, | ||
replace: replace, | ||
go: go, | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
}; | ||
/** | ||
* Creates a history object that uses the HTML5 history API including | ||
* pushState, replaceState, and the popstate event. | ||
* Browser history stores the location in regular URLs. This is the | ||
* standard for most web apps, but it requires some configuration on | ||
* the server to ensure you serve the same app at multiple URLs. | ||
*/ | ||
var createBrowserHistory = function createBrowserHistory(_temp2) { | ||
var _ref2 = _temp2 === void 0 ? {} : _temp2, | ||
_ref2$window = _ref2.window, | ||
window = _ref2$window === void 0 ? document.defaultView : _ref2$window; | ||
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 getIndexAndLocation = function getIndexAndLocation() { | ||
var _window$location = window.location, | ||
@@ -297,207 +212,204 @@ pathname = _window$location.pathname, | ||
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); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var blockedPopTx = null; | ||
var transitionManager = createTransitionManager(); | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
var _getIndexAndLocation = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation[0], | ||
nextLocation = _getIndexAndLocation[1]; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
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 | ||
}); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
revertPop(location); | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
{ | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
}); | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
} | ||
}; | ||
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. | ||
window.addEventListener(PopStateEventType, handlePop); | ||
var action = PopAction; | ||
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; | ||
var _getIndexAndLocation2 = getIndexAndLocation(), | ||
index = _getIndexAndLocation2[0], | ||
location = _getIndexAndLocation2[1]; | ||
if (delta) { | ||
forceNextPop = true; | ||
go(delta); | ||
} | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
var initialLocation = getDOMLocation(getHistoryState()); | ||
var allKeys = [initialLocation.key]; // Public interface | ||
var createHref = createPath; | ||
function createHref(location) { | ||
return basename + createPath(location); | ||
} | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
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; | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if (canUseHistory) { | ||
globalHistory.pushState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
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; | ||
} | ||
}); | ||
} | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
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; | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
if (canUseHistory) { | ||
globalHistory.replaceState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var _getIndexAndLocation3 = getIndexAndLocation(); | ||
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); | ||
} | ||
index = _getIndexAndLocation3[0]; | ||
location = _getIndexAndLocation3[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
function go(n) { | ||
globalHistory.go(n); | ||
} | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function goBack() { | ||
go(-1); | ||
} | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
function goForward() { | ||
go(1); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr[0], | ||
url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
var listenerCount = 0; | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
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); | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
var isBlocked = false; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr2[0], | ||
url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -507,285 +419,270 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
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 | ||
} | ||
}; | ||
/** | ||
* Hash history stores the location in window.location.hash. This makes | ||
* it ideal for situations where you don't want to send the location to | ||
* the server for some reason, either because you do cannot configure it | ||
* or the URL space is reserved for something else. | ||
*/ | ||
function stripHash(url) { | ||
var hashIndex = url.indexOf('#'); | ||
return hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
var createHashHistory = function createHashHistory(_temp3) { | ||
var _ref3 = _temp3 === void 0 ? {} : _temp3, | ||
_ref3$window = _ref3.window, | ||
window = _ref3$window === void 0 ? document.defaultView : _ref3$window; | ||
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); | ||
} | ||
var globalHistory = window.history; | ||
function pushHashPath(path) { | ||
window.location.hash = path; | ||
} | ||
var getIndexAndLocation = function getIndexAndLocation() { | ||
var _parsePath = parsePath(window.location.hash.substr(1)), | ||
_parsePath$pathname = _parsePath.pathname, | ||
pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname, | ||
_parsePath$search = _parsePath.search, | ||
search = _parsePath$search === void 0 ? '' : _parsePath$search, | ||
_parsePath$hash = _parsePath.hash, | ||
hash = _parsePath$hash === void 0 ? '' : _parsePath$hash; | ||
function replaceHashPath(path) { | ||
window.location.replace(stripHash(window.location.href) + '#' + path); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createHashHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var blockedPopTx = null; | ||
!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; | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
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 _getIndexAndLocation4 = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation4[0], | ||
nextLocation = _getIndexAndLocation4[1]; | ||
var transitionManager = createTransitionManager(); | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
{ | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
window.addEventListener(PopStateEventType, handlePop); // TODO: Is this still necessary? Which browsers do | ||
// not trigger popstate when the hash changes? | ||
var forceNextPop = false; | ||
var ignorePath = null; | ||
window.addEventListener(HashChangeEventType, function (event) { | ||
var _getIndexAndLocation5 = getIndexAndLocation(), | ||
nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events. | ||
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 (createPath(nextLocation) !== createPath(location)) { | ||
handlePop(); | ||
} | ||
}); | ||
var action = PopAction; | ||
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. | ||
var _getIndexAndLocation6 = getIndexAndLocation(), | ||
index = _getIndexAndLocation6[0], | ||
location = _getIndexAndLocation6[1]; | ||
if (ignorePath === createPath(location)) return; // Ignore this change; we already setState in push/replace. | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
ignorePath = null; | ||
handlePop(location); | ||
} | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
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); | ||
} | ||
}); | ||
var createHref = function createHref(location) { | ||
var base = document.querySelector('base'); | ||
var href = ''; | ||
if (base && base.getAttribute('href')) { | ||
var url = window.location.href; | ||
var hashIndex = url.indexOf('#'); | ||
href = hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
} | ||
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. | ||
return href + '#' + createPath(location); | ||
}; | ||
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); | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
} // Ensure the hash is encoded properly before doing anything else. | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
var path = getHashPath(); | ||
var encodedPath = encodePath(path); | ||
if (path !== encodedPath) replaceHashPath(encodedPath); | ||
var initialLocation = getDOMLocation(); | ||
var allPaths = [createPath(initialLocation)]; // Public interface | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
function createHref(location) { | ||
var baseTag = document.querySelector('base'); | ||
var href = ''; | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
if (baseTag && baseTag.getAttribute('href')) { | ||
href = stripHash(window.location.href); | ||
} | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
return href + '#' + encodePath(basename + createPath(location)); | ||
} | ||
var _getIndexAndLocation7 = getIndexAndLocation(); | ||
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(); | ||
} | ||
index = _getIndexAndLocation7[0]; | ||
location = _getIndexAndLocation7[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
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; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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 retry = function retry() { | ||
return push(to, state); | ||
}; | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().push(" + arg + ")"); | ||
} | ||
} | ||
var prevIndex = allPaths.indexOf(createPath(history.location)); | ||
if (prevIndex !== -1) allPaths[prevIndex] = path; | ||
setState({ | ||
action: action, | ||
location: location | ||
}); | ||
}); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr3[0], | ||
url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
function go(n) { | ||
warning(canGoWithoutReload, 'Hash history go(n) causes a full page reload in this browser'); | ||
globalHistory.go(n); | ||
} | ||
function goBack() { | ||
go(-1); | ||
} | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
function goForward() { | ||
go(1); | ||
} | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var listenerCount = 0; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (listenerCount === 1 && delta === 1) { | ||
window.addEventListener(HashChangeEvent$1, handleHashChange); | ||
} else if (listenerCount === 0) { | ||
window.removeEventListener(HashChangeEvent$1, handleHashChange); | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().replace(" + arg + ")"); | ||
} | ||
} | ||
} | ||
var isBlocked = false; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr4[0], | ||
url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -795,159 +692,95 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
} | ||
}; // Utils | ||
function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
} | ||
/** | ||
* Creates a history object that stores locations in memory. | ||
*/ | ||
var promptBeforeUnload = function promptBeforeUnload(event) { | ||
// Cancel the event. | ||
event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set. | ||
event.returnValue = ''; | ||
}; | ||
function createMemoryHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var createKey = function createKey() { | ||
return Math.random().toString(36).substr(2, 8); | ||
}; // TODO: Probably only do this in dev? | ||
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); | ||
var createReadOnlyObject = function createReadOnlyObject(props) { | ||
return Object.keys(props).reduce(function (obj, key) { | ||
return Object.defineProperty(obj, key, { | ||
enumerable: true, | ||
value: props[key] | ||
}); | ||
}, Object.create(null)); | ||
}; | ||
history.length = history.entries.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
var createPath = function createPath(_ref4) { | ||
var _ref4$pathname = _ref4.pathname, | ||
pathname = _ref4$pathname === void 0 ? '/' : _ref4$pathname, | ||
_ref4$search = _ref4.search, | ||
search = _ref4$search === void 0 ? '' : _ref4$search, | ||
_ref4$hash = _ref4.hash, | ||
hash = _ref4$hash === void 0 ? '' : _ref4$hash; | ||
return pathname + search + hash; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var parsePath = function parsePath(path) { | ||
var pieces = {}; | ||
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 | ||
if (path) { | ||
var hashIndex = path.indexOf('#'); | ||
var createHref = createPath; | ||
if (hashIndex >= 0) { | ||
pieces.hash = path.substr(hashIndex); | ||
path = path.substr(0, hashIndex); | ||
} | ||
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); | ||
var searchIndex = path.indexOf('?'); | ||
if (nextEntries.length > nextIndex) { | ||
nextEntries.splice(nextIndex, nextEntries.length - nextIndex, location); | ||
} else { | ||
nextEntries.push(location); | ||
} | ||
if (searchIndex >= 0) { | ||
pieces.search = path.substr(searchIndex); | ||
path = path.substr(0, searchIndex); | ||
} | ||
setState({ | ||
action: action, | ||
location: location, | ||
index: nextIndex, | ||
entries: nextEntries | ||
}); | ||
}); | ||
if (path) { | ||
pieces.pathname = path; | ||
} | ||
} | ||
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 | ||
}); | ||
}); | ||
} | ||
return pieces; | ||
}; | ||
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 | ||
var createEvents = function createEvents() { | ||
var handlers = []; | ||
return { | ||
get length() { | ||
return handlers.length; | ||
}, | ||
push: function push(fn) { | ||
return handlers.push(fn) && function () { | ||
handlers = handlers.filter(function (handler) { | ||
return handler !== fn; | ||
}); | ||
} 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; | ||
}; | ||
}, | ||
call: function call(arg) { | ||
handlers.forEach(function (fn) { | ||
return fn && fn(arg); | ||
}); | ||
} | ||
}; | ||
}; | ||
return transitionManager.setPrompt(prompt); | ||
} | ||
var clamp = function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
}; | ||
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.createMemoryHistory = createMemoryHistory; | ||
exports.createBrowserHistory = createBrowserHistory; | ||
exports.createHashHistory = createHashHistory; | ||
exports.createMemoryHistory = createMemoryHistory; | ||
exports.createLocation = createLocation; | ||
exports.locationsAreEqual = locationsAreEqual; | ||
exports.parsePath = parsePath; | ||
exports.createPath = createPath; |
@@ -1,1 +0,1 @@ | ||
"use strict";function _interopDefault(t){return t&&"object"==typeof t&&"default"in t?t.default:t}Object.defineProperty(exports,"__esModule",{value:!0});var resolvePathname=_interopDefault(require("resolve-pathname")),valueEqual=_interopDefault(require("value-equal"));require("tiny-warning");var invariant=_interopDefault(require("tiny-invariant"));function _extends(){return(_extends=Object.assign||function(t){for(var n=1;n<arguments.length;n++){var e=arguments[n];for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&(t[a]=e[a])}return t}).apply(this,arguments)}function addLeadingSlash(t){return"/"===t.charAt(0)?t:"/"+t}function stripLeadingSlash(t){return"/"===t.charAt(0)?t.substr(1):t}function hasBasename(t,n){return 0===t.toLowerCase().indexOf(n.toLowerCase())&&-1!=="/?#".indexOf(t.charAt(n.length))}function stripBasename(t,n){return hasBasename(t,n)?t.substr(n.length):t}function stripTrailingSlash(t){return"/"===t.charAt(t.length-1)?t.slice(0,-1):t}function parsePath(t){var n=t||"/",e="",a="",r=n.indexOf("#");-1!==r&&(a=n.substr(r),n=n.substr(0,r));var o=n.indexOf("?");return-1!==o&&(e=n.substr(o),n=n.substr(0,o)),{pathname:n,search:"?"===e?"":e,hash:"#"===a?"":a}}function createPath(t){var n=t.pathname,e=t.search,a=t.hash,r=n||"/";return e&&"?"!==e&&(r+="?"===e.charAt(0)?e:"?"+e),a&&"#"!==a&&(r+="#"===a.charAt(0)?a:"#"+a),r}function createLocation(t,n,e,a){var r;"string"==typeof t?(r=parsePath(t)).state=n:(void 0===(r=_extends({},t)).pathname&&(r.pathname=""),r.search?"?"!==r.search.charAt(0)&&(r.search="?"+r.search):r.search="",r.hash?"#"!==r.hash.charAt(0)&&(r.hash="#"+r.hash):r.hash="",void 0!==n&&void 0===r.state&&(r.state=n));try{r.pathname=decodeURI(r.pathname)}catch(t){throw t instanceof URIError?new URIError('Pathname "'+r.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):t}return e&&(r.key=e),a?r.pathname?"/"!==r.pathname.charAt(0)&&(r.pathname=resolvePathname(r.pathname,a.pathname)):r.pathname=a.pathname:r.pathname||(r.pathname="/"),r}function locationsAreEqual(t,n){return t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash&&t.key===n.key&&valueEqual(t.state,n.state)}function createTransitionManager(){var o=null;var a=[];return{setPrompt:function(t){return o=t,function(){o===t&&(o=null)}},confirmTransitionTo:function(t,n,e,a){if(null!=o){var r="function"==typeof o?o(t,n):o;"string"==typeof r?"function"==typeof e?e(r,a):a(!0):a(!1!==r)}else a(!0)},appendListener:function(t){var n=!0;function e(){n&&t.apply(void 0,arguments)}return a.push(e),function(){n=!1,a=a.filter(function(t){return t!==e})}},notifyListeners:function(){for(var t=arguments.length,n=new Array(t),e=0;e<t;e++)n[e]=arguments[e];a.forEach(function(t){return t.apply(void 0,n)})}}}var canUseDOM=!("undefined"==typeof window||!window.document||!window.document.createElement);function getConfirmation(t,n){n(window.confirm(t))}function supportsHistory(){var t=window.navigator.userAgent;return(-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&(window.history&&"pushState"in window.history)}function supportsPopStateOnHashChange(){return-1===window.navigator.userAgent.indexOf("Trident")}function supportsGoWithoutReloadUsingHash(){return-1===window.navigator.userAgent.indexOf("Firefox")}function isExtraneousPopstateEvent(t){return void 0===t.state&&-1===navigator.userAgent.indexOf("CriOS")}var PopStateEvent="popstate",HashChangeEvent="hashchange";function getHistoryState(){try{return window.history.state||{}}catch(t){return{}}}function createBrowserHistory(t){void 0===t&&(t={}),canUseDOM||invariant(!1);var s=window.history,c=supportsHistory(),n=!supportsPopStateOnHashChange(),e=t,a=e.forceRefresh,h=void 0!==a&&a,r=e.getUserConfirmation,u=void 0===r?getConfirmation:r,o=e.keyLength,i=void 0===o?6:o,f=t.basename?stripTrailingSlash(addLeadingSlash(t.basename)):"";function l(t){var n=t||{},e=n.key,a=n.state,r=window.location,o=r.pathname+r.search+r.hash;return f&&(o=stripBasename(o,f)),createLocation(o,a,e)}function d(){return Math.random().toString(36).substr(2,i)}var v=createTransitionManager();function p(t){_extends(T,t),T.length=s.length,v.notifyListeners(T.location,T.action)}function g(t){isExtraneousPopstateEvent(t)||w(l(t.state))}function P(){w(l(getHistoryState()))}var m=!1;function w(n){if(m)m=!1,p();else{v.confirmTransitionTo(n,"POP",u,function(t){t?p({action:"POP",location:n}):function(t){var n=T.location,e=H.indexOf(n.key);-1===e&&(e=0);var a=H.indexOf(t.key);-1===a&&(a=0);var r=e-a;r&&(m=!0,L(r))}(n)})}}var y=l(getHistoryState()),H=[y.key];function x(t){return f+createPath(t)}function L(t){s.go(t)}var O=0;function E(t){1===(O+=t)&&1===t?(window.addEventListener(PopStateEvent,g),n&&window.addEventListener(HashChangeEvent,P)):0===O&&(window.removeEventListener(PopStateEvent,g),n&&window.removeEventListener(HashChangeEvent,P))}var S=!1;var T={length:s.length,action:"POP",location:y,createHref:x,push:function(t,n){var i=createLocation(t,n,d(),T.location);v.confirmTransitionTo(i,"PUSH",u,function(t){if(t){var n=x(i),e=i.key,a=i.state;if(c)if(s.pushState({key:e,state:a},null,n),h)window.location.href=n;else{var r=H.indexOf(T.location.key),o=H.slice(0,r+1);o.push(i.key),H=o,p({action:"PUSH",location:i})}else window.location.href=n}})},replace:function(t,n){var o="REPLACE",i=createLocation(t,n,d(),T.location);v.confirmTransitionTo(i,o,u,function(t){if(t){var n=x(i),e=i.key,a=i.state;if(c)if(s.replaceState({key:e,state:a},null,n),h)window.location.replace(n);else{var r=H.indexOf(T.location.key);-1!==r&&(H[r]=i.key),p({action:o,location:i})}else window.location.replace(n)}})},go:L,goBack:function(){L(-1)},goForward:function(){L(1)},block:function(t){void 0===t&&(t=!1);var n=v.setPrompt(t);return S||(E(1),S=!0),function(){return S&&(S=!1,E(-1)),n()}},listen:function(t){var n=v.appendListener(t);return E(1),function(){E(-1),n()}}};return T}var HashChangeEvent$1="hashchange",HashPathCoders={hashbang:{encodePath:function(t){return"!"===t.charAt(0)?t:"!/"+stripLeadingSlash(t)},decodePath:function(t){return"!"===t.charAt(0)?t.substr(1):t}},noslash:{encodePath:stripLeadingSlash,decodePath:addLeadingSlash},slash:{encodePath:addLeadingSlash,decodePath:addLeadingSlash}};function stripHash(t){var n=t.indexOf("#");return-1===n?t:t.slice(0,n)}function getHashPath(){var t=window.location.href,n=t.indexOf("#");return-1===n?"":t.substring(n+1)}function pushHashPath(t){window.location.hash=t}function replaceHashPath(t){window.location.replace(stripHash(window.location.href)+"#"+t)}function createHashHistory(t){void 0===t&&(t={}),canUseDOM||invariant(!1);var n=window.history,e=(supportsGoWithoutReloadUsingHash(),t),a=e.getUserConfirmation,i=void 0===a?getConfirmation:a,r=e.hashType,o=void 0===r?"slash":r,s=t.basename?stripTrailingSlash(addLeadingSlash(t.basename)):"",c=HashPathCoders[o],h=c.encodePath,u=c.decodePath;function f(){var t=u(getHashPath());return s&&(t=stripBasename(t,s)),createLocation(t)}var l=createTransitionManager();function d(t){_extends(E,t),E.length=n.length,l.notifyListeners(E.location,E.action)}var v=!1,p=null;function g(){var t=getHashPath(),n=h(t);if(t!==n)replaceHashPath(n);else{var e=f(),a=E.location;if(!v&&function(t,n){return t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash}(a,e))return;if(p===createPath(e))return;p=null,function(n){if(v)v=!1,d();else{l.confirmTransitionTo(n,"POP",i,function(t){t?d({action:"POP",location:n}):function(t){var n=E.location,e=y.lastIndexOf(createPath(n));-1===e&&(e=0);var a=y.lastIndexOf(createPath(t));-1===a&&(a=0);var r=e-a;r&&(v=!0,H(r))}(n)})}}(e)}}var P=getHashPath(),m=h(P);P!==m&&replaceHashPath(m);var w=f(),y=[createPath(w)];function H(t){n.go(t)}var x=0;function L(t){1===(x+=t)&&1===t?window.addEventListener(HashChangeEvent$1,g):0===x&&window.removeEventListener(HashChangeEvent$1,g)}var O=!1;var E={length:n.length,action:"POP",location:w,createHref:function(t){var n=document.querySelector("base"),e="";return n&&n.getAttribute("href")&&(e=stripHash(window.location.href)),e+"#"+h(s+createPath(t))},push:function(t,n){var o=createLocation(t,void 0,void 0,E.location);l.confirmTransitionTo(o,"PUSH",i,function(t){if(t){var n=createPath(o),e=h(s+n);if(getHashPath()!==e){p=n,pushHashPath(e);var a=y.lastIndexOf(createPath(E.location)),r=y.slice(0,a+1);r.push(n),y=r,d({action:"PUSH",location:o})}else d()}})},replace:function(t,n){var r="REPLACE",o=createLocation(t,void 0,void 0,E.location);l.confirmTransitionTo(o,r,i,function(t){if(t){var n=createPath(o),e=h(s+n);getHashPath()!==e&&(p=n,replaceHashPath(e));var a=y.indexOf(createPath(E.location));-1!==a&&(y[a]=n),d({action:r,location:o})}})},go:H,goBack:function(){H(-1)},goForward:function(){H(1)},block:function(t){void 0===t&&(t=!1);var n=l.setPrompt(t);return O||(L(1),O=!0),function(){return O&&(O=!1,L(-1)),n()}},listen:function(t){var n=l.appendListener(t);return L(1),function(){L(-1),n()}}};return E}function clamp(t,n,e){return Math.min(Math.max(t,n),e)}function createMemoryHistory(t){void 0===t&&(t={});var n=t,r=n.getUserConfirmation,e=n.initialEntries,a=void 0===e?["/"]:e,o=n.initialIndex,i=void 0===o?0:o,s=n.keyLength,c=void 0===s?6:s,h=createTransitionManager();function u(t){_extends(g,t),g.length=g.entries.length,h.notifyListeners(g.location,g.action)}function f(){return Math.random().toString(36).substr(2,c)}var l=clamp(i,0,a.length-1),d=a.map(function(t){return createLocation(t,void 0,"string"==typeof t?f():t.key||f())}),v=createPath;function p(t){var n=clamp(g.index+t,0,g.entries.length-1),e=g.entries[n];h.confirmTransitionTo(e,"POP",r,function(t){t?u({action:"POP",location:e,index:n}):u()})}var g={length:d.length,action:"POP",location:d[l],index:l,entries:d,createHref:v,push:function(t,n){var a=createLocation(t,n,f(),g.location);h.confirmTransitionTo(a,"PUSH",r,function(t){if(t){var n=g.index+1,e=g.entries.slice(0);e.length>n?e.splice(n,e.length-n,a):e.push(a),u({action:"PUSH",location:a,index:n,entries:e})}})},replace:function(t,n){var e="REPLACE",a=createLocation(t,n,f(),g.location);h.confirmTransitionTo(a,e,r,function(t){t&&(g.entries[g.index]=a,u({action:e,location:a}))})},go:p,goBack:function(){p(-1)},goForward:function(){p(1)},canGo:function(t){var n=g.index+t;return 0<=n&&n<g.entries.length},block:function(t){return void 0===t&&(t=!1),h.setPrompt(t)},listen:function(t){return h.appendListener(t)}};return g}exports.createBrowserHistory=createBrowserHistory,exports.createHashHistory=createHashHistory,exports.createMemoryHistory=createMemoryHistory,exports.createLocation=createLocation,exports.locationsAreEqual=locationsAreEqual,exports.parsePath=parsePath,exports.createPath=createPath; | ||
"use strict";function _extends(){return(_extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}Object.defineProperty(exports,"__esModule",{value:!0});var PopAction="POP",PushAction="PUSH",ReplaceAction="REPLACE",BeforeUnloadEventType="beforeunload",PopStateEventType="popstate",HashChangeEventType="hashchange",createMemoryHistory=function(e){function o(e,t){return void 0===t&&(t=null),createReadOnlyObject(_extends({},p,{},"string"==typeof e?parsePath(e):e,{state:t,key:createKey()}))}function c(e,t,n){return!v.length||(v.call({action:e,location:t,retry:n}),!1)}function i(e,t){h=e,p=t,d.call({action:h,location:p})}function a(e){var t=clamp(f+e,0,s.length-1),n=PopAction,r=s[t];c(n,r,function(){a(e)})&&(f=t,i(n,r))}var t=void 0===e?{}:e,n=t.initialEntries,r=void 0===n?["/"]:n,u=t.initialIndex,l=void 0===u?0:u,s=r.map(function(e){return createReadOnlyObject(_extends({pathname:"/",search:"",hash:"",state:null,key:createKey()},"string"==typeof e?parsePath(e):e))}),f=clamp(l,0,s.length-1),h=PopAction,p=s[f],v=createEvents(),d=createEvents();return{get action(){return h},get location(){return p},createHref:createPath,push:function e(t,n){var r=PushAction,a=o(t,n);c(r,a,function(){return e(t,n)})&&(f+=1,s.splice(f,s.length,a),i(r,a))},replace:function e(t,n){var r=ReplaceAction,a=o(t,n);c(r,a,function(){return e(t,n)})&&(s[f]=a,i(r,a))},go:a,back:function(){a(-1)},forward:function(){a(1)},listen:function(e){return d.push(e)},block:function(e){return v.push(e)}}},createBrowserHistory=function(e){function o(){var e=u.location,t=e.pathname,n=e.search,r=e.hash,a=l.state||{};return[a.idx,createReadOnlyObject({pathname:t,search:n,hash:r,state:a.usr||null,key:a.key||"default"})]}var t=(void 0===e?{}:e).window,u=void 0===t?document.defaultView:t,l=u.history,c=null;u.addEventListener(PopStateEventType,function(){if(c)i.call(c),c=null;else{var e=PopAction,t=o(),n=t[0],r=t[1];if(i.length){if(null!=n){var a=s-n;a&&(c={action:e,location:r,retry:function(){g(-1*a)}},g(a))}}else y(e)}});var n=PopAction,r=o(),s=r[0],a=r[1],i=createEvents(),f=createEvents();null==s&&(s=0,l.replaceState(_extends({},l.state,{idx:s}),null));function h(e,t){return void 0===t&&(t=null),createReadOnlyObject(_extends({},a,{},"string"==typeof e?parsePath(e):e,{state:t,key:createKey()}))}function p(e,t){return[{usr:e.state,key:e.key,idx:t},d(e)]}function v(e,t,n){return!i.length||(i.call({action:e,location:t,retry:n}),!1)}var d=createPath,y=function(e){n=e;var t=o();s=t[0],a=t[1],f.call({action:n,location:a})},g=function(e){l.go(e)};return{get action(){return n},get location(){return a},createHref:d,push:function e(t,n){var r=PushAction,a=h(t,n);if(v(r,a,function(){return e(t,n)})){var o=p(a,s+1),c=o[0],i=o[1];try{l.pushState(c,null,i)}catch(e){u.location.assign(i)}y(r)}},replace:function e(t,n){var r=ReplaceAction,a=h(t,n);if(v(r,a,function(){return e(t,n)})){var o=p(a,s),c=o[0],i=o[1];l.replaceState(c,null,i),y(r)}},go:g,back:function(){g(-1)},forward:function(){g(1)},listen:function(e){return f.push(e)},block:function(e){var t=i.push(e);return 1===i.length&&u.addEventListener(BeforeUnloadEventType,promptBeforeUnload),function(){t(),i.length||u.removeEventListener(BeforeUnloadEventType,promptBeforeUnload)}}}},createHashHistory=function(e){function o(){var e=parsePath(u.location.hash.substr(1)),t=e.pathname,n=void 0===t?"/":t,r=e.search,a=void 0===r?"":r,o=e.hash,c=void 0===o?"":o,i=l.state||{};return[i.idx,createReadOnlyObject({pathname:n,search:a,hash:c,state:i.usr||null,key:i.key||"default"})]}function n(){if(c)f.call(c),c=null;else{var e=PopAction,t=o(),n=t[0],r=t[1];if(f.length){if(null!=n){var a=s-n;a&&(c={action:e,location:r,retry:function(){P(-1*a)}},P(a))}}else g(e)}}var t=(void 0===e?{}:e).window,u=void 0===t?document.defaultView:t,l=u.history,c=null;u.addEventListener(PopStateEventType,n),u.addEventListener(HashChangeEventType,function(e){var t=o()[1];createPath(t)!==createPath(i)&&n()});var r=PopAction,a=o(),s=a[0],i=a[1],f=createEvents(),h=createEvents();null==s&&(s=0,l.replaceState(_extends({},l.state,{idx:s}),null));function p(e){var t=document.querySelector("base"),n="";if(t&&t.getAttribute("href")){var r=u.location.href,a=r.indexOf("#");n=-1===a?r:r.slice(0,a)}return n+"#"+createPath(e)}function v(e,t){return void 0===t&&(t=null),createReadOnlyObject(_extends({},i,{},"string"==typeof e?parsePath(e):e,{state:t,key:createKey()}))}function d(e,t){return[{usr:e.state,key:e.key,idx:t},p(e)]}function y(e,t,n){return!f.length||(f.call({action:e,location:t,retry:n}),!1)}var g=function(e){r=e;var t=o();s=t[0],i=t[1],h.call({action:r,location:i})},P=function(e){l.go(e)};return{get action(){return r},get location(){return i},createHref:p,push:function e(t,n){var r=PushAction,a=v(t,n);if(y(r,a,function(){return e(t,n)})){var o=d(a,s+1),c=o[0],i=o[1];try{l.pushState(c,null,i)}catch(e){u.location.assign(i)}g(r)}},replace:function e(t,n){var r=ReplaceAction,a=v(t,n);if(y(r,a,function(){return e(t,n)})){var o=d(a,s),c=o[0],i=o[1];l.replaceState(c,null,i),g(r)}},go:P,back:function(){P(-1)},forward:function(){P(1)},listen:function(e){return h.push(e)},block:function(e){var t=f.push(e);return 1===f.length&&u.addEventListener(BeforeUnloadEventType,promptBeforeUnload),function(){t(),f.length||u.removeEventListener(BeforeUnloadEventType,promptBeforeUnload)}}}},promptBeforeUnload=function(e){e.preventDefault(),e.returnValue=""},createKey=function(){return Math.random().toString(36).substr(2,8)},createReadOnlyObject=function(n){return Object.keys(n).reduce(function(e,t){return Object.defineProperty(e,t,{enumerable:!0,value:n[t]})},Object.create(null))},createPath=function(e){var t=e.pathname,n=void 0===t?"/":t,r=e.search,a=void 0===r?"":r,o=e.hash;return n+a+(void 0===o?"":o)},parsePath=function(e){var t={};if(e){var n=e.indexOf("#");0<=n&&(t.hash=e.substr(n),e=e.substr(0,n));var r=e.indexOf("?");0<=r&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t},createEvents=function(){var e=[];return{get length(){return e.length},push:function(t){return e.push(t)&&function(){e=e.filter(function(e){return e!==t})}},call:function(t){e.forEach(function(e){return e&&e(t)})}}},clamp=function(e,t,n){return Math.min(Math.max(e,t),n)};exports.createMemoryHistory=createMemoryHistory,exports.createBrowserHistory=createBrowserHistory,exports.createHashHistory=createHashHistory; |
1338
esm/history.js
import _extends from '@babel/runtime/helpers/esm/extends'; | ||
import resolvePathname from 'resolve-pathname'; | ||
import valueEqual from 'value-equal'; | ||
import warning from 'tiny-warning'; | ||
import invariant from 'tiny-invariant'; | ||
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('#'); | ||
var PopAction = 'POP'; | ||
var PushAction = 'PUSH'; | ||
var ReplaceAction = 'REPLACE'; | ||
var BeforeUnloadEventType = 'beforeunload'; | ||
var PopStateEventType = 'popstate'; | ||
var HashChangeEventType = 'hashchange'; // There's some duplication in this code, but only one create* method | ||
// should ever be used in a given web page, so it's best for minifying | ||
// to just inline everything. | ||
if (hashIndex !== -1) { | ||
hash = pathname.substr(hashIndex); | ||
pathname = pathname.substr(0, hashIndex); | ||
} | ||
/** | ||
* Memory history stores the current location in memory. It is designed | ||
* for use in stateful non-browser environments like headless tests (in | ||
* node.js) and React Native. | ||
*/ | ||
var searchIndex = pathname.indexOf('?'); | ||
var createMemoryHistory = function createMemoryHistory(_temp) { | ||
var _ref = _temp === void 0 ? {} : _temp, | ||
_ref$initialEntries = _ref.initialEntries, | ||
initialEntries = _ref$initialEntries === void 0 ? ['/'] : _ref$initialEntries, | ||
_ref$initialIndex = _ref.initialIndex, | ||
initialIndex = _ref$initialIndex === void 0 ? 0 : _ref$initialIndex; | ||
if (searchIndex !== -1) { | ||
search = pathname.substr(searchIndex); | ||
pathname = pathname.substr(0, searchIndex); | ||
} | ||
var entries = initialEntries.map(function (entry) { | ||
var location = createReadOnlyObject(_extends({ | ||
pathname: '/', | ||
search: '', | ||
hash: '', | ||
state: null, | ||
key: createKey() | ||
}, typeof entry === 'string' ? parsePath(entry) : entry)); | ||
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; | ||
} | ||
if (process.env.NODE_ENV !== "production") { | ||
if (location.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(entry); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + arg + ")"); | ||
} | ||
} | ||
function createLocation(path, state, key, currentLocation) { | ||
var location; | ||
return location; | ||
}); | ||
var index = clamp(initialIndex, 0, entries.length - 1); | ||
var action = PopAction; | ||
var location = entries[index]; | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
var createHref = createPath; | ||
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 = ''; | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
if (location.hash) { | ||
if (location.hash.charAt(0) !== '#') location.hash = '#' + location.hash; | ||
} else { | ||
location.hash = ''; | ||
} | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if (state !== undefined && location.state === undefined) location.state = state; | ||
} | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
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; | ||
} | ||
} | ||
var applyTx = function applyTx(nextAction, nextLocation) { | ||
action = nextAction; | ||
location = nextLocation; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
}; | ||
if (key) location.key = key; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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); | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
if (process.env.NODE_ENV !== "production") { | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().push(" + arg + ")"); | ||
} | ||
} | ||
} else { | ||
// When there is no prior location and pathname is empty, set it to / | ||
if (!location.pathname) { | ||
location.pathname = '/'; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index += 1; | ||
entries.splice(index, entries.length, nextLocation); | ||
applyTx(nextAction, nextLocation); | ||
} | ||
} | ||
}; | ||
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); | ||
} | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function createTransitionManager() { | ||
var prompt = null; | ||
function setPrompt(nextPrompt) { | ||
process.env.NODE_ENV !== "production" ? warning(prompt == null, 'A history supports only one prompt at a time') : void 0; | ||
prompt = nextPrompt; | ||
return function () { | ||
if (prompt === nextPrompt) prompt = null; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
} | ||
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 { | ||
process.env.NODE_ENV !== "production" ? warning(false, 'A history needs a getUserConfirmation function in order to use a prompt message') : void 0; | ||
callback(true); | ||
} | ||
} else { | ||
// Return false from a transition hook to cancel the transition. | ||
callback(result !== false); | ||
if (process.env.NODE_ENV !== "production") { | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().replace(" + arg + ")"); | ||
} | ||
} else { | ||
callback(true); | ||
} | ||
} | ||
var listeners = []; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
entries[index] = nextLocation; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
function appendListener(fn) { | ||
var isActive = true; | ||
var go = function go(n) { | ||
var nextIndex = clamp(index + n, 0, entries.length - 1); | ||
var nextAction = PopAction; | ||
var nextLocation = entries[nextIndex]; | ||
function listener() { | ||
if (isActive) fn.apply(void 0, arguments); | ||
} | ||
listeners.push(listener); | ||
return function () { | ||
isActive = false; | ||
listeners = listeners.filter(function (item) { | ||
return item !== listener; | ||
}); | ||
var retry = function retry() { | ||
go(n); | ||
}; | ||
} | ||
function notifyListeners() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index = nextIndex; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
listeners.forEach(function (listener) { | ||
return listener.apply(void 0, args); | ||
}); | ||
} | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
return { | ||
setPrompt: setPrompt, | ||
confirmTransitionTo: confirmTransitionTo, | ||
appendListener: appendListener, | ||
notifyListeners: notifyListeners | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
} | ||
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 | ||
*/ | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
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. | ||
*/ | ||
var block = function block(fn) { | ||
return blockers.push(fn); | ||
}; | ||
function supportsPopStateOnHashChange() { | ||
return window.navigator.userAgent.indexOf('Trident') === -1; | ||
} | ||
/** | ||
* Returns false if using go(n) with hash history causes a full page reload. | ||
*/ | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
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. | ||
*/ | ||
get location() { | ||
return location; | ||
}, | ||
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 {}; | ||
} | ||
} | ||
createHref: createHref, | ||
push: push, | ||
replace: replace, | ||
go: go, | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
}; | ||
/** | ||
* Creates a history object that uses the HTML5 history API including | ||
* pushState, replaceState, and the popstate event. | ||
* Browser history stores the location in regular URLs. This is the | ||
* standard for most web apps, but it requires some configuration on | ||
* the server to ensure you serve the same app at multiple URLs. | ||
*/ | ||
var createBrowserHistory = function createBrowserHistory(_temp2) { | ||
var _ref2 = _temp2 === void 0 ? {} : _temp2, | ||
_ref2$window = _ref2.window, | ||
window = _ref2$window === void 0 ? document.defaultView : _ref2$window; | ||
function createBrowserHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
!canUseDOM ? process.env.NODE_ENV !== "production" ? invariant(false, 'Browser history needs a DOM') : invariant(false) : 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 getIndexAndLocation = function getIndexAndLocation() { | ||
var _window$location = window.location, | ||
@@ -272,207 +190,204 @@ pathname = _window$location.pathname, | ||
hash = _window$location.hash; | ||
var path = pathname + search + hash; | ||
process.env.NODE_ENV !== "production" ? 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 + '".') : void 0; | ||
if (basename) path = stripBasename(path, basename); | ||
return createLocation(path, state, key); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var blockedPopTx = null; | ||
var transitionManager = createTransitionManager(); | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
var _getIndexAndLocation = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation[0], | ||
nextLocation = _getIndexAndLocation[1]; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
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 | ||
}); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
revertPop(location); | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
if (process.env.NODE_ENV !== "production") { | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
}); | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
} | ||
}; | ||
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. | ||
window.addEventListener(PopStateEventType, handlePop); | ||
var action = PopAction; | ||
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; | ||
var _getIndexAndLocation2 = getIndexAndLocation(), | ||
index = _getIndexAndLocation2[0], | ||
location = _getIndexAndLocation2[1]; | ||
if (delta) { | ||
forceNextPop = true; | ||
go(delta); | ||
} | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
var initialLocation = getDOMLocation(getHistoryState()); | ||
var allKeys = [initialLocation.key]; // Public interface | ||
var createHref = createPath; | ||
function createHref(location) { | ||
return basename + createPath(location); | ||
} | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
function push(path, state) { | ||
process.env.NODE_ENV !== "production" ? 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') : void 0; | ||
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; | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if (canUseHistory) { | ||
globalHistory.pushState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
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 { | ||
process.env.NODE_ENV !== "production" ? warning(state === undefined, 'Browser history cannot push state in browsers that do not support HTML5 history') : void 0; | ||
window.location.href = href; | ||
} | ||
}); | ||
} | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
function replace(path, state) { | ||
process.env.NODE_ENV !== "production" ? 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') : void 0; | ||
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; | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
if (canUseHistory) { | ||
globalHistory.replaceState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var _getIndexAndLocation3 = getIndexAndLocation(); | ||
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 { | ||
process.env.NODE_ENV !== "production" ? warning(state === undefined, 'Browser history cannot replace state in browsers that do not support HTML5 history') : void 0; | ||
window.location.replace(href); | ||
} | ||
index = _getIndexAndLocation3[0]; | ||
location = _getIndexAndLocation3[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
function go(n) { | ||
globalHistory.go(n); | ||
} | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function goBack() { | ||
go(-1); | ||
} | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
function goForward() { | ||
go(1); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr[0], | ||
url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
var listenerCount = 0; | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
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); | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
var isBlocked = false; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr2[0], | ||
url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -482,285 +397,270 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
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 | ||
} | ||
}; | ||
/** | ||
* Hash history stores the location in window.location.hash. This makes | ||
* it ideal for situations where you don't want to send the location to | ||
* the server for some reason, either because you do cannot configure it | ||
* or the URL space is reserved for something else. | ||
*/ | ||
function stripHash(url) { | ||
var hashIndex = url.indexOf('#'); | ||
return hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
var createHashHistory = function createHashHistory(_temp3) { | ||
var _ref3 = _temp3 === void 0 ? {} : _temp3, | ||
_ref3$window = _ref3.window, | ||
window = _ref3$window === void 0 ? document.defaultView : _ref3$window; | ||
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); | ||
} | ||
var globalHistory = window.history; | ||
function pushHashPath(path) { | ||
window.location.hash = path; | ||
} | ||
var getIndexAndLocation = function getIndexAndLocation() { | ||
var _parsePath = parsePath(window.location.hash.substr(1)), | ||
_parsePath$pathname = _parsePath.pathname, | ||
pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname, | ||
_parsePath$search = _parsePath.search, | ||
search = _parsePath$search === void 0 ? '' : _parsePath$search, | ||
_parsePath$hash = _parsePath.hash, | ||
hash = _parsePath$hash === void 0 ? '' : _parsePath$hash; | ||
function replaceHashPath(path) { | ||
window.location.replace(stripHash(window.location.href) + '#' + path); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createHashHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var blockedPopTx = null; | ||
!canUseDOM ? process.env.NODE_ENV !== "production" ? invariant(false, 'Hash history needs a DOM') : invariant(false) : 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; | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
function getDOMLocation() { | ||
var path = decodePath(getHashPath()); | ||
process.env.NODE_ENV !== "production" ? 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 + '".') : void 0; | ||
if (basename) path = stripBasename(path, basename); | ||
return createLocation(path); | ||
} | ||
var _getIndexAndLocation4 = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation4[0], | ||
nextLocation = _getIndexAndLocation4[1]; | ||
var transitionManager = createTransitionManager(); | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
if (process.env.NODE_ENV !== "production") { | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
window.addEventListener(PopStateEventType, handlePop); // TODO: Is this still necessary? Which browsers do | ||
// not trigger popstate when the hash changes? | ||
var forceNextPop = false; | ||
var ignorePath = null; | ||
window.addEventListener(HashChangeEventType, function (event) { | ||
var _getIndexAndLocation5 = getIndexAndLocation(), | ||
nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events. | ||
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 (createPath(nextLocation) !== createPath(location)) { | ||
handlePop(); | ||
} | ||
}); | ||
var action = PopAction; | ||
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. | ||
var _getIndexAndLocation6 = getIndexAndLocation(), | ||
index = _getIndexAndLocation6[0], | ||
location = _getIndexAndLocation6[1]; | ||
if (ignorePath === createPath(location)) return; // Ignore this change; we already setState in push/replace. | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
ignorePath = null; | ||
handlePop(location); | ||
} | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
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); | ||
} | ||
}); | ||
var createHref = function createHref(location) { | ||
var base = document.querySelector('base'); | ||
var href = ''; | ||
if (base && base.getAttribute('href')) { | ||
var url = window.location.href; | ||
var hashIndex = url.indexOf('#'); | ||
href = hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
} | ||
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. | ||
return href + '#' + createPath(location); | ||
}; | ||
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); | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
} // Ensure the hash is encoded properly before doing anything else. | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
var path = getHashPath(); | ||
var encodedPath = encodePath(path); | ||
if (path !== encodedPath) replaceHashPath(encodedPath); | ||
var initialLocation = getDOMLocation(); | ||
var allPaths = [createPath(initialLocation)]; // Public interface | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
function createHref(location) { | ||
var baseTag = document.querySelector('base'); | ||
var href = ''; | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
if (baseTag && baseTag.getAttribute('href')) { | ||
href = stripHash(window.location.href); | ||
} | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
return href + '#' + encodePath(basename + createPath(location)); | ||
} | ||
var _getIndexAndLocation7 = getIndexAndLocation(); | ||
function push(path, state) { | ||
process.env.NODE_ENV !== "production" ? warning(state === undefined, 'Hash history cannot push state; it is ignored') : void 0; | ||
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 { | ||
process.env.NODE_ENV !== "production" ? warning(false, 'Hash history cannot PUSH the same path; a new entry will not be added to the history stack') : void 0; | ||
setState(); | ||
} | ||
index = _getIndexAndLocation7[0]; | ||
location = _getIndexAndLocation7[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
function replace(path, state) { | ||
process.env.NODE_ENV !== "production" ? warning(state === undefined, 'Hash history cannot replace state; it is ignored') : void 0; | ||
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; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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 retry = function retry() { | ||
return push(to, state); | ||
}; | ||
if (process.env.NODE_ENV !== "production") { | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().push(" + arg + ")"); | ||
} | ||
} | ||
var prevIndex = allPaths.indexOf(createPath(history.location)); | ||
if (prevIndex !== -1) allPaths[prevIndex] = path; | ||
setState({ | ||
action: action, | ||
location: location | ||
}); | ||
}); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr3[0], | ||
url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
function go(n) { | ||
process.env.NODE_ENV !== "production" ? warning(canGoWithoutReload, 'Hash history go(n) causes a full page reload in this browser') : void 0; | ||
globalHistory.go(n); | ||
} | ||
function goBack() { | ||
go(-1); | ||
} | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
function goForward() { | ||
go(1); | ||
} | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var listenerCount = 0; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (listenerCount === 1 && delta === 1) { | ||
window.addEventListener(HashChangeEvent$1, handleHashChange); | ||
} else if (listenerCount === 0) { | ||
window.removeEventListener(HashChangeEvent$1, handleHashChange); | ||
if (process.env.NODE_ENV !== "production") { | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().replace(" + arg + ")"); | ||
} | ||
} | ||
} | ||
var isBlocked = false; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr4[0], | ||
url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -770,153 +670,93 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
} | ||
}; // Utils | ||
function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
} | ||
/** | ||
* Creates a history object that stores locations in memory. | ||
*/ | ||
var promptBeforeUnload = function promptBeforeUnload(event) { | ||
// Cancel the event. | ||
event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set. | ||
event.returnValue = ''; | ||
}; | ||
function createMemoryHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var createKey = function createKey() { | ||
return Math.random().toString(36).substr(2, 8); | ||
}; // TODO: Probably only do this in dev? | ||
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); | ||
var createReadOnlyObject = function createReadOnlyObject(props) { | ||
return Object.keys(props).reduce(function (obj, key) { | ||
return Object.defineProperty(obj, key, { | ||
enumerable: true, | ||
value: props[key] | ||
}); | ||
}, Object.create(null)); | ||
}; | ||
history.length = history.entries.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
var createPath = function createPath(_ref4) { | ||
var _ref4$pathname = _ref4.pathname, | ||
pathname = _ref4$pathname === void 0 ? '/' : _ref4$pathname, | ||
_ref4$search = _ref4.search, | ||
search = _ref4$search === void 0 ? '' : _ref4$search, | ||
_ref4$hash = _ref4.hash, | ||
hash = _ref4$hash === void 0 ? '' : _ref4$hash; | ||
return pathname + search + hash; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var parsePath = function parsePath(path) { | ||
var pieces = {}; | ||
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 | ||
if (path) { | ||
var hashIndex = path.indexOf('#'); | ||
var createHref = createPath; | ||
if (hashIndex >= 0) { | ||
pieces.hash = path.substr(hashIndex); | ||
path = path.substr(0, hashIndex); | ||
} | ||
function push(path, state) { | ||
process.env.NODE_ENV !== "production" ? 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') : void 0; | ||
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); | ||
var searchIndex = path.indexOf('?'); | ||
if (nextEntries.length > nextIndex) { | ||
nextEntries.splice(nextIndex, nextEntries.length - nextIndex, location); | ||
} else { | ||
nextEntries.push(location); | ||
} | ||
if (searchIndex >= 0) { | ||
pieces.search = path.substr(searchIndex); | ||
path = path.substr(0, searchIndex); | ||
} | ||
setState({ | ||
action: action, | ||
location: location, | ||
index: nextIndex, | ||
entries: nextEntries | ||
}); | ||
}); | ||
if (path) { | ||
pieces.pathname = path; | ||
} | ||
} | ||
function replace(path, state) { | ||
process.env.NODE_ENV !== "production" ? 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') : void 0; | ||
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 | ||
}); | ||
}); | ||
} | ||
return pieces; | ||
}; | ||
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 | ||
var createEvents = function createEvents() { | ||
var handlers = []; | ||
return { | ||
get length() { | ||
return handlers.length; | ||
}, | ||
push: function push(fn) { | ||
return handlers.push(fn) && function () { | ||
handlers = handlers.filter(function (handler) { | ||
return handler !== fn; | ||
}); | ||
} 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; | ||
}; | ||
}, | ||
call: function call(arg) { | ||
handlers.forEach(function (fn) { | ||
return fn && fn(arg); | ||
}); | ||
} | ||
}; | ||
}; | ||
return transitionManager.setPrompt(prompt); | ||
} | ||
var clamp = function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
}; | ||
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; | ||
} | ||
export { createBrowserHistory, createHashHistory, createMemoryHistory, createLocation, locationsAreEqual, parsePath, createPath }; | ||
export { createMemoryHistory, createBrowserHistory, createHashHistory }; |
{ | ||
"name": "history", | ||
"version": "4.10.1", | ||
"version": "5.0.0-beta.0", | ||
"description": "Manage session history with JavaScript", | ||
@@ -12,15 +12,5 @@ "repository": "ReactTraining/history", | ||
"files": [ | ||
"DOMUtils.js", | ||
"ExecutionEnvironment.js", | ||
"LocationUtils.js", | ||
"PathUtils.js", | ||
"cjs", | ||
"createBrowserHistory.js", | ||
"createHashHistory.js", | ||
"createMemoryHistory.js", | ||
"createTransitionManager.js", | ||
"es", | ||
"esm", | ||
"umd", | ||
"warnAboutDeprecatedCJSRequire.js" | ||
"umd" | ||
], | ||
@@ -31,3 +21,3 @@ "sideEffects": false, | ||
"clean": "git clean -fdX .", | ||
"lint": "eslint modules", | ||
"lint": "eslint .", | ||
"prepublishOnly": "yarn build", | ||
@@ -38,7 +28,3 @@ "test": "karma start --single-run" | ||
"@babel/runtime": "^7.1.2", | ||
"loose-envify": "^1.2.0", | ||
"resolve-pathname": "^3.0.0", | ||
"tiny-invariant": "^1.0.2", | ||
"tiny-warning": "^1.0.0", | ||
"value-equal": "^1.0.1" | ||
"loose-envify": "^1.2.0" | ||
}, | ||
@@ -57,2 +43,3 @@ "devDependencies": { | ||
"expect": "^21.0.0", | ||
"express": "^4.17.1", | ||
"jest-mock": "^21.0.0", | ||
@@ -59,0 +46,0 @@ "karma": "^3.1.3", |
1468
umd/history.js
@@ -25,401 +25,185 @@ (function (global, factory) { | ||
function isAbsolute(pathname) { | ||
return pathname.charAt(0) === '/'; | ||
} | ||
var PopAction = 'POP'; | ||
var PushAction = 'PUSH'; | ||
var ReplaceAction = 'REPLACE'; | ||
var BeforeUnloadEventType = 'beforeunload'; | ||
var PopStateEventType = 'popstate'; | ||
var HashChangeEventType = 'hashchange'; // There's some duplication in this code, but only one create* method | ||
// should ever be used in a given web page, so it's best for minifying | ||
// to just inline everything. | ||
// 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]; | ||
} | ||
/** | ||
* Memory history stores the current location in memory. It is designed | ||
* for use in stateful non-browser environments like headless tests (in | ||
* node.js) and React Native. | ||
*/ | ||
list.pop(); | ||
} | ||
var createMemoryHistory = function createMemoryHistory(_temp) { | ||
var _ref = _temp === void 0 ? {} : _temp, | ||
_ref$initialEntries = _ref.initialEntries, | ||
initialEntries = _ref$initialEntries === void 0 ? ['/'] : _ref$initialEntries, | ||
_ref$initialIndex = _ref.initialIndex, | ||
initialIndex = _ref$initialIndex === void 0 ? 0 : _ref$initialIndex; | ||
// This implementation is based heavily on node's url.parse | ||
function resolvePathname(to, from) { | ||
if (from === undefined) from = ''; | ||
var entries = initialEntries.map(function (entry) { | ||
var location = createReadOnlyObject(_extends({ | ||
pathname: '/', | ||
search: '', | ||
hash: '', | ||
state: null, | ||
key: createKey() | ||
}, typeof entry === 'string' ? parsePath(entry) : entry)); | ||
var toParts = (to && to.split('/')) || []; | ||
var fromParts = (from && from.split('/')) || []; | ||
{ | ||
if (location.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(entry); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + arg + ")"); | ||
} | ||
} | ||
var isToAbs = to && isAbsolute(to); | ||
var isFromAbs = from && isAbsolute(from); | ||
var mustEndAbs = isToAbs || isFromAbs; | ||
return location; | ||
}); | ||
var index = clamp(initialIndex, 0, entries.length - 1); | ||
var action = PopAction; | ||
var location = entries[index]; | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
var createHref = createPath; | ||
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--; | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
} | ||
if (!mustEndAbs) for (; up--; up) fromParts.unshift('..'); | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if ( | ||
mustEndAbs && | ||
fromParts[0] !== '' && | ||
(!fromParts[0] || !isAbsolute(fromParts[0])) | ||
) | ||
fromParts.unshift(''); | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
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]); | ||
var applyTx = function applyTx(nextAction, nextLocation) { | ||
action = nextAction; | ||
location = nextLocation; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
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; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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 = ''; | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
if (location.search) { | ||
if (location.search.charAt(0) !== '?') location.search = '?' + location.search; | ||
} else { | ||
location.search = ''; | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().push(" + arg + ")"); | ||
} | ||
} | ||
if (location.hash) { | ||
if (location.hash.charAt(0) !== '#') location.hash = '#' + location.hash; | ||
} else { | ||
location.hash = ''; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index += 1; | ||
entries.splice(index, entries.length, nextLocation); | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
if (state !== undefined && location.state === undefined) location.state = state; | ||
} | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, 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; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
} | ||
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); | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createMemoryHistory().replace(" + arg + ")"); | ||
} | ||
} else { | ||
callback(true); | ||
} | ||
} | ||
var listeners = []; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
entries[index] = nextLocation; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
function appendListener(fn) { | ||
var isActive = true; | ||
var go = function go(n) { | ||
var nextIndex = clamp(index + n, 0, entries.length - 1); | ||
var nextAction = PopAction; | ||
var nextLocation = entries[nextIndex]; | ||
function listener() { | ||
if (isActive) fn.apply(void 0, arguments); | ||
} | ||
listeners.push(listener); | ||
return function () { | ||
isActive = false; | ||
listeners = listeners.filter(function (item) { | ||
return item !== listener; | ||
}); | ||
var retry = function retry() { | ||
go(n); | ||
}; | ||
} | ||
function notifyListeners() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
index = nextIndex; | ||
applyTx(nextAction, nextLocation); | ||
} | ||
}; | ||
listeners.forEach(function (listener) { | ||
return listener.apply(void 0, args); | ||
}); | ||
} | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
return { | ||
setPrompt: setPrompt, | ||
confirmTransitionTo: confirmTransitionTo, | ||
appendListener: appendListener, | ||
notifyListeners: notifyListeners | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
} | ||
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 | ||
*/ | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
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. | ||
*/ | ||
var block = function block(fn) { | ||
return blockers.push(fn); | ||
}; | ||
function supportsPopStateOnHashChange() { | ||
return window.navigator.userAgent.indexOf('Trident') === -1; | ||
} | ||
/** | ||
* Returns false if using go(n) with hash history causes a full page reload. | ||
*/ | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
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. | ||
*/ | ||
get location() { | ||
return location; | ||
}, | ||
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 {}; | ||
} | ||
} | ||
createHref: createHref, | ||
push: push, | ||
replace: replace, | ||
go: go, | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
}; | ||
/** | ||
* Creates a history object that uses the HTML5 history API including | ||
* pushState, replaceState, and the popstate event. | ||
* Browser history stores the location in regular URLs. This is the | ||
* standard for most web apps, but it requires some configuration on | ||
* the server to ensure you serve the same app at multiple URLs. | ||
*/ | ||
var createBrowserHistory = function createBrowserHistory(_temp2) { | ||
var _ref2 = _temp2 === void 0 ? {} : _temp2, | ||
_ref2$window = _ref2.window, | ||
window = _ref2$window === void 0 ? document.defaultView : _ref2$window; | ||
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 getIndexAndLocation = function getIndexAndLocation() { | ||
var _window$location = window.location, | ||
@@ -429,207 +213,204 @@ pathname = _window$location.pathname, | ||
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); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var blockedPopTx = null; | ||
var transitionManager = createTransitionManager(); | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
var _getIndexAndLocation = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation[0], | ||
nextLocation = _getIndexAndLocation[1]; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
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 | ||
}); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
revertPop(location); | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
{ | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
}); | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
} | ||
}; | ||
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. | ||
window.addEventListener(PopStateEventType, handlePop); | ||
var action = PopAction; | ||
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; | ||
var _getIndexAndLocation2 = getIndexAndLocation(), | ||
index = _getIndexAndLocation2[0], | ||
location = _getIndexAndLocation2[1]; | ||
if (delta) { | ||
forceNextPop = true; | ||
go(delta); | ||
} | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
var initialLocation = getDOMLocation(getHistoryState()); | ||
var allKeys = [initialLocation.key]; // Public interface | ||
var createHref = createPath; | ||
function createHref(location) { | ||
return basename + createPath(location); | ||
} | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
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; | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
if (canUseHistory) { | ||
globalHistory.pushState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
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; | ||
} | ||
}); | ||
} | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
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; | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
if (canUseHistory) { | ||
globalHistory.replaceState({ | ||
key: key, | ||
state: state | ||
}, null, href); | ||
var _getIndexAndLocation3 = getIndexAndLocation(); | ||
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); | ||
} | ||
index = _getIndexAndLocation3[0]; | ||
location = _getIndexAndLocation3[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
function go(n) { | ||
globalHistory.go(n); | ||
} | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function goBack() { | ||
go(-1); | ||
} | ||
var retry = function retry() { | ||
return push(to, state); | ||
}; | ||
function goForward() { | ||
go(1); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr[0], | ||
url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
var listenerCount = 0; | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
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); | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
var isBlocked = false; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr2[0], | ||
url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -639,285 +420,270 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
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 | ||
} | ||
}; | ||
/** | ||
* Hash history stores the location in window.location.hash. This makes | ||
* it ideal for situations where you don't want to send the location to | ||
* the server for some reason, either because you do cannot configure it | ||
* or the URL space is reserved for something else. | ||
*/ | ||
function stripHash(url) { | ||
var hashIndex = url.indexOf('#'); | ||
return hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
var createHashHistory = function createHashHistory(_temp3) { | ||
var _ref3 = _temp3 === void 0 ? {} : _temp3, | ||
_ref3$window = _ref3.window, | ||
window = _ref3$window === void 0 ? document.defaultView : _ref3$window; | ||
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); | ||
} | ||
var globalHistory = window.history; | ||
function pushHashPath(path) { | ||
window.location.hash = path; | ||
} | ||
var getIndexAndLocation = function getIndexAndLocation() { | ||
var _parsePath = parsePath(window.location.hash.substr(1)), | ||
_parsePath$pathname = _parsePath.pathname, | ||
pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname, | ||
_parsePath$search = _parsePath.search, | ||
search = _parsePath$search === void 0 ? '' : _parsePath$search, | ||
_parsePath$hash = _parsePath.hash, | ||
hash = _parsePath$hash === void 0 ? '' : _parsePath$hash; | ||
function replaceHashPath(path) { | ||
window.location.replace(stripHash(window.location.href) + '#' + path); | ||
} | ||
var state = globalHistory.state || {}; | ||
return [state.idx, createReadOnlyObject({ | ||
pathname: pathname, | ||
search: search, | ||
hash: hash, | ||
state: state.usr || null, | ||
key: state.key || 'default' | ||
})]; | ||
}; | ||
function createHashHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var blockedPopTx = null; | ||
!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; | ||
var handlePop = function handlePop() { | ||
if (blockedPopTx) { | ||
blockers.call(blockedPopTx); | ||
blockedPopTx = null; | ||
} else { | ||
var nextAction = PopAction; | ||
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 _getIndexAndLocation4 = getIndexAndLocation(), | ||
nextIndex = _getIndexAndLocation4[0], | ||
nextLocation = _getIndexAndLocation4[1]; | ||
var transitionManager = createTransitionManager(); | ||
if (blockers.length) { | ||
if (nextIndex != null) { | ||
var n = index - nextIndex; | ||
function setState(nextState) { | ||
_extends(history, nextState); | ||
if (n) { | ||
// Revert the POP | ||
blockedPopTx = { | ||
action: nextAction, | ||
location: nextLocation, | ||
retry: function retry() { | ||
go(n * -1); | ||
} | ||
}; | ||
go(n); | ||
} | ||
} else { | ||
// Trying to POP to a location with no index. We did not create | ||
// this location, so we can't effectively block the navigation. | ||
{ | ||
// TODO: Write up a doc that explains our blocking strategy in | ||
// detail and link to it here so people can understand better | ||
// what is going on and how to avoid it. | ||
throw new Error("You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation."); | ||
} | ||
} | ||
} else { | ||
applyTx(nextAction); | ||
} | ||
} | ||
}; | ||
history.length = globalHistory.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
window.addEventListener(PopStateEventType, handlePop); // TODO: Is this still necessary? Which browsers do | ||
// not trigger popstate when the hash changes? | ||
var forceNextPop = false; | ||
var ignorePath = null; | ||
window.addEventListener(HashChangeEventType, function (event) { | ||
var _getIndexAndLocation5 = getIndexAndLocation(), | ||
nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events. | ||
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 (createPath(nextLocation) !== createPath(location)) { | ||
handlePop(); | ||
} | ||
}); | ||
var action = PopAction; | ||
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. | ||
var _getIndexAndLocation6 = getIndexAndLocation(), | ||
index = _getIndexAndLocation6[0], | ||
location = _getIndexAndLocation6[1]; | ||
if (ignorePath === createPath(location)) return; // Ignore this change; we already setState in push/replace. | ||
var blockers = createEvents(); | ||
var listeners = createEvents(); | ||
ignorePath = null; | ||
handlePop(location); | ||
} | ||
if (index == null) { | ||
index = 0; | ||
globalHistory.replaceState(_extends({}, globalHistory.state, { | ||
idx: index | ||
}), null); | ||
} | ||
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); | ||
} | ||
}); | ||
var createHref = function createHref(location) { | ||
var base = document.querySelector('base'); | ||
var href = ''; | ||
if (base && base.getAttribute('href')) { | ||
var url = window.location.href; | ||
var hashIndex = url.indexOf('#'); | ||
href = hashIndex === -1 ? url : url.slice(0, hashIndex); | ||
} | ||
} | ||
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. | ||
return href + '#' + createPath(location); | ||
}; | ||
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); | ||
var getNextLocation = function getNextLocation(to, state) { | ||
if (state === void 0) { | ||
state = null; | ||
} | ||
} // Ensure the hash is encoded properly before doing anything else. | ||
return createReadOnlyObject(_extends({}, location, {}, typeof to === 'string' ? parsePath(to) : to, { | ||
state: state, | ||
key: createKey() | ||
})); | ||
}; | ||
var path = getHashPath(); | ||
var encodedPath = encodePath(path); | ||
if (path !== encodedPath) replaceHashPath(encodedPath); | ||
var initialLocation = getDOMLocation(); | ||
var allPaths = [createPath(initialLocation)]; // Public interface | ||
var getHistoryStateAndUrl = function getHistoryStateAndUrl(nextLocation, index) { | ||
return [{ | ||
usr: nextLocation.state, | ||
key: nextLocation.key, | ||
idx: index | ||
}, createHref(nextLocation)]; | ||
}; | ||
function createHref(location) { | ||
var baseTag = document.querySelector('base'); | ||
var href = ''; | ||
var allowTx = function allowTx(action, location, retry) { | ||
return !blockers.length || (blockers.call({ | ||
action: action, | ||
location: location, | ||
retry: retry | ||
}), false); | ||
}; | ||
if (baseTag && baseTag.getAttribute('href')) { | ||
href = stripHash(window.location.href); | ||
} | ||
var applyTx = function applyTx(nextAction) { | ||
action = nextAction; | ||
return href + '#' + encodePath(basename + createPath(location)); | ||
} | ||
var _getIndexAndLocation7 = getIndexAndLocation(); | ||
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(); | ||
} | ||
index = _getIndexAndLocation7[0]; | ||
location = _getIndexAndLocation7[1]; | ||
listeners.call({ | ||
action: action, | ||
location: location | ||
}); | ||
} | ||
}; | ||
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; | ||
var push = function push(to, state) { | ||
var nextAction = PushAction; | ||
var nextLocation = getNextLocation(to, state); | ||
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 retry = function retry() { | ||
return push(to, state); | ||
}; | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().push(" + arg + ")"); | ||
} | ||
} | ||
var prevIndex = allPaths.indexOf(createPath(history.location)); | ||
if (prevIndex !== -1) allPaths[prevIndex] = path; | ||
setState({ | ||
action: action, | ||
location: location | ||
}); | ||
}); | ||
} | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1), | ||
historyState = _getHistoryStateAndUr3[0], | ||
url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading | ||
// try...catch because iOS limits us to 100 pushState calls :/ | ||
function go(n) { | ||
warning(canGoWithoutReload, 'Hash history go(n) causes a full page reload in this browser'); | ||
globalHistory.go(n); | ||
} | ||
function goBack() { | ||
go(-1); | ||
} | ||
try { | ||
globalHistory.pushState(historyState, null, url); | ||
} catch (error) { | ||
// They are going to lose state here, but there is no real | ||
// way to warn them about it since the page will refresh... | ||
window.location.assign(url); | ||
} | ||
function goForward() { | ||
go(1); | ||
} | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var listenerCount = 0; | ||
var replace = function replace(to, state) { | ||
var nextAction = ReplaceAction; | ||
var nextLocation = getNextLocation(to, state); | ||
function checkDOMListeners(delta) { | ||
listenerCount += delta; | ||
var retry = function retry() { | ||
return replace(to, state); | ||
}; | ||
if (listenerCount === 1 && delta === 1) { | ||
window.addEventListener(HashChangeEvent$1, handleHashChange); | ||
} else if (listenerCount === 0) { | ||
window.removeEventListener(HashChangeEvent$1, handleHashChange); | ||
{ | ||
if (nextLocation.pathname.charAt(0) !== '/') { | ||
var arg = JSON.stringify(to); | ||
throw new Error("Relative pathnames are not supported in createHashHistory().replace(" + arg + ")"); | ||
} | ||
} | ||
} | ||
var isBlocked = false; | ||
if (allowTx(nextAction, nextLocation, retry)) { | ||
var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index), | ||
historyState = _getHistoryStateAndUr4[0], | ||
url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading | ||
function block(prompt) { | ||
if (prompt === void 0) { | ||
prompt = false; | ||
globalHistory.replaceState(historyState, null, url); | ||
applyTx(nextAction); | ||
} | ||
}; | ||
var unblock = transitionManager.setPrompt(prompt); | ||
var go = function go(n) { | ||
globalHistory.go(n); | ||
}; | ||
if (!isBlocked) { | ||
checkDOMListeners(1); | ||
isBlocked = true; | ||
var back = function back() { | ||
go(-1); | ||
}; | ||
var forward = function forward() { | ||
go(1); | ||
}; | ||
var listen = function listen(fn) { | ||
return listeners.push(fn); | ||
}; | ||
var block = function block(fn) { | ||
var unblock = blockers.push(fn); | ||
if (blockers.length === 1) { | ||
window.addEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return function () { | ||
if (isBlocked) { | ||
isBlocked = false; | ||
checkDOMListeners(-1); | ||
unblock(); // Remove the beforeunload listener so the document may | ||
// still be salvageable in the pagehide event. | ||
// See https://html.spec.whatwg.org/#unloading-documents | ||
if (!blockers.length) { | ||
window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload); | ||
} | ||
return unblock(); | ||
}; | ||
} | ||
}; | ||
function listen(listener) { | ||
var unlisten = transitionManager.appendListener(listener); | ||
checkDOMListeners(1); | ||
return function () { | ||
checkDOMListeners(-1); | ||
unlisten(); | ||
}; | ||
} | ||
var history = { | ||
get action() { | ||
return action; | ||
}, | ||
var history = { | ||
length: globalHistory.length, | ||
action: 'POP', | ||
location: initialLocation, | ||
get location() { | ||
return location; | ||
}, | ||
createHref: createHref, | ||
@@ -927,160 +693,96 @@ push: push, | ||
go: go, | ||
goBack: goBack, | ||
goForward: goForward, | ||
block: block, | ||
listen: listen | ||
back: back, | ||
forward: forward, | ||
listen: listen, | ||
block: block | ||
}; | ||
return history; | ||
} | ||
}; // Utils | ||
function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
} | ||
/** | ||
* Creates a history object that stores locations in memory. | ||
*/ | ||
var promptBeforeUnload = function promptBeforeUnload(event) { | ||
// Cancel the event. | ||
event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set. | ||
event.returnValue = ''; | ||
}; | ||
function createMemoryHistory(props) { | ||
if (props === void 0) { | ||
props = {}; | ||
} | ||
var createKey = function createKey() { | ||
return Math.random().toString(36).substr(2, 8); | ||
}; // TODO: Probably only do this in dev? | ||
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); | ||
var createReadOnlyObject = function createReadOnlyObject(props) { | ||
return Object.keys(props).reduce(function (obj, key) { | ||
return Object.defineProperty(obj, key, { | ||
enumerable: true, | ||
value: props[key] | ||
}); | ||
}, Object.create(null)); | ||
}; | ||
history.length = history.entries.length; | ||
transitionManager.notifyListeners(history.location, history.action); | ||
} | ||
var createPath = function createPath(_ref4) { | ||
var _ref4$pathname = _ref4.pathname, | ||
pathname = _ref4$pathname === void 0 ? '/' : _ref4$pathname, | ||
_ref4$search = _ref4.search, | ||
search = _ref4$search === void 0 ? '' : _ref4$search, | ||
_ref4$hash = _ref4.hash, | ||
hash = _ref4$hash === void 0 ? '' : _ref4$hash; | ||
return pathname + search + hash; | ||
}; | ||
function createKey() { | ||
return Math.random().toString(36).substr(2, keyLength); | ||
} | ||
var parsePath = function parsePath(path) { | ||
var pieces = {}; | ||
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 | ||
if (path) { | ||
var hashIndex = path.indexOf('#'); | ||
var createHref = createPath; | ||
if (hashIndex >= 0) { | ||
pieces.hash = path.substr(hashIndex); | ||
path = path.substr(0, hashIndex); | ||
} | ||
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); | ||
var searchIndex = path.indexOf('?'); | ||
if (nextEntries.length > nextIndex) { | ||
nextEntries.splice(nextIndex, nextEntries.length - nextIndex, location); | ||
} else { | ||
nextEntries.push(location); | ||
} | ||
if (searchIndex >= 0) { | ||
pieces.search = path.substr(searchIndex); | ||
path = path.substr(0, searchIndex); | ||
} | ||
setState({ | ||
action: action, | ||
location: location, | ||
index: nextIndex, | ||
entries: nextEntries | ||
}); | ||
}); | ||
if (path) { | ||
pieces.pathname = path; | ||
} | ||
} | ||
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 | ||
}); | ||
}); | ||
} | ||
return pieces; | ||
}; | ||
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 | ||
var createEvents = function createEvents() { | ||
var handlers = []; | ||
return { | ||
get length() { | ||
return handlers.length; | ||
}, | ||
push: function push(fn) { | ||
return handlers.push(fn) && function () { | ||
handlers = handlers.filter(function (handler) { | ||
return handler !== fn; | ||
}); | ||
} 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; | ||
}; | ||
}, | ||
call: function call(arg) { | ||
handlers.forEach(function (fn) { | ||
return fn && fn(arg); | ||
}); | ||
} | ||
}; | ||
}; | ||
return transitionManager.setPrompt(prompt); | ||
} | ||
var clamp = function clamp(n, lowerBound, upperBound) { | ||
return Math.min(Math.max(n, lowerBound), upperBound); | ||
}; | ||
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.createMemoryHistory = createMemoryHistory; | ||
exports.createBrowserHistory = createBrowserHistory; | ||
exports.createHashHistory = createHashHistory; | ||
exports.createMemoryHistory = createMemoryHistory; | ||
exports.createLocation = createLocation; | ||
exports.locationsAreEqual = locationsAreEqual; | ||
exports.parsePath = parsePath; | ||
exports.createPath = createPath; | ||
@@ -1087,0 +789,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,1 +0,1 @@ | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.History={})}(this,function(n){"use strict";function E(){return(E=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o])}return n}).apply(this,arguments)}function d(n){return"/"===n.charAt(0)}function v(n,t){for(var e=t,o=e+1,r=n.length;o<r;e+=1,o+=1)n[e]=n[o];n.pop()}function i(n){return n.valueOf?n.valueOf():Object.prototype.valueOf.call(n)}function H(n){return"/"===n.charAt(0)?n:"/"+n}function t(n){return"/"===n.charAt(0)?n.substr(1):n}function S(n,t){return function(n,t){return 0===n.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(n.charAt(t.length))}(n,t)?n.substr(t.length):n}function U(n){return"/"===n.charAt(n.length-1)?n.slice(0,-1):n}function a(n){var t=n||"/",e="",o="",r=t.indexOf("#");-1!==r&&(o=t.substr(r),t=t.substr(0,r));var i=t.indexOf("?");return-1!==i&&(e=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===e?"":e,hash:"#"===o?"":o}}function j(n){var t=n.pathname,e=n.search,o=n.hash,r=t||"/";return e&&"?"!==e&&(r+="?"===e.charAt(0)?e:"?"+e),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}function C(n,t,e,o){var r;"string"==typeof n?(r=a(n)).state=t:(void 0===(r=E({},n)).pathname&&(r.pathname=""),r.search?"?"!==r.search.charAt(0)&&(r.search="?"+r.search):r.search="",r.hash?"#"!==r.hash.charAt(0)&&(r.hash="#"+r.hash):r.hash="",void 0!==t&&void 0===r.state&&(r.state=t));try{r.pathname=decodeURI(r.pathname)}catch(n){throw n instanceof URIError?new URIError('Pathname "'+r.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):n}return e&&(r.key=e),o?r.pathname?"/"!==r.pathname.charAt(0)&&(r.pathname=function(n,t){void 0===t&&(t="");var e,o=n&&n.split("/")||[],r=t&&t.split("/")||[],i=n&&d(n),a=t&&d(t),c=i||a;if(n&&d(n)?r=o:o.length&&(r.pop(),r=r.concat(o)),!r.length)return"/";if(r.length){var u=r[r.length-1];e="."===u||".."===u||""===u}else e=!1;for(var f=0,s=r.length;0<=s;s--){var h=r[s];"."===h?v(r,s):".."===h?(v(r,s),f++):f&&(v(r,s),f--)}if(!c)for(;f--;)r.unshift("..");!c||""===r[0]||r[0]&&d(r[0])||r.unshift("");var l=r.join("/");return e&&"/"!==l.substr(-1)&&(l+="/"),l}(r.pathname,o.pathname)):r.pathname=o.pathname:r.pathname||(r.pathname="/"),r}function I(){var i=null;var o=[];return{setPrompt:function(n){return i=n,function(){i===n&&(i=null)}},confirmTransitionTo:function(n,t,e,o){if(null!=i){var r="function"==typeof i?i(n,t):i;"string"==typeof r?"function"==typeof e?e(r,o):o(!0):o(!1!==r)}else o(!0)},appendListener:function(n){var t=!0;function e(){t&&n.apply(void 0,arguments)}return o.push(e),function(){t=!1,o=o.filter(function(n){return n!==e})}},notifyListeners:function(){for(var n=arguments.length,t=new Array(n),e=0;e<n;e++)t[e]=arguments[e];o.forEach(function(n){return n.apply(void 0,t)})}}}var M=!("undefined"==typeof window||!window.document||!window.document.createElement);function R(n,t){t(window.confirm(n))}var e="Invariant failed";function B(n){if(!n)throw new Error(e)}var F="popstate",q="hashchange";function _(){try{return window.history.state||{}}catch(n){return{}}}var T="hashchange",L={hashbang:{encodePath:function(n){return"!"===n.charAt(0)?n:"!/"+t(n)},decodePath:function(n){return"!"===n.charAt(0)?n.substr(1):n}},noslash:{encodePath:t,decodePath:H},slash:{encodePath:H,decodePath:H}};function G(n){var t=n.indexOf("#");return-1===t?n:n.slice(0,t)}function W(){var n=window.location.href,t=n.indexOf("#");return-1===t?"":n.substring(t+1)}function z(n){window.location.replace(G(window.location.href)+"#"+n)}function g(n,t,e){return Math.min(Math.max(n,t),e)}n.createBrowserHistory=function(n){void 0===n&&(n={}),M||B(!1);var c=window.history,u=function(){var n=window.navigator.userAgent;return(-1===n.indexOf("Android 2.")&&-1===n.indexOf("Android 4.0")||-1===n.indexOf("Mobile Safari")||-1!==n.indexOf("Chrome")||-1!==n.indexOf("Windows Phone"))&&(window.history&&"pushState"in window.history)}(),t=!(-1===window.navigator.userAgent.indexOf("Trident")),e=n,o=e.forceRefresh,f=void 0!==o&&o,r=e.getUserConfirmation,s=void 0===r?R:r,i=e.keyLength,a=void 0===i?6:i,h=n.basename?U(H(n.basename)):"";function l(n){var t=n||{},e=t.key,o=t.state,r=window.location,i=r.pathname+r.search+r.hash;return h&&(i=S(i,h)),C(i,o,e)}function d(){return Math.random().toString(36).substr(2,a)}var v=I();function p(n){E(L,n),L.length=c.length,v.notifyListeners(L.location,L.action)}function w(n){!function(n){return void 0===n.state&&-1===navigator.userAgent.indexOf("CriOS")}(n)&&m(l(n.state))}function g(){m(l(_()))}var y=!1;function m(t){if(y)y=!1,p();else{v.confirmTransitionTo(t,"POP",s,function(n){n?p({action:"POP",location:t}):function(n){var t=L.location,e=O.indexOf(t.key);-1===e&&(e=0);var o=O.indexOf(n.key);-1===o&&(o=0);var r=e-o;r&&(y=!0,b(r))}(t)})}}var P=l(_()),O=[P.key];function x(n){return h+j(n)}function b(n){c.go(n)}var A=0;function k(n){1===(A+=n)&&1===n?(window.addEventListener(F,w),t&&window.addEventListener(q,g)):0===A&&(window.removeEventListener(F,w),t&&window.removeEventListener(q,g))}var T=!1,L={length:c.length,action:"POP",location:P,createHref:x,push:function(n,t){var a=C(n,t,d(),L.location);v.confirmTransitionTo(a,"PUSH",s,function(n){if(n){var t=x(a),e=a.key,o=a.state;if(u)if(c.pushState({key:e,state:o},null,t),f)window.location.href=t;else{var r=O.indexOf(L.location.key),i=O.slice(0,r+1);i.push(a.key),O=i,p({action:"PUSH",location:a})}else window.location.href=t}})},replace:function(n,t){var i="REPLACE",a=C(n,t,d(),L.location);v.confirmTransitionTo(a,i,s,function(n){if(n){var t=x(a),e=a.key,o=a.state;if(u)if(c.replaceState({key:e,state:o},null,t),f)window.location.replace(t);else{var r=O.indexOf(L.location.key);-1!==r&&(O[r]=a.key),p({action:i,location:a})}else window.location.replace(t)}})},go:b,goBack:function(){b(-1)},goForward:function(){b(1)},block:function(n){void 0===n&&(n=!1);var t=v.setPrompt(n);return T||(k(1),T=!0),function(){return T&&(T=!1,k(-1)),t()}},listen:function(n){var t=v.appendListener(n);return k(1),function(){k(-1),t()}}};return L},n.createHashHistory=function(n){void 0===n&&(n={}),M||B(!1);var t=window.history,e=(window.navigator.userAgent.indexOf("Firefox"),n),o=e.getUserConfirmation,a=void 0===o?R:o,r=e.hashType,i=void 0===r?"slash":r,c=n.basename?U(H(n.basename)):"",u=L[i],f=u.encodePath,s=u.decodePath;function h(){var n=s(W());return c&&(n=S(n,c)),C(n)}var l=I();function d(n){E(k,n),k.length=t.length,l.notifyListeners(k.location,k.action)}var v=!1,p=null;function w(){var n=W(),t=f(n);if(n!==t)z(t);else{var e=h(),o=k.location;if(!v&&function(n,t){return n.pathname===t.pathname&&n.search===t.search&&n.hash===t.hash}(o,e))return;if(p===j(e))return;p=null,function(t){if(v)v=!1,d();else{l.confirmTransitionTo(t,"POP",a,function(n){n?d({action:"POP",location:t}):function(n){var t=k.location,e=P.lastIndexOf(j(t));-1===e&&(e=0);var o=P.lastIndexOf(j(n));-1===o&&(o=0);var r=e-o;r&&(v=!0,O(r))}(t)})}}(e)}}var g=W(),y=f(g);g!==y&&z(y);var m=h(),P=[j(m)];function O(n){t.go(n)}var x=0;function b(n){1===(x+=n)&&1===n?window.addEventListener(T,w):0===x&&window.removeEventListener(T,w)}var A=!1,k={length:t.length,action:"POP",location:m,createHref:function(n){var t=document.querySelector("base"),e="";return t&&t.getAttribute("href")&&(e=G(window.location.href)),e+"#"+f(c+j(n))},push:function(n,t){var i=C(n,void 0,void 0,k.location);l.confirmTransitionTo(i,"PUSH",a,function(n){if(n){var t=j(i),e=f(c+t);if(W()!==e){p=t,function(n){window.location.hash=n}(e);var o=P.lastIndexOf(j(k.location)),r=P.slice(0,o+1);r.push(t),P=r,d({action:"PUSH",location:i})}else d()}})},replace:function(n,t){var r="REPLACE",i=C(n,void 0,void 0,k.location);l.confirmTransitionTo(i,r,a,function(n){if(n){var t=j(i),e=f(c+t);W()!==e&&(p=t,z(e));var o=P.indexOf(j(k.location));-1!==o&&(P[o]=t),d({action:r,location:i})}})},go:O,goBack:function(){O(-1)},goForward:function(){O(1)},block:function(n){void 0===n&&(n=!1);var t=l.setPrompt(n);return A||(b(1),A=!0),function(){return A&&(A=!1,b(-1)),t()}},listen:function(n){var t=l.appendListener(n);return b(1),function(){b(-1),t()}}};return k},n.createMemoryHistory=function(n){void 0===n&&(n={});var t=n,r=t.getUserConfirmation,e=t.initialEntries,o=void 0===e?["/"]:e,i=t.initialIndex,a=void 0===i?0:i,c=t.keyLength,u=void 0===c?6:c,f=I();function s(n){E(w,n),w.length=w.entries.length,f.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,u)}var l=g(a,0,o.length-1),d=o.map(function(n){return C(n,void 0,"string"==typeof n?h():n.key||h())}),v=j;function p(n){var t=g(w.index+n,0,w.entries.length-1),e=w.entries[t];f.confirmTransitionTo(e,"POP",r,function(n){n?s({action:"POP",location:e,index:t}):s()})}var w={length:d.length,action:"POP",location:d[l],index:l,entries:d,createHref:v,push:function(n,t){var o=C(n,t,h(),w.location);f.confirmTransitionTo(o,"PUSH",r,function(n){if(n){var t=w.index+1,e=w.entries.slice(0);e.length>t?e.splice(t,e.length-t,o):e.push(o),s({action:"PUSH",location:o,index:t,entries:e})}})},replace:function(n,t){var e="REPLACE",o=C(n,t,h(),w.location);f.confirmTransitionTo(o,e,r,function(n){n&&(w.entries[w.index]=o,s({action:e,location:o}))})},go:p,goBack:function(){p(-1)},goForward:function(){p(1)},canGo:function(n){var t=w.index+n;return 0<=t&&t<w.entries.length},block:function(n){return void 0===n&&(n=!1),f.setPrompt(n)},listen:function(n){return f.appendListener(n)}};return w},n.createLocation=C,n.locationsAreEqual=function(n,t){return n.pathname===t.pathname&&n.search===t.search&&n.hash===t.hash&&n.key===t.key&&function e(t,o){if(t===o)return!0;if(null==t||null==o)return!1;if(Array.isArray(t))return Array.isArray(o)&&t.length===o.length&&t.every(function(n,t){return e(n,o[t])});if("object"!=typeof t&&"object"!=typeof o)return!1;var n=i(t),r=i(o);return n!==t||r!==o?e(n,r):Object.keys(Object.assign({},t,o)).every(function(n){return e(t[n],o[n])})}(n.state,t.state)},n.parsePath=a,n.createPath=j,Object.defineProperty(n,"__esModule",{value:!0})}); | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.History={})}(this,function(n){"use strict";function b(){return(b=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r])}return n}).apply(this,arguments)}var m="POP",k="REPLACE",O="beforeunload",x="popstate",H=function(n){n.preventDefault(),n.returnValue=""},S=function(){return Math.random().toString(36).substr(2,8)},w=function(e){return Object.keys(e).reduce(function(n,t){return Object.defineProperty(n,t,{enumerable:!0,value:e[t]})},Object.create(null))},E=function(n){var t=n.pathname,e=void 0===t?"/":t,r=n.search,i=void 0===r?"":r,o=n.hash;return e+i+(void 0===o?"":o)},L=function(n){var t={};if(n){var e=n.indexOf("#");0<=e&&(t.hash=n.substr(e),n=n.substr(0,e));var r=n.indexOf("?");0<=r&&(t.search=n.substr(r),n=n.substr(0,r)),n&&(t.pathname=n)}return t},j=function(){var n=[];return{get length(){return n.length},push:function(t){return n.push(t)&&function(){n=n.filter(function(n){return n!==t})}},call:function(t){n.forEach(function(n){return n&&n(t)})}}},y=function(n,t,e){return Math.min(Math.max(n,t),e)};n.createMemoryHistory=function(n){function o(n,t){return void 0===t&&(t=null),w(b({},v,{},"string"==typeof n?L(n):n,{state:t,key:S()}))}function u(n,t,e){return!d.length||(d.call({action:n,location:t,retry:e}),!1)}function a(n,t){h=n,v=t,p.call({action:h,location:v})}function r(n){var t=y(s+n,0,f.length-1),e=f[t];u("POP",e,function(){r(n)})&&(s=t,a("POP",e))}var t=void 0===n?{}:n,e=t.initialEntries,i=void 0===e?["/"]:e,c=t.initialIndex,l=void 0===c?0:c,f=i.map(function(n){return w(b({pathname:"/",search:"",hash:"",state:null,key:S()},"string"==typeof n?L(n):n))}),s=y(l,0,f.length-1),h=m,v=f[s],d=j(),p=j();return{get action(){return h},get location(){return v},createHref:E,push:function n(t,e){var r=o(t,e);u("PUSH",r,function(){return n(t,e)})&&(s+=1,f.splice(s,f.length,r),a("PUSH",r))},replace:function n(t,e){var r=k,i=o(t,e);u(r,i,function(){return n(t,e)})&&(f[s]=i,a(r,i))},go:r,back:function(){r(-1)},forward:function(){r(1)},listen:function(n){return p.push(n)},block:function(n){return d.push(n)}}},n.createBrowserHistory=function(n){function i(){var n=a.location,t=n.pathname,e=n.search,r=n.hash,i=c.state||{};return[i.idx,w({pathname:t,search:e,hash:r,state:i.usr||null,key:i.key||"default"})]}var t=(void 0===n?{}:n).window,a=void 0===t?document.defaultView:t,c=a.history,o=null;a.addEventListener(x,function(){if(o)f.call(o),o=null;else{var n=i(),t=n[0],e=n[1];if(f.length){if(null!=t){var r=l-t;r&&(o={action:"POP",location:e,retry:function(){g(-1*r)}},g(r))}}else y("POP")}});var e=m,r=i(),l=r[0],u=r[1],f=j(),s=j();null==l&&(l=0,c.replaceState(b({},c.state,{idx:l}),null));function h(n,t){return void 0===t&&(t=null),w(b({},u,{},"string"==typeof n?L(n):n,{state:t,key:S()}))}function v(n,t){return[{usr:n.state,key:n.key,idx:t},p(n)]}function d(n,t,e){return!f.length||(f.call({action:n,location:t,retry:e}),!1)}var p=E,y=function(n){e=n;var t=i();l=t[0],u=t[1],s.call({action:e,location:u})},g=function(n){c.go(n)};return{get action(){return e},get location(){return u},createHref:p,push:function n(t,e){var r=h(t,e);if(d("PUSH",r,function(){return n(t,e)})){var i=v(r,l+1),o=i[0],u=i[1];try{c.pushState(o,null,u)}catch(n){a.location.assign(u)}y("PUSH")}},replace:function n(t,e){var r=k,i=h(t,e);if(d(r,i,function(){return n(t,e)})){var o=v(i,l),u=o[0],a=o[1];c.replaceState(u,null,a),y(r)}},go:g,back:function(){g(-1)},forward:function(){g(1)},listen:function(n){return s.push(n)},block:function(n){var t=f.push(n);return 1===f.length&&a.addEventListener(O,H),function(){t(),f.length||a.removeEventListener(O,H)}}}},n.createHashHistory=function(n){function i(){var n=L(c.location.hash.substr(1)),t=n.pathname,e=void 0===t?"/":t,r=n.search,i=void 0===r?"":r,o=n.hash,u=void 0===o?"":o,a=l.state||{};return[a.idx,w({pathname:e,search:i,hash:u,state:a.usr||null,key:a.key||"default"})]}function e(){if(o)s.call(o),o=null;else{var n=i(),t=n[0],e=n[1];if(s.length){if(null!=t){var r=f-t;r&&(o={action:"POP",location:e,retry:function(){P(-1*r)}},P(r))}}else g("POP")}}var t=(void 0===n?{}:n).window,c=void 0===t?document.defaultView:t,l=c.history,o=null;c.addEventListener(x,e),c.addEventListener("hashchange",function(n){var t=i()[1];E(t)!==E(a)&&e()});var r=m,u=i(),f=u[0],a=u[1],s=j(),h=j();null==f&&(f=0,l.replaceState(b({},l.state,{idx:f}),null));function v(n){var t=document.querySelector("base"),e="";if(t&&t.getAttribute("href")){var r=c.location.href,i=r.indexOf("#");e=-1===i?r:r.slice(0,i)}return e+"#"+E(n)}function d(n,t){return void 0===t&&(t=null),w(b({},a,{},"string"==typeof n?L(n):n,{state:t,key:S()}))}function p(n,t){return[{usr:n.state,key:n.key,idx:t},v(n)]}function y(n,t,e){return!s.length||(s.call({action:n,location:t,retry:e}),!1)}var g=function(n){r=n;var t=i();f=t[0],a=t[1],h.call({action:r,location:a})},P=function(n){l.go(n)};return{get action(){return r},get location(){return a},createHref:v,push:function n(t,e){var r=d(t,e);if(y("PUSH",r,function(){return n(t,e)})){var i=p(r,f+1),o=i[0],u=i[1];try{l.pushState(o,null,u)}catch(n){c.location.assign(u)}g("PUSH")}},replace:function n(t,e){var r=k,i=d(t,e);if(y(r,i,function(){return n(t,e)})){var o=p(i,f),u=o[0],a=o[1];l.replaceState(u,null,a),g(r)}},go:P,back:function(){P(-1)},forward:function(){P(1)},listen:function(n){return h.push(n)},block:function(n){var t=s.push(n);return 1===s.length&&c.addEventListener(O,H),function(){t(),s.length||c.removeEventListener(O,H)}}}},Object.defineProperty(n,"__esModule",{value:!0})}); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
2
8
82958
30
9
1964
1
- Removedresolve-pathname@^3.0.0
- Removedtiny-invariant@^1.0.2
- Removedtiny-warning@^1.0.0
- Removedvalue-equal@^1.0.1
- Removedresolve-pathname@3.0.0(transitive)
- Removedtiny-invariant@1.3.3(transitive)
- Removedtiny-warning@1.0.3(transitive)
- Removedvalue-equal@1.0.1(transitive)