From 14428abb0046f3091e223817ee5379af2c6ea3b6 Mon Sep 17 00:00:00 2001 From: reglim Date: Tue, 4 Apr 2023 14:50:03 +0200 Subject: [PATCH] Improvement: Make deep links work fixes: #479 --- web/src/pages/Docs.tsx | 67 +++++++++++++++++------ web/src/repositories/ProjectRepository.ts | 5 +- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/web/src/pages/Docs.tsx b/web/src/pages/Docs.tsx index f1718a664..ec8710cec 100644 --- a/web/src/pages/Docs.tsx +++ b/web/src/pages/Docs.tsx @@ -5,7 +5,7 @@ */ import React, { useEffect, useRef, useState } from 'react' -import { useParams, useSearchParams } from 'react-router-dom' +import { useLocation, useParams, useSearchParams } from 'react-router-dom' import DocumentControlButtons from '../components/DocumentControlButtons' import ProjectDetails from '../models/ProjectDetails' import ProjectRepository from '../repositories/ProjectRepository' @@ -20,17 +20,19 @@ export default function Docs (): JSX.Element { const projectParam = useParams().project ?? '' const versionParam = useParams().version ?? 'latest' const pageParam = useParams().page ?? 'index.html' + const hashParam = useLocation().hash ?? '' const hideUiParam = useSearchParams()[0].get('hide-ui') === 'true' const [project, setProject] = useState('') const [version, setVersion] = useState('') const [page, setPage] = useState('') + const [hash, setHash] = useState('') const [hideUi, setHideUi] = useState(false) const [versions, setVersions] = useState([]) const [loadingFailed, setLoadingFailed] = useState(false) - const iFrameRef = useRef(null) + const iFrameRef = useRef(null) document.title = `${project} | docat` @@ -38,10 +40,18 @@ export default function Docs (): JSX.Element { setLoadingFailed(true) } - const updateURL = (newProject: string, newVersion: string, newPage: string, newHideUi: boolean): void => { - const url = `#/${newProject}/${newVersion}/${newPage}${newHideUi ? '?hide-ui=true' : ''}` + const updateURL = (newProject: string, newVersion: string, newPage: string, newHash: string, newHideUi: boolean): void => { + let url = `#/${newProject}/${newVersion}/${newPage}` - if (project === newProject && version === newVersion && page === newPage && hideUi === newHideUi) { + if (newHash.length > 0) { + url += newHash + } + + if (newHideUi) { + url += '?hide-ui=true' + } + + if (project === newProject && version === newVersion && page === newPage && hash === newHash && hideUi === newHideUi) { // no change return } @@ -52,6 +62,7 @@ export default function Docs (): JSX.Element { setProject(newProject) setVersion(newVersion) setPage(newPage) + setHash(newHash) setHideUi(newHideUi) if (oldVersion === 'latest' && newVersion !== 'latest') { @@ -69,20 +80,42 @@ export default function Docs (): JSX.Element { window.history.pushState(null, '', url) } - const onIFrameLocationChanged = (url: string): void => { + const onIFrameLocationChanged = (url?: string): void => { + if (url == null) { + return + } + url = url.split('/doc/')[1] - if (url.length === 0) { - // should never happen + if (url == null) { + console.error('IFrame URL did not contain "/doc/"') return } + // make all external links in iframe open in new tab + // and internal links to docat links + // @ts-expect-error - ts does not find the document on the iframe + iFrameRef.current.contentDocument + .querySelectorAll('a') + .forEach((a: HTMLAnchorElement) => { + if (a.href.startsWith(window.location.origin)) { + // internal link, make docat link + a.href = a.href.replace('/doc/', '/#/') + } else { + // external link + a.setAttribute('target', '_blank') + } + }) + const parts = url.split('/') const urlProject = parts[0] const urlVersion = parts[1] - const urlPage = parts.slice(2).join('/') + const urlPageAndHash = parts.slice(2).join('/') + const hashIndex = urlPageAndHash.includes('#') ? urlPageAndHash.indexOf('#') : urlPageAndHash.length + const urlPage = urlPageAndHash.slice(0, hashIndex) + const urlHash = urlPageAndHash.slice(hashIndex) - if (urlProject !== project || urlVersion !== version || urlPage !== page) { - updateURL(urlProject, urlVersion, urlPage, hideUi) + if (urlProject !== project || urlVersion !== version || urlPage !== page || urlHash !== hash) { + updateURL(urlProject, urlVersion, urlPage, urlHash, hideUi) } } @@ -118,7 +151,7 @@ export default function Docs (): JSX.Element { versionToUse = version } - updateURL(project, versionToUse, page, hideUi) + updateURL(project, versionToUse, page, hash, hideUi) setVersions(allVersions) setLoadingFailed(false) } catch (e) { @@ -135,7 +168,7 @@ export default function Docs (): JSX.Element { return p } - updateURL(projectParam, versionParam, pageParam, hideUiParam) + updateURL(projectParam, versionParam, pageParam, hashParam, hideUiParam) return projectParam }) }, []) @@ -153,12 +186,12 @@ export default function Docs (): JSX.Element {