123 lines
2.8 KiB
JavaScript
123 lines
2.8 KiB
JavaScript
import regexparam from "regexparam"
|
|
import appStore from "../state/store"
|
|
import { getAppId } from "@budibase/component-sdk"
|
|
|
|
export const screenRouter = ({ screens, onScreenSelected, window }) => {
|
|
function sanitize(url) {
|
|
if (!url) return url
|
|
return url
|
|
.split("/")
|
|
.map(part => {
|
|
// if parameter, then use as is
|
|
if (part.startsWith(":")) return part
|
|
return encodeURIComponent(part)
|
|
})
|
|
.join("/")
|
|
.toLowerCase()
|
|
}
|
|
|
|
const isRunningLocally = () => {
|
|
const hostname = (window.location && window.location.hostname) || ""
|
|
return (
|
|
hostname === "localhost" ||
|
|
hostname === "127.0.0.1" ||
|
|
hostname.startsWith("192.168")
|
|
)
|
|
}
|
|
|
|
const makeRootedPath = url => {
|
|
if (isRunningLocally()) {
|
|
const appId = getAppId()
|
|
if (url) {
|
|
url = sanitize(url)
|
|
if (!url.startsWith("/")) {
|
|
url = `/${url}`
|
|
}
|
|
if (url.startsWith(`/${appId}`)) {
|
|
return url
|
|
}
|
|
return `/${appId}${url}`
|
|
}
|
|
return `/${appId}`
|
|
}
|
|
return sanitize(url)
|
|
}
|
|
|
|
const routes = screens.map(s => makeRootedPath(s.routing?.route))
|
|
let fallback = routes.findIndex(([p]) => p === makeRootedPath("*"))
|
|
if (fallback < 0) fallback = 0
|
|
|
|
let current
|
|
|
|
function route(url) {
|
|
const _url = makeRootedPath(url.state || url)
|
|
current = routes.findIndex(
|
|
p =>
|
|
p !== makeRootedPath("*") &&
|
|
new RegExp("^" + p.toLowerCase() + "$").test(_url.toLowerCase())
|
|
)
|
|
|
|
const params = {}
|
|
|
|
if (current === -1) {
|
|
routes.forEach((p, i) => {
|
|
// ignore home - which matched everything
|
|
if (p === makeRootedPath("*")) return
|
|
const pm = regexparam(p)
|
|
const matches = pm.pattern.exec(_url)
|
|
|
|
if (!matches) return
|
|
|
|
let j = 0
|
|
while (j < pm.keys.length) {
|
|
params[pm.keys[j]] = matches[++j] || null
|
|
}
|
|
|
|
current = i
|
|
})
|
|
}
|
|
|
|
appStore.update(state => {
|
|
state["##routeParams"] = params
|
|
return state
|
|
})
|
|
|
|
const screenIndex = current !== -1 ? current : fallback
|
|
|
|
try {
|
|
!url.state && history.pushState(_url, null, _url)
|
|
} catch (_) {
|
|
// ignoring an exception here as the builder runs an iframe, which does not like this
|
|
}
|
|
|
|
onScreenSelected(screens[screenIndex], _url)
|
|
}
|
|
|
|
function click(e) {
|
|
const x = e.target.closest("a")
|
|
const y = x && x.getAttribute("href")
|
|
|
|
if (
|
|
e.ctrlKey ||
|
|
e.metaKey ||
|
|
e.altKey ||
|
|
e.shiftKey ||
|
|
e.button ||
|
|
e.defaultPrevented
|
|
)
|
|
return
|
|
|
|
const target = (x && x.target) || "_self"
|
|
if (!y || target !== "_self" || x.host !== location.host) return
|
|
|
|
e.preventDefault()
|
|
route(y)
|
|
}
|
|
|
|
addEventListener("popstate", route)
|
|
addEventListener("pushstate", route)
|
|
addEventListener("click", click)
|
|
|
|
return route
|
|
}
|