ilink-world/docs/.docz/.cache/navigation.js

248 lines
7.0 KiB
JavaScript
Raw Normal View History

2020-03-12 15:14:51 +00:00
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 { globalHistory } from "@reach/router/lib/history"
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 })
}
}
const navigate = (to, options = {}) => {
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 ? decodeURI(hash.slice(1)) : [0, 0]
}
}
return true
}
function init() {
// The "scroll-behavior" package expects the "action" to be on the location
// object so let's copy it over.
globalHistory.listen(args => {
args.location.action = args.action
})
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)
}
class RouteAnnouncer extends React.Component {
constructor(props) {
super(props)
this.announcementRef = React.createRef()
}
componentDidUpdate(prevProps, nextProps) {
requestAnimationFrame(() => {
let pageName = `new page at ${this.props.location.pathname}`
if (document.title) {
pageName = document.title
}
const pageHeadings = document
.getElementById(`gatsby-focus-wrapper`)
.getElementsByTagName(`h1`)
if (pageHeadings && pageHeadings.length) {
pageName = pageHeadings[0].textContent
}
const newAnnouncement = `Navigated to ${pageName}`
const oldAnnouncement = this.announcementRef.current.innerText
if (oldAnnouncement !== newAnnouncement) {
this.announcementRef.current.innerText = newAnnouncement
}
})
}
render() {
return (
<div
id="gatsby-announcer"
style={{
position: `absolute`,
top: 0,
width: 1,
height: 1,
padding: 0,
overflow: `hidden`,
clip: `rect(0, 0, 0, 0)`,
whiteSpace: `nowrap`,
border: 0,
}}
aria-live="assertive"
aria-atomic="true"
ref={this.announcementRef}
></div>
)
}
}
// 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 (
<React.Fragment>
{this.props.children}
<RouteAnnouncer location={location} />
</React.Fragment>
)
}
}
RouteUpdates.propTypes = {
location: PropTypes.object.isRequired,
}
export { init, shouldUpdateScroll, RouteUpdates }