From 6b601794404ebac887a3ad3fe4ed38ca709ea19f Mon Sep 17 00:00:00 2001 From: Michael Gartner Date: Fri, 27 Dec 2024 01:25:53 -0600 Subject: [PATCH] move pageRefObs from discourseGraphMode --- apps/roam/src/discourseGraphsMode.ts | 93 ++-------------- apps/roam/src/index.ts | 34 +++--- apps/roam/src/utils/isCanvasPage.ts | 13 +++ .../src/utils/isDiscourseNodeConfigPage.ts | 4 + .../roam/src/utils/pageRefObserverHandlers.ts | 101 ++++++++++++++++++ 5 files changed, 144 insertions(+), 101 deletions(-) create mode 100644 apps/roam/src/utils/isDiscourseNodeConfigPage.ts create mode 100644 apps/roam/src/utils/pageRefObserverHandlers.ts diff --git a/apps/roam/src/discourseGraphsMode.ts b/apps/roam/src/discourseGraphsMode.ts index e02cba179..0b3e1e792 100644 --- a/apps/roam/src/discourseGraphsMode.ts +++ b/apps/roam/src/discourseGraphsMode.ts @@ -22,8 +22,6 @@ import refreshConfigTree from "./utils/refreshConfigTree"; import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid"; import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree"; import { render } from "./components/DiscourseNodeMenu"; -import { render as discourseOverlayRender } from "./components/DiscourseContextOverlay"; -import { render as previewRender } from "./components/LivePreview"; import { render as renderReferenceContext } from "./components/ReferenceContext"; import DiscourseContext from "./components/DiscourseContext"; import createHTMLObserver from "roamjs-components/dom/createHTMLObserver"; @@ -45,56 +43,11 @@ import { Condition, QBClause } from "./utils/types"; import styles from "./styles/discourseGraphStyles.css"; import { DISCOURSE_CONFIG_PAGE_TITLE } from "./settings/configPages"; import { formatHexColor } from "./components/settings/DiscourseNodeCanvasSettings"; - -export const SETTING = "discourse-graphs"; - -// TODO POST MIGRATE - move this logic within the toggle -const pageRefObservers = new Set<(s: HTMLSpanElement) => void>(); -const pageRefObserverRef: { current?: MutationObserver } = { - current: undefined, -}; -const enablePageRefObserver = () => - (pageRefObserverRef.current = createHTMLObserver({ - useBody: true, - tag: "SPAN", - className: "rm-page-ref", - callback: (s: HTMLSpanElement) => { - pageRefObservers.forEach((f) => f(s)); - }, - })); -const disablePageRefObserver = () => { - pageRefObserverRef.current?.disconnect(); - pageRefObserverRef.current = undefined; -}; -const onPageRefObserverChange = - (handler: (s: HTMLSpanElement) => void) => (b: boolean) => { - if (b) { - if (!pageRefObservers.size) enablePageRefObserver(); - pageRefObservers.add(handler); - } else { - pageRefObservers.delete(handler); - if (!pageRefObservers.size) disablePageRefObserver(); - } - }; - -const previewPageRefHandler = (s: HTMLSpanElement) => { - const tag = - s.getAttribute("data-tag") || - s.parentElement?.getAttribute("data-link-title"); - if (tag && !s.getAttribute("data-roamjs-discourse-augment-tag")) { - s.setAttribute("data-roamjs-discourse-augment-tag", "true"); - const parent = document.createElement("span"); - previewRender({ - parent, - tag, - registerMouseEvents: ({ open, close }) => { - s.addEventListener("mouseenter", (e) => open(e.ctrlKey)); - s.addEventListener("mouseleave", close); - }, - }); - s.appendChild(parent); - } -}; +import { + onPageRefObserverChange, + overlayPageRefHandler, + previewPageRefHandler, +} from "./utils/pageRefObserverHandlers"; export const getPlainTitleFromSpecification = ({ specification, @@ -136,32 +89,6 @@ const initializeDiscourseGraphsMode = async (args: OnloadArgs) => { unloads.delete(removeStyle); }); - const overlayPageRefHandler = (s: HTMLSpanElement) => { - if (s.parentElement && !s.parentElement.closest(".rm-page-ref")) { - const tag = - s.getAttribute("data-tag") || - s.parentElement.getAttribute("data-link-title"); - if ( - tag && - !s.getAttribute("data-roamjs-discourse-overlay") && - isDiscourseNode(getPageUidByPageTitle(tag)) - ) { - s.setAttribute("data-roamjs-discourse-overlay", "true"); - const parent = document.createElement("span"); - discourseOverlayRender({ - parent, - tag: tag.replace(/\\"/g, '"'), - onloadArgs: args, - }); - if (s.hasAttribute("data-tag")) { - s.appendChild(parent); - } else { - s.parentElement.appendChild(parent); - } - } - } - }; - const { pageUid, observer } = await createConfigObserver({ title: DISCOURSE_CONFIG_PAGE_TITLE, config: { @@ -228,7 +155,9 @@ const initializeDiscourseGraphsMode = async (args: OnloadArgs) => { disabled: true, options: { onChange: (val) => { - onPageRefObserverChange(overlayPageRefHandler)(val); + onPageRefObserverChange((s) => + overlayPageRefHandler(s, args), + )(val); }, }, } as Field, @@ -474,12 +403,6 @@ const initializeDiscourseGraphsMode = async (args: OnloadArgs) => { unloads.delete(removeObservers); }); - if (isFlagEnabled("preview")) pageRefObservers.add(previewPageRefHandler); - // if (isFlagEnabled("grammar.overlay")) { - // pageRefObservers.add(overlayPageRefHandler); - // } - if (pageRefObservers.size) enablePageRefObserver(); - const queryPages = args.extensionAPI.settings.get("query-pages"); const queryPageArray = Array.isArray(queryPages) ? queryPages diff --git a/apps/roam/src/index.ts b/apps/roam/src/index.ts index 913275817..ccf4a12cb 100644 --- a/apps/roam/src/index.ts +++ b/apps/roam/src/index.ts @@ -11,6 +11,7 @@ import { runExtension } from "roamjs-components/util"; import { renderTldrawCanvas } from "./components/canvas/Tldraw"; import { renderQueryPage, renderQueryBlock } from "./components/QueryBuilder"; +import { QueryBuilderLoadedToast } from "./components/toastMessages"; import runQuery from "./utils/runQuery"; import isDiscourseNode from "./utils/isDiscourseNode"; @@ -25,12 +26,20 @@ import { registerCommandPaletteCommands } from "./settings/commandPalette"; import { createSettingsPanel } from "./settings/settingsPanel"; import { renderNodeConfigPage } from "./settings/configPages"; -import { isCanvasPage as checkIfCanvasPage } from "./utils/isCanvasPage"; +import { isCurrentPageCanvas as isCanvasPage } from "./utils/isCanvasPage"; +import { isDiscourseNodeConfigPage as isNodeConfigPage } from "./utils/isDiscourseNodeConfigPage"; import { isQueryPage } from "./utils/isQueryPage"; import { listActiveQueries } from "./utils/listActiveQueries"; import { registerSmartBlock } from "./utils/registerSmartBlock"; +import isFlagEnabled from "./utils/isFlagEnabled"; -import { QueryBuilderLoadedToast } from "./components/toastMessages"; +import { + enablePageRefObserver, + addPageRefObserver, + getPageRefObserversSize, + previewPageRefHandler, + overlayPageRefHandler, +} from "./utils/pageRefObserverHandlers"; export const DEFAULT_CANVAS_PAGE_FORMAT = "Canvas/*"; @@ -61,17 +70,6 @@ export default runExtension(async (onloadArgs) => { await initializeDiscourseGraphsMode(onloadArgs); // Observers and Listeners - const isDiscourseNodePage = (title: string) => - title.startsWith("discourse-graph/nodes/"); - const isCanvasPage = ({ - title, - h1, - }: { - title: string; - h1: HTMLHeadingElement; - }) => - checkIfCanvasPage({ title, extensionAPI }) && !!h1.closest(".roam-article"); - const pageTitleObserver = createHTMLObserver({ tag: "H1", className: "rm-title-display", @@ -80,7 +78,7 @@ export default runExtension(async (onloadArgs) => { const title = getPageTitleValueByHtmlElement(h1); const props = { title, h1, onloadArgs }; - if (isDiscourseNodePage(title)) renderNodeConfigPage(props); + if (isNodeConfigPage(title)) renderNodeConfigPage(props); else if (isQueryPage(props)) renderQueryPage(props); else if (isCanvasPage(props)) renderTldrawCanvas(props); }, @@ -113,7 +111,11 @@ export default runExtension(async (onloadArgs) => { }) as EventListener; document.addEventListener("roamjs:query-builder:action", pageActionListener); - registerSmartBlock(extensionAPI); + if (isFlagEnabled("preview")) addPageRefObserver(previewPageRefHandler); + if (isFlagEnabled("grammar.overlay")) { + addPageRefObserver((s) => overlayPageRefHandler(s, onloadArgs)); + } + if (!!getPageRefObserversSize()) enablePageRefObserver(); // Window // @ts-ignore @@ -130,9 +132,9 @@ export default runExtension(async (onloadArgs) => { isDiscourseNode: isDiscourseNode, }; - // Command Palette and Roam Settings registerCommandPaletteCommands(onloadArgs); createSettingsPanel(onloadArgs); + registerSmartBlock(extensionAPI); return { elements: [style, settingsStyle], diff --git a/apps/roam/src/utils/isCanvasPage.ts b/apps/roam/src/utils/isCanvasPage.ts index 655e7cbfc..a8bec619b 100644 --- a/apps/roam/src/utils/isCanvasPage.ts +++ b/apps/roam/src/utils/isCanvasPage.ts @@ -13,3 +13,16 @@ export const isCanvasPage = ({ const canvasRegex = new RegExp(`^${format}$`.replace(/\*/g, ".+")); return canvasRegex.test(title); }; + +export const isCurrentPageCanvas = ({ + title, + h1, + onloadArgs, +}: { + title: string; + h1: HTMLHeadingElement; + onloadArgs: OnloadArgs; +}) => { + const { extensionAPI } = onloadArgs; + return isCanvasPage({ title, extensionAPI }) && !!h1.closest(".roam-article"); +}; diff --git a/apps/roam/src/utils/isDiscourseNodeConfigPage.ts b/apps/roam/src/utils/isDiscourseNodeConfigPage.ts new file mode 100644 index 000000000..efaeaee71 --- /dev/null +++ b/apps/roam/src/utils/isDiscourseNodeConfigPage.ts @@ -0,0 +1,4 @@ +import { NODE_CONFIG_PAGE_TITLE } from "~/settings/configPages"; + +export const isDiscourseNodeConfigPage = (title: string) => + title.startsWith(NODE_CONFIG_PAGE_TITLE); diff --git a/apps/roam/src/utils/pageRefObserverHandlers.ts b/apps/roam/src/utils/pageRefObserverHandlers.ts new file mode 100644 index 000000000..6c5576785 --- /dev/null +++ b/apps/roam/src/utils/pageRefObserverHandlers.ts @@ -0,0 +1,101 @@ +import { createHTMLObserver } from "roamjs-components/dom"; +import { render as previewRender } from "../components/LivePreview"; +import isDiscourseNode from "./isDiscourseNode"; +import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle"; +import { render as discourseOverlayRender } from "../components/DiscourseContextOverlay"; +import { OnloadArgs } from "roamjs-components/types"; + +const pageRefObservers = new Set<(s: HTMLSpanElement) => void>(); +const pageRefObserverRef: { current?: MutationObserver } = { + current: undefined, +}; + +export const overlayPageRefHandler = (s: HTMLSpanElement, args: OnloadArgs) => { + if (s.parentElement && !s.parentElement.closest(".rm-page-ref")) { + const tag = + s.getAttribute("data-tag") || + s.parentElement.getAttribute("data-link-title"); + if ( + tag && + !s.getAttribute("data-roamjs-discourse-overlay") && + isDiscourseNode(getPageUidByPageTitle(tag)) + ) { + s.setAttribute("data-roamjs-discourse-overlay", "true"); + const parent = document.createElement("span"); + discourseOverlayRender({ + parent, + tag: tag.replace(/\\"/g, '"'), + onloadArgs: args, + }); + if (s.hasAttribute("data-tag")) { + s.appendChild(parent); + } else { + s.parentElement.appendChild(parent); + } + } + } +}; + +export const previewPageRefHandler = (s: HTMLSpanElement) => { + const tag = + s.getAttribute("data-tag") || + s.parentElement?.getAttribute("data-link-title"); + if (tag && !s.getAttribute("data-roamjs-discourse-augment-tag")) { + s.setAttribute("data-roamjs-discourse-augment-tag", "true"); + const parent = document.createElement("span"); + previewRender({ + parent, + tag, + registerMouseEvents: ({ open, close }) => { + s.addEventListener("mouseenter", (e) => open(e.ctrlKey)); + s.addEventListener("mouseleave", close); + }, + }); + s.appendChild(parent); + } +}; + +export const enablePageRefObserver = () => + (pageRefObserverRef.current = createHTMLObserver({ + useBody: true, + tag: "SPAN", + className: "rm-page-ref", + callback: (s: HTMLSpanElement) => { + pageRefObservers.forEach((f) => f(s)); + }, + })); + +const disablePageRefObserver = () => { + pageRefObserverRef.current?.disconnect(); + pageRefObserverRef.current = undefined; +}; + +export const onPageRefObserverChange = + (handler: (s: HTMLSpanElement) => void) => (b: boolean) => { + if (b) { + if (!pageRefObservers.size) enablePageRefObserver(); + pageRefObservers.add(handler); + } else { + pageRefObservers.delete(handler); + if (!pageRefObservers.size) disablePageRefObserver(); + } + }; + +export const addPageRefObserver = (handler: (s: HTMLSpanElement) => void) => { + pageRefObservers.add(handler); + if (pageRefObservers.size === 1) enablePageRefObserver(); +}; + +export const removePageRefObserver = ( + handler: (s: HTMLSpanElement) => void, +) => { + pageRefObservers.delete(handler); + if (pageRefObservers.size === 0) disablePageRefObserver(); +}; + +export const clearPageRefObservers = () => { + disablePageRefObserver(); + pageRefObservers.clear(); +}; + +export const getPageRefObserversSize = () => pageRefObservers.size;