From e76900bed71d500a0c9f095becc770f1ea09f1e6 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 7 Dec 2023 15:21:33 -0500 Subject: [PATCH] It builds but it doesn't work --- src/Main.svelte | 27 ++++----- src/common/Dropdown.svelte | 4 +- src/common/HtmlField.svelte | 9 ++- src/manager/documents.js | 17 +++--- src/manager/layout.js | 21 ++++--- src/manager/orgsAndUsers.js | 60 +++++++++---------- src/pages/NotFound.svelte | 6 +- src/pages/app/App.svelte | 2 +- src/pages/app/SearchBar.svelte | 5 +- src/pages/entities/Entities.svelte | 6 +- src/router/Link.svelte | 54 +++-------------- src/{util => router}/lazyComponent.js | 0 src/router/router.js | 84 ++++++++++++++++++++++----- src/{ => router}/routes.js | 12 ++-- src/search/search.js | 19 +++--- src/util/url.js | 5 +- src/viewer/document.js | 8 +-- src/viewer/layout.js | 48 +++++++-------- src/viewer/viewer.js | 9 +-- 19 files changed, 204 insertions(+), 192 deletions(-) rename src/{util => router}/lazyComponent.js (100%) rename src/{ => router}/routes.js (89%) diff --git a/src/Main.svelte b/src/Main.svelte index cb3fb2595..83e120efb 100644 --- a/src/Main.svelte +++ b/src/Main.svelte @@ -6,40 +6,35 @@ import { isLoading } from "svelte-i18n"; import Empty from "./pages/home/Empty.svelte"; + import NotFound from "./pages/NotFound.svelte"; - import { router } from "./router/router.js"; - import { routes } from "./routes.js"; - import { currentUrl } from "./util/url.js"; + import { currentUrl, resolvedRoute } from "./router/router.js"; + import { getCurrentUrl } from "./util/url.js"; import "./langs/i18n.js"; // Patch poll events import "./ticker/ticker.js"; - // Set up routes - router.notFound = routes[0]; - router.routeFunc = routes[1]; - $: routeComponent = - ($router.resolvedRoute || { component: Empty }).component || Empty; - $: routeProps = ($router.resolvedRoute || { props: [] }).props || {}; + ($resolvedRoute || { component: Empty }).component || Empty; + $: routeProps = ($resolvedRoute || { props: [] }).props || {}; + + $: console.log($resolvedRoute); onMount(() => { - router.currentUrl = currentUrl(); + $currentUrl = getCurrentUrl(); if (!history.state) { window.history.replaceState( - { path: currentUrl() }, + { path: getCurrentUrl() }, "", window.location.href, ); } - - // debug - window.router = router; }); function handleBackNav(e) { if (e.state == null) return; - router.currentUrl = e.state.path; + $currentUrl = e.state.path; } @@ -48,7 +43,7 @@
{#if $isLoading} Please wait... - {:else if $router.resolvedRoute != null} + {:else if $resolvedRoute != null} {/if}
diff --git a/src/common/Dropdown.svelte b/src/common/Dropdown.svelte index 9df667bc6..ab748130e 100644 --- a/src/common/Dropdown.svelte +++ b/src/common/Dropdown.svelte @@ -1,6 +1,6 @@ @@ -70,35 +52,17 @@ {#if !back} {#if newPage} - + {:else} - + {/if} {:else} - + {/if} diff --git a/src/util/lazyComponent.js b/src/router/lazyComponent.js similarity index 100% rename from src/util/lazyComponent.js rename to src/router/lazyComponent.js diff --git a/src/router/router.js b/src/router/router.js index d37206dbe..d556480c1 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -1,13 +1,71 @@ import rlite from "rlite-router"; +import { writable, derived, get } from "svelte/store"; import { Svue } from "svue"; -import Empty from "@/pages/home/Empty.svelte"; // explicit extension for tests -import { lazyComponent } from "@/util/lazyComponent.js"; + +import NotFound from "../pages/NotFound.svelte"; +import { lazyComponent } from "./lazyComponent.js"; +import route from "./routes.js"; const endings = [".html", ".html"]; const FALLBACK_URL = "/app"; -export class Router extends Svue { +// updated in Main.svelte +// export const notFound = writable(NotFound); + +// only referenced in Link component +export const routes = route(lazyComponent); + +// internal +const mapping = Object.entries(routes).reduce((map, [name, route]) => { + if (route.path != null) { + map[route.path] = (props) => { + return { + name, + props, + component: route.component, + get: route.get, + }; + }; + } + return map; +}, {}); + +// internal +const router = rlite(() => ({ component: NotFound }), mapping); + +export const currentUrl = writable(""); +export const backNav = writable(false); + +const pastUrl = writable(""); + +export const resolvedRoute = derived(currentUrl, async ($currentUrl, set) => { + // if ($currentUrl == null) return null; + const resolved = resolve($currentUrl); + if (resolved.component == null && resolved.get != null) { + await Promise.resolve(resolved.get()); + } + set(resolved); +}); + +function lookup(name) { + return routes?.[name]?.path; +} + +function resolve(path) { + // Remove common endings + path = path.split("#")[0]; + for (let i = 0; i < endings.length; i++) { + const ending = endings[i]; + if (path.endsWith(ending)) { + path = path.substr(0, path.length - ending.length); + break; + } + } + return router(path); +} + +class Router extends Svue { constructor(notFound) { super({ data() { @@ -77,10 +135,8 @@ export class Router extends Svue { } } -export const router = new Router(Empty); - export function getPath(to, params = null) { - let path = router.lookup(to); + let path = lookup(to); if (params != null) { for (const param in params) { if (params.hasOwnProperty(param)) { @@ -94,9 +150,9 @@ export function getPath(to, params = null) { export function pushUrl(url) { // change current router path - router.backNav = false; - router.pastUrl = router.currentUrl; - router.currentUrl = url; + backNav.set(false); + pastUrl.set(get(currentUrl)); + currentUrl.set(url); // push the path into web browser history API window.history.pushState( { path: url, dc: true }, @@ -107,7 +163,7 @@ export function pushUrl(url) { // for hash routing in App.svelte and Viewer.svelte export function setHash(hash) { - const url = new URL(router.currentUrl, window.location.href); + const url = new URL(get(currentUrl), window.location.href); url.hash = hash; window.location.hash = hash; @@ -122,7 +178,7 @@ export function setHash(hash) { * @param {Array} keep Keys to preserve */ export function setQS(qs, keep = []) { - const url = new URL(router.currentUrl, window.location.href); + const url = new URL(get(currentUrl), window.location.href); const keys = Array.from(url.searchParams).filter(([k, v]) => keep.includes(k), ); @@ -136,10 +192,10 @@ export function setQS(qs, keep = []) { } export function goBack(fallback = FALLBACK_URL) { - if (router.pastUrl != null) { + if (get(pastUrl) != null) { window.history.back(); } else { - router.currentUrl = fallback; + currentUrl.set(fallback); window.history.replaceState( { path: fallback }, "", @@ -156,5 +212,5 @@ export function nav(to, params = null) { window.addEventListener("popstate", (e) => { const state = e.state || { dc: false }; const isDc = state.dc; - router.backNav = isDc == true; + backNav.set(isDc == true); }); diff --git a/src/routes.js b/src/router/routes.js similarity index 89% rename from src/routes.js rename to src/router/routes.js index 5961be75b..f84996fc8 100644 --- a/src/routes.js +++ b/src/router/routes.js @@ -1,4 +1,3 @@ -import NotFound from "./pages/NotFound.svelte"; import { loadDefault, loadHome, @@ -9,11 +8,10 @@ import { loadProject, loadLegacyRedirect, loadEntities, -} from "./util/lazyComponent.js"; +} from "./lazyComponent.js"; -export const routes = [ - NotFound, - (lazyComponent) => ({ +export default function route(lazyComponent) { + return { default: { path: "/", component: lazyComponent.default, @@ -70,5 +68,5 @@ export const routes = [ component: lazyComponent.legacyRedirect, get: loadLegacyRedirect, }, - }), -]; + }; +} diff --git a/src/search/search.js b/src/search/search.js index 4f6bbbd9f..4b300b70b 100644 --- a/src/search/search.js +++ b/src/search/search.js @@ -1,9 +1,9 @@ import { Svue } from "svue"; -import { router, getPath } from "@/router/router.js"; +import { get } from "svelte/store"; +import { resolvedRoute, getPath, backNav, pushUrl } from "@/router/router.js"; import { wrapSeparate } from "@/util/wrapLoad.js"; import { layout } from "@/manager/layout.js"; import { SearchParams } from "@/structure/searchParams.js"; -import { pushUrl } from "@/router/router.js"; import { queryBuilder } from "@/util/url.js"; import { slugify } from "@/util/string.js"; import { modifications } from "@/manager/modifications.js"; @@ -18,7 +18,7 @@ let lastSearch = null; export const search = new Svue({ data() { return { - router, + resolvedRoute, params: null, results: null, filePickerUser: null, @@ -28,9 +28,6 @@ export const search = new Svue({ }; }, watch: { - "router.resolvedRoute"() { - checkForInit(); - }, filePickerUser() { checkForInit(); }, @@ -40,9 +37,9 @@ export const search = new Svue({ }, }, computed: { - onlyShowSuccessfulStatuses(filePickerUser, router) { + onlyShowSuccessfulStatuses(filePickerUser, resolvedRoute) { // Applies when in embed or dialog - const route = router.resolvedRoute; + const route = resolvedRoute; if (filePickerUser != null) return true; if (route != null && route.name == "project") return true; return false; @@ -125,9 +122,9 @@ export async function searchPrev() { ); } -function checkForInit() { - const route = router.resolvedRoute; +resolvedRoute.subscribe(checkForInit); +function checkForInit(route) { // Prevent repeated searches const searchCache = [ route != null && route.name, @@ -140,7 +137,7 @@ function checkForInit() { if ( route != null && (((route.name == "app" || route.name == "project") && - router.backNav != true) || + get(backNav) != true) || search.filePickerUser != null) ) { initSearch( diff --git a/src/util/url.js b/src/util/url.js index 720b3b10c..9ef945fc4 100644 --- a/src/util/url.js +++ b/src/util/url.js @@ -46,6 +46,7 @@ export function getQueryStringParams(url) { } export function urlsEqual(url1, url2, plusReplace = false) { + if (!url1 || !url2) return false; const [base1, query1] = urlParts(url1); const [base2, query2] = urlParts(url2); @@ -84,7 +85,7 @@ export function urlsEqual(url1, url2, plusReplace = false) { return true; } -export function currentUrl() { +export function getCurrentUrl() { return window.location.pathname + window.location.search; } @@ -95,7 +96,7 @@ export function currentUrl() { * @param {boolean} cleanSlate If true, wipes existing query parameters */ export function queryBuilder(baseUrl, params, cleanSlate = false) { - if (baseUrl == null) baseUrl = currentUrl(); + if (baseUrl == null) baseUrl = getCurrentUrl(); const [url, query] = urlParts(baseUrl); const oldParams = cleanSlate ? {} : getQueryStringParamsFromQuery(query); diff --git a/src/viewer/document.js b/src/viewer/document.js index b2a569966..f4e8b3c3e 100644 --- a/src/viewer/document.js +++ b/src/viewer/document.js @@ -1,7 +1,7 @@ import { Svue } from "svue"; import { viewer } from "./viewer.js"; import { tick } from "svelte"; -import { router } from "@/router/router.js"; +import { resolvedRoute } from "@/router/router.js"; import { layout, annotationValid, @@ -33,7 +33,7 @@ class Doc extends Svue { super({ data() { return { - router, + resolvedRoute, layout: LAYOUT, allDefaultAspects: { image: DEFAULT_IMAGE_ASPECT, @@ -67,8 +67,8 @@ class Doc extends Svue { viewer(viewer) { if (viewer.pageAspects != null) this.initAspects(); }, - "router.resolvedRoute"() { - const route = router.resolvedRoute; + resolvedRoute() { + const route = resolvedRoute; if (route != null && route.name != "viewer") { // Reset mode this.mode = "image"; diff --git a/src/viewer/layout.js b/src/viewer/layout.js index 06ddd5af4..6c2dd73bc 100644 --- a/src/viewer/layout.js +++ b/src/viewer/layout.js @@ -1,4 +1,5 @@ import { Svue } from "svue"; +import { get } from "svelte/store"; import { viewer, updateNote, addNote, removeNote } from "./viewer.js"; import { truthyParamValue, falsyParamValue } from "@/util/url.js"; import { wrapLoad } from "@/util/wrapLoad.js"; @@ -12,7 +13,7 @@ import { import { search } from "@/search/search.js"; import { showConfirm } from "@/manager/confirmDialog.js"; import { markAsDirty, documents } from "@/manager/documents.js"; -import { router } from "@/router/router.js"; +import { resolvedRoute } from "@/router/router.js"; import { createAnnotation, updateAnnotation, @@ -33,7 +34,7 @@ import { export const layout = new Svue({ data() { return { - router, + resolvedRoute, viewer, // Height of header row @@ -102,28 +103,7 @@ export const layout = new Svue({ showInsertDialog: false, }; }, - watch: { - "router.resolvedRoute"() { - const route = router.resolvedRoute; - if (route != null && route.name != "viewer") { - reset(); - } else if (route != null && route.name == "viewer") { - this.embed = inIframe() || truthyParamValue(route.props.embed); - this.title = !this.embed || truthyParamValue(route.props.title); - this.hideTextOption = falsyParamValue(route.props.text); - this.hidePdfLink = falsyParamValue(route.props.pdf); - this.showOrg = truthyParamValue(route.props.onlyshoworg); - this.showFullscreen = !falsyParamValue(route.props.fullscreen); - const sidebarValue = route.props.sidebar; - if (sidebarValue != null) { - this.showSidebar = truthyParamValue(sidebarValue); - } else if (this.embed) { - // Hide sidebar in embed mode by default unless explicitly set - this.showSidebar = false; - } - } - }, - }, + watch: {}, computed: { pollEvents(viewer) { // Update document only if it is readable or pending (processing) @@ -252,6 +232,26 @@ export const layout = new Svue({ }, }); +resolvedRoute.subscribe((route) => { + if (route != null && route.name != "viewer") { + reset(); + } else if (route != null && route.name == "viewer") { + layout.embed = inIframe() || truthyParamValue(route.props.embed); + layout.title = !this.embed || truthyParamValue(route.props.title); + layout.hideTextOption = falsyParamValue(route.props.text); + layout.hidePdfLink = falsyParamValue(route.props.pdf); + layout.showOrg = truthyParamValue(route.props.onlyshoworg); + layout.showFullscreen = !falsyParamValue(route.props.fullscreen); + const sidebarValue = route.props.sidebar; + if (sidebarValue != null) { + layout.showSidebar = truthyParamValue(sidebarValue); + } else if (layout.embed) { + // Hide sidebar in embed mode by default unless explicitly set + layout.showSidebar = false; + } + } +}); + // Loading export function initializeViewer() { layout.viewerInitialized = true; diff --git a/src/viewer/viewer.js b/src/viewer/viewer.js index 898418a18..fe831f557 100644 --- a/src/viewer/viewer.js +++ b/src/viewer/viewer.js @@ -1,7 +1,8 @@ import { Svue } from "svue"; +import { get } from "svelte/store"; import { getDocument } from "@/api/document.js"; import { getMe } from "@/api/orgAndUser.js"; -import { router } from "@/router/router.js"; +import { resolvedRoute } from "@/router/router.js"; import { DEFAULT_EXPAND } from "../api/common.js"; import { inIframe } from "@/util/iframe.js"; import { loadViewerEditDialogs } from "@/pages/viewer/viewerEditDialogs.js"; @@ -26,7 +27,7 @@ let viewerInitCache = {}; export const viewer = new Svue({ data() { return { - router, + resolvedRoute, notes: null, sections: null, document: null, @@ -42,8 +43,8 @@ export const viewer = new Svue({ }; }, watch: { - "router.resolvedRoute"() { - const route = router.resolvedRoute; + resolvedRoute() { + const route = get(resolvedRoute); if (route != null && route.name == "viewer" && route.props != null) { this.id = extractId(route.props.id); if (route.props.embed == "1") {