From e72c191cabe5d70bf7ced38aab06205beac64d6d Mon Sep 17 00:00:00 2001 From: Michael Gartner Date: Tue, 8 Jul 2025 16:41:49 -0600 Subject: [PATCH 1/2] Remove Sortable Linked References documentation and related functionality - Deleted the Sortable Linked References documentation from README.md and removed the associated runSortReferences utility. - Updated settings in index.ts to eliminate references to sorting linked references. --- README.md | 1 - docs/sortable-linked-refs.md | 18 -- src/index.ts | 18 +- src/utils/runSortReferences.ts | 360 --------------------------------- 4 files changed, 2 insertions(+), 395 deletions(-) delete mode 100644 docs/sortable-linked-refs.md delete mode 100644 src/utils/runSortReferences.ts diff --git a/README.md b/README.md index 31b2a3e7..2e065758 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ For more information, check out our docs at [https://github.com/RoamJS/query-bui - [Randomization](https://github.com/RoamJS/query-builder/blob/main/docs/roam-queries.md#randomization) - [Context](https://github.com/RoamJS/query-builder/blob/main/docs/roam-queries.md#context) - [Aliases](https://github.com/RoamJS/query-builder/blob/main/docs/roam-queries.md#aliases) -- [Sortable Linked References](https://github.com/RoamJS/query-builder/blob/main/docs/sortable-linked-refs.md) ## Nomenclature diff --git a/docs/sortable-linked-refs.md b/docs/sortable-linked-refs.md deleted file mode 100644 index ab720541..00000000 --- a/docs/sortable-linked-refs.md +++ /dev/null @@ -1,18 +0,0 @@ -# Sortable Linked References - -In your Roam Depot Settings, there is a flag called `Sortable Linked References`. When enabled, there will appear a sort icon next to the filter icon near the linked references. Clicking on the sort icon will make a sort menu visible to the user. - -![](https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2Froamjs%2FrH9xJYbsTn.png?alt=media&token=863e38d5-03bd-4b33-95fe-a62254d271dd) - -You could also add a `Default Sort` attribute with a valid value on the page itself to have a specific sorting for just that page. - -Here are the options you can sort by: - -| Option | Description | -| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| Sort By Created Date | This will sort all the linked references in ascending order that the page was created. | -| Sort By Created Date Descending | This will sort all the linked references in descending order that the page was created. | -| Sort By Daily Note | This will sort all the linked references in ascending order by Daily Note, followed by created date of non-daily note pages. | -| Sort By Daily Note Descending | This will sort all the linked references in descending order by Daily Note, followed by created date of non-daily note pages. | -| Sort By Page Title | This will sort all the linked references in ascending alphabetical order of the page title. | -| Sort By Page Title Descending | This will sort all the linked references in descending alphabetical order of the page title. | diff --git a/src/index.ts b/src/index.ts index 1add43b3..41f7db42 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,7 @@ import extractRef from "roamjs-components/util/extractRef"; import type { InputTextNode, PullBlock } from "roamjs-components/types/native"; import QueryPagesPanel, { getQueryPages } from "./components/QueryPagesPanel"; import runQuery from "./utils/runQuery"; -import runSortReferences from "./utils/runSortReferences"; + import updateBlock from "roamjs-components/writes/updateBlock"; import getChildrenLengthByPageUid from "roamjs-components/queries/getChildrenLengthByPageUid"; import createBlock from "roamjs-components/writes/createBlock"; @@ -339,16 +339,7 @@ svg.rs-svg-container { description: "The default sorting all native queries in your graph should use", }, - { - id: "sort-references", - name: "Sortable Linked References", - action: { - type: "switch", - onChange: (e) => toggleSortReferences(e.target.checked), - }, - description: - "Whether or not to enable sorting on the linked references section", - }, + { id: "show-page-metadata", name: "Show Page Metadata", @@ -424,11 +415,6 @@ svg.rs-svg-container { toggleDiscourseGraphsMode(true); } - const toggleSortReferences = runSortReferences(); - if (!!extensionAPI.settings.get("sort-references")) { - toggleSortReferences(true); - } - const globalRefs: QBGlobalRefs = { clearOnClick: ({ parentUid, text }) => { const order = getChildrenLengthByPageUid(parentUid); diff --git a/src/utils/runSortReferences.ts b/src/utils/runSortReferences.ts deleted file mode 100644 index e1ea679c..00000000 --- a/src/utils/runSortReferences.ts +++ /dev/null @@ -1,360 +0,0 @@ -import getFullTreeByParentUid from "roamjs-components/queries/getFullTreeByParentUid"; -import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle"; -import getPageTitleValueByHtmlElement from "roamjs-components/dom/getPageTitleValueByHtmlElement"; -import getPageTitlesReferencingBlockUid from "roamjs-components/queries/getPageTitlesReferencingBlockUid"; -import createOverlayObserver from "roamjs-components/dom/createOverlayObserver"; -import createIconButton from "roamjs-components/dom/createIconButton"; - -const POPOVER_WRAPPER_CLASS = "sort-popover-wrapper"; - -export const createSortIcon = ( - refContainer: HTMLDivElement, - sortCallbacks: { [key: string]: (refContainer: Element) => () => void } -): HTMLSpanElement => { - // Icon Button - const popoverWrapper = document.createElement("span"); - popoverWrapper.className = `bp3-popover-wrapper ${POPOVER_WRAPPER_CLASS} roamjs-sort-icon`; - - const popoverTarget = document.createElement("span"); - popoverTarget.className = "bp3-popover-target"; - popoverWrapper.appendChild(popoverTarget); - - const popoverButton = createIconButton("sort"); - popoverTarget.appendChild(popoverButton); - - // Overlay Content - const popoverOverlay = document.createElement("div"); - popoverOverlay.className = "bp3-overlay bp3-overlay-inline"; - popoverWrapper.appendChild(popoverOverlay); - - const transitionContainer = document.createElement("div"); - transitionContainer.className = - "bp3-transition-container bp3-popover-enter-done"; - transitionContainer.style.position = "absolute"; - transitionContainer.style.willChange = "transform"; - transitionContainer.style.top = "0"; - transitionContainer.style.left = "0"; - - const popover = document.createElement("div"); - popover.className = "bp3-popover"; - popover.style.transformOrigin = "162px top"; - transitionContainer.appendChild(popover); - - const popoverContent = document.createElement("div"); - popoverContent.className = "bp3-popover-content"; - popover.appendChild(popoverContent); - - const menuUl = document.createElement("ul"); - menuUl.className = "bp3-menu"; - popoverContent.appendChild(menuUl); - - let selectedMenuItem: HTMLAnchorElement; - const createMenuItem = (text: string, sortCallback: () => void) => { - const liItem = document.createElement("li"); - const aMenuItem = document.createElement("a"); - aMenuItem.className = "bp3-menu-item bp3-popover-dismiss"; - liItem.appendChild(aMenuItem); - const menuItemText = document.createElement("div"); - menuItemText.className = "bp3-text-overflow-ellipsis bp3-fill"; - menuItemText.innerText = text; - aMenuItem.appendChild(menuItemText); - menuUl.appendChild(liItem); - aMenuItem.onclick = (e) => { - sortCallback(); - aMenuItem.style.fontWeight = "600"; - if (selectedMenuItem) { - selectedMenuItem.style.fontWeight = ""; - } - selectedMenuItem = aMenuItem; - e.stopImmediatePropagation(); - e.preventDefault(); - }; - aMenuItem.onmousedown = (e) => { - e.stopImmediatePropagation(); - e.preventDefault(); - }; - }; - Object.keys(sortCallbacks).forEach((k: keyof typeof sortCallbacks) => - createMenuItem(`Sort By ${k}`, sortCallbacks[k](refContainer)) - ); - - let popoverOpen = false; - const documentEventListener = (e: MouseEvent) => { - if ( - (!e.target || !popoverOverlay.contains(e.target as HTMLElement)) && - popoverOpen - ) { - closePopover(); - } - }; - - const closePopover = () => { - popoverOverlay.className = "bp3-overlay bp3-overlay-inline"; - popoverOverlay.removeChild(transitionContainer); - document.removeEventListener("click", documentEventListener); - popoverOpen = false; - }; - - popoverButton.onmousedown = (e) => { - e.stopImmediatePropagation(); - e.preventDefault(); - }; - - popoverButton.onclick = (e) => { - if (!popoverOpen) { - transitionContainer.style.transform = `translate3d(${ - popoverButton.offsetLeft <= 240 - ? popoverButton.offsetLeft - : popoverButton.offsetLeft - 240 - }px, ${popoverButton.offsetTop + 24}px, 0px)`; - popoverOverlay.className = - "bp3-overlay bp3-overlay-open bp3-overlay-inline"; - popoverOverlay.appendChild(transitionContainer); - e.stopImmediatePropagation(); - e.preventDefault(); - document.addEventListener("click", documentEventListener); - popoverOpen = true; - } else { - closePopover(); - } - }; - return popoverWrapper; -}; - -// This API is terrible and should be redesigned -const createSortIcons = ( - containerClass: string, - callback: (container: HTMLDivElement) => void, - sortCallbacks: { [key: string]: (refContainer: Element) => () => void }, - childIndex?: number, - shouldCreate?: (container: HTMLDivElement) => boolean -): void => { - const sortButtonContainers = Array.from( - document.getElementsByClassName(containerClass) - ) as HTMLDivElement[]; - sortButtonContainers.forEach((sortButtonContainer) => { - const exists = - sortButtonContainer.getElementsByClassName(POPOVER_WRAPPER_CLASS).length > - 0; - if (exists) { - return; - } - - if (shouldCreate && !shouldCreate(sortButtonContainer)) { - return; - } - - const popoverWrapper = createSortIcon(sortButtonContainer, sortCallbacks); - if (childIndex) { - const before = sortButtonContainer.children[childIndex]; - sortButtonContainer.insertBefore(popoverWrapper, before); - } else { - sortButtonContainer.appendChild(popoverWrapper); - } - - callback(sortButtonContainer); - }); -}; - -const runSortReferences = () => { - const unloads = new Set<() => void>(); - return (flag: boolean) => { - if (flag) { - const config = Object.fromEntries( - getFullTreeByParentUid(getPageUidByPageTitle("roam/js/sort-references")) - .children.map((c) => c.text.split("::")) - .filter((c) => c.length === 2) - ); - const getAttribute = (attr: string) => { - const page = - document.getElementsByClassName("rm-title-display")[0]?.textContent || - ""; - const node = - getFullTreeByParentUid(getPageUidByPageTitle(page)).children.find( - (t) => new RegExp(`${attr}::`, "i").test(t.text) - )?.text || ""; - return node.substring(attr.length + 2).trim(); - }; - - const menuItemCallback = async ( - sortContainer: Element, - sortBy: ( - a: { title: string; time: number }, - b: { title: string; time: number } - ) => number - ) => { - const sidebarWindow = sortContainer.closest(".rm-sidebar-window"); - const currentPageUID = - await window.roamAlphaAPI.ui.mainWindow.getOpenPageOrBlockUid(); - const allSidebarWindows = - document.body.querySelectorAll(".rm-sidebar-window"); - const sidebarWindowIndex = sidebarWindow - ? Array.from(allSidebarWindows).indexOf(sidebarWindow) - : -1; - const sidebarWindowData = - window.roamAlphaAPI.ui.rightSidebar.getWindows()[sidebarWindowIndex]; - const pageUID = !!sidebarWindow - ? // @ts-ignore Roam has an API inconsistency - https://roamresearch.slack.com/archives/C02TMKXNVS6/p1676389252784269 - sidebarWindowData["page-uid"] || sidebarWindowData["mentions-uid"] - : !currentPageUID - ? getPageUidByPageTitle(getPageTitleValueByHtmlElement(sortContainer)) - : currentPageUID; - if (!pageUID) { - return; - } - const linkedReferences = getPageTitlesReferencingBlockUid(pageUID).map( - (title) => ({ - title, - time: - window.roamAlphaAPI.pull("[:create/time]", [ - ":node/title", - title, - ])?.[":create/time"] || 0, - }) - ); - linkedReferences.sort(sortBy); - const refIndexByTitle: { [key: string]: number } = {}; - linkedReferences.forEach((v, i) => (refIndexByTitle[v.title] = i)); - const getRefIndexByTitle = (title: string) => { - if (!isNaN(refIndexByTitle[title])) { - return refIndexByTitle[title]; - } - const len = Object.keys(refIndexByTitle).length; - refIndexByTitle[title] = len; - return len; - }; - - const refContainer = sortContainer.parentElement - ?.closest(".rm-reference-container") - ?.getElementsByClassName("refs-by-page-view")?.[0]; - const refsInView = Array.from(refContainer?.children || []); - refsInView.forEach((r) => refContainer?.removeChild(r)); - refsInView.sort((a, b) => { - const aTitle = a.getElementsByClassName( - "rm-ref-page-view-title" - )?.[0] as HTMLDivElement; - const bTitle = b.getElementsByClassName( - "rm-ref-page-view-title" - )?.[0] as HTMLDivElement; - return ( - getRefIndexByTitle(aTitle?.textContent || "") - - getRefIndexByTitle(bTitle?.textContent || "") - ); - }); - refsInView.forEach((r) => refContainer?.appendChild(r)); - }; - - const sortCallbacks = { - "Page Title": (refContainer: Element) => () => - menuItemCallback(refContainer, (a, b) => - a.title.localeCompare(b.title) - ), - "Page Title Descending": (refContainer: Element) => () => - menuItemCallback(refContainer, (a, b) => - b.title.localeCompare(a.title) - ), - "Created Date": (refContainer: Element) => () => - menuItemCallback(refContainer, (a, b) => a.time - b.time), - "Created Date Descending": (refContainer: Element) => () => - menuItemCallback(refContainer, (a, b) => b.time - a.time), - "Daily Note": (refContainer: Element) => { - const dailyNoteSecondary = - getAttribute("Daily Note Secondary") || - config["Daily Note Secondary"] || - "time"; - return () => - menuItemCallback(refContainer, (a, b) => { - const aDate = window.roamAlphaAPI.util.pageTitleToDate(a.title); - const bDate = window.roamAlphaAPI.util.pageTitleToDate(b.title); - if (!aDate && !bDate) { - if (/^page title$/i.test(dailyNoteSecondary)) { - return a.title.localeCompare(b.title); - } else if ( - /^page title descending$/i.test(dailyNoteSecondary) - ) { - return b.title.localeCompare(a.title); - } else { - return a.time - b.time; - } - } else if (!aDate) { - return 1; - } else if (!bDate) { - return -1; - } else { - return aDate.valueOf() - bDate.valueOf(); - } - }); - }, - "Daily Note Descending": (refContainer: Element) => { - const dailyNoteSecondary = - getAttribute("Daily Note Secondary") || - config["Daily Note Secondary"] || - "time"; - return () => - menuItemCallback(refContainer, (a, b) => { - const aDate = window.roamAlphaAPI.util.pageTitleToDate(a.title); - const bDate = window.roamAlphaAPI.util.pageTitleToDate(b.title); - if (!aDate && !bDate) { - if (/^page title$/i.test(dailyNoteSecondary)) { - return a.title.localeCompare(b.title); - } else if ( - /^page title descending$/i.test(dailyNoteSecondary) - ) { - return b.title.localeCompare(a.title); - } else { - return b.time - a.time; - } - } else if (!aDate) { - return 1; - } else if (!bDate) { - return -1; - } else { - return bDate.valueOf() - aDate.valueOf(); - } - }); - }, - }; - - const createSortIconCallback = (container: HTMLDivElement) => { - const thisPageDefaultSort = getAttribute( - "Default Sort" - ) as keyof typeof sortCallbacks; - if (thisPageDefaultSort && sortCallbacks[thisPageDefaultSort]) { - sortCallbacks[thisPageDefaultSort](container)(); - return; - } - - const defaultSort = config[ - "Default Sort" - ] as keyof typeof sortCallbacks; - if (defaultSort && sortCallbacks[defaultSort]) { - sortCallbacks[defaultSort](container)(); - } - }; - const observerCallback = () => - createSortIcons( - "rm-reference-container dont-focus-block", - createSortIconCallback, - sortCallbacks, - undefined, - (container: HTMLDivElement) => - !!container.parentElement - ?.closest(".rm-reference-container") - ?.getElementsByClassName("refs-by-page-view")?.[0] - ); - const observer = createOverlayObserver(observerCallback); - observerCallback(); - unloads.add(() => { - document - .querySelectorAll(".roamjs-sort-icon") - .forEach((s) => s.remove()); - observer.disconnect(); - }); - } else { - unloads.forEach((u) => u()); - unloads.clear(); - } - }; -}; - -export default runSortReferences; From 65f5b88bf55b8dc86f7f2a7dfe7dd1fa8b009965 Mon Sep 17 00:00:00 2001 From: Michael Gartner Date: Tue, 8 Jul 2025 16:42:11 -0600 Subject: [PATCH 2/2] 1.36.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab121576..672e22be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "query-builder", - "version": "1.35.0", + "version": "1.36.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "query-builder", - "version": "1.35.0", + "version": "1.36.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 7f225013..04332976 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "query-builder", - "version": "1.35.0", + "version": "1.36.0", "description": "Introduces new user interfaces for building queries in Roam", "main": "./build/main.js", "author": {