antv-l7/.cache/navigation.js

198 lines
5.7 KiB
JavaScript

import React from "react"
import PropTypes from "prop-types"
import loader from "./loader"
import redirects from "./redirects.json"
import { apiRunner } from "./api-runner-browser"
import emitter from "./emitter"
import { navigate as reachNavigate } from "@reach/router"
import { parsePath } from "gatsby-link"
// Convert to a map for faster lookup in maybeRedirect()
const redirectMap = redirects.reduce((map, redirect) => {
map[redirect.fromPath] = redirect
return map
}, {})
function maybeRedirect(pathname) {
const redirect = redirectMap[pathname]
if (redirect != null) {
if (process.env.NODE_ENV !== `production`) {
const pageResources = loader.loadPageSync(pathname)
if (pageResources != null) {
console.error(
`The route "${pathname}" matches both a page and a redirect; this is probably not intentional.`
)
}
}
window.___replace(redirect.toPath)
return true
} else {
return false
}
}
const onPreRouteUpdate = (location, prevLocation) => {
if (!maybeRedirect(location.pathname)) {
apiRunner(`onPreRouteUpdate`, { location, prevLocation })
}
}
const onRouteUpdate = (location, prevLocation) => {
if (!maybeRedirect(location.pathname)) {
apiRunner(`onRouteUpdate`, { location, prevLocation })
// Temp hack while awaiting https://github.com/reach/router/issues/119
window.__navigatingToLink = false
}
}
const navigate = (to, options = {}) => {
// Temp hack while awaiting https://github.com/reach/router/issues/119
if (!options.replace) {
window.__navigatingToLink = true
}
let { pathname } = parsePath(to)
const redirect = redirectMap[pathname]
// If we're redirecting, just replace the passed in pathname
// to the one we want to redirect to.
if (redirect) {
to = redirect.toPath
pathname = parsePath(to).pathname
}
// If we had a service worker update, no matter the path, reload window and
// reset the pathname whitelist
if (window.___swUpdated) {
window.location = pathname
return
}
// Start a timer to wait for a second before transitioning and showing a
// loader in case resources aren't around yet.
const timeoutId = setTimeout(() => {
emitter.emit(`onDelayedLoadPageResources`, { pathname })
apiRunner(`onRouteUpdateDelayed`, {
location: window.location,
})
}, 1000)
loader.loadPage(pathname).then(pageResources => {
// If no page resources, then refresh the page
// Do this, rather than simply `window.location.reload()`, so that
// pressing the back/forward buttons work - otherwise when pressing
// back, the browser will just change the URL and expect JS to handle
// the change, which won't always work since it might not be a Gatsby
// page.
if (!pageResources || pageResources.status === `error`) {
window.history.replaceState({}, ``, location.href)
window.location = pathname
}
// If the loaded page has a different compilation hash to the
// window, then a rebuild has occurred on the server. Reload.
if (process.env.NODE_ENV === `production` && pageResources) {
if (
pageResources.page.webpackCompilationHash !==
window.___webpackCompilationHash
) {
// Purge plugin-offline cache
if (
`serviceWorker` in navigator &&
navigator.serviceWorker.controller !== null &&
navigator.serviceWorker.controller.state === `activated`
) {
navigator.serviceWorker.controller.postMessage({
gatsbyApi: `clearPathResources`,
})
}
console.log(`Site has changed on server. Reloading browser`)
window.location = pathname
}
}
reachNavigate(to, options)
clearTimeout(timeoutId)
})
}
function shouldUpdateScroll(prevRouterProps, { location }) {
const { pathname, hash } = location
const results = apiRunner(`shouldUpdateScroll`, {
prevRouterProps,
// `pathname` for backwards compatibility
pathname,
routerProps: { location },
getSavedScrollPosition: args => this._stateStorage.read(args),
})
if (results.length > 0) {
// Use the latest registered shouldUpdateScroll result, this allows users to override plugin's configuration
// @see https://github.com/gatsbyjs/gatsby/issues/12038
return results[results.length - 1]
}
if (prevRouterProps) {
const {
location: { pathname: oldPathname },
} = prevRouterProps
if (oldPathname === pathname) {
// Scroll to element if it exists, if it doesn't, or no hash is provided,
// scroll to top.
return hash ? hash.slice(1) : [0, 0]
}
}
return true
}
function init() {
// Temp hack while awaiting https://github.com/reach/router/issues/119
window.__navigatingToLink = false
window.___push = to => navigate(to, { replace: false })
window.___replace = to => navigate(to, { replace: true })
window.___navigate = (to, options) => navigate(to, options)
// Check for initial page-load redirect
maybeRedirect(window.location.pathname)
}
// Fire on(Pre)RouteUpdate APIs
class RouteUpdates extends React.Component {
constructor(props) {
super(props)
onPreRouteUpdate(props.location, null)
}
componentDidMount() {
onRouteUpdate(this.props.location, null)
}
componentDidUpdate(prevProps, prevState, shouldFireRouteUpdate) {
if (shouldFireRouteUpdate) {
onRouteUpdate(this.props.location, prevProps.location)
}
}
getSnapshotBeforeUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
onPreRouteUpdate(this.props.location, prevProps.location)
return true
}
return false
}
render() {
return this.props.children
}
}
RouteUpdates.propTypes = {
location: PropTypes.object.isRequired,
}
export { init, shouldUpdateScroll, RouteUpdates }