diff --git a/src/index.ts b/src/index.ts index fd50bac..c21f42c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,6 +38,7 @@ import XRegExp from "xregexp"; import { PullBlock } from "roamjs-components/types"; import getParentUidByBlockUid from "roamjs-components/queries/getParentUidByBlockUid"; import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid"; +import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid"; import extractRef from "roamjs-components/util/extractRef"; import getDailyConfig from "./utils/getDailyConfig"; import saveDailyConfig from "./utils/saveDailyConfig"; @@ -597,6 +598,50 @@ export default runExtension(async ({ extensionAPI }) => { }, }); + const ROAM_TABLE_REGEX = /\{\{\[\[table\]\]\}\}/i; + type TableNode = { + uid: string; + children?: TableNode[]; + }; + + const getRoamTableUidRows = (nodes: TableNode[] = []): string[][] => + nodes + .filter((node): node is TableNode => !!node?.uid) + .map((rowNode) => + (rowNode.children || []) + .filter((cell): cell is TableNode => !!cell?.uid) + .map((cell) => cell.uid) + ); + + const resolveRoamTableButtonBlock = ({ + el, + tableUid, + }: { + el: HTMLElement; + tableUid: string; + }): { uid: string; text: string } | null => { + const tableEl = el.closest("table"); + const rowEl = el.closest("tr"); + const cellEl = el.closest("td"); + if (!tableEl || !rowEl || !cellEl) return null; + + const tableRows = Array.from(tableEl.querySelectorAll("tr")).filter( + (row) => row.querySelectorAll("td").length > 0 + ); + const rowIndex = tableRows.indexOf(rowEl); + const cells = Array.from(rowEl.querySelectorAll("td")); + const columnIndex = cells.indexOf(cellEl); + if (rowIndex < 0 || columnIndex < 0) return null; + + const uidRows = getRoamTableUidRows( + getBasicTreeByParentUid(tableUid) as unknown as TableNode[] + ); + const uid = uidRows[rowIndex]?.[columnIndex]; + if (!uid) return null; + + return { uid, text: getTextByBlockUid(uid) }; + }; + const registerElAsSmartBlockTrigger = ({ textContent, text, @@ -612,7 +657,13 @@ export default runExtension(async ({ extensionAPI }) => { }) => { // We include textcontent here bc there could be multiple smartblocks in a block const label = textContent.trim(); - const parsed = parseSmartBlockButton(label, text); + const tableResolution = + ROAM_TABLE_REGEX.test(text) && !!el.closest("table") + ? resolveRoamTableButtonBlock({ el, tableUid: parentUid }) + : null; + const resolvedParentUid = tableResolution?.uid || parentUid; + const resolvedText = tableResolution?.text || text; + const parsed = parseSmartBlockButton(label, resolvedText); if (parsed) { const { index, full, buttonContent, workflowName, variables } = parsed; const clickListener = () => { @@ -627,7 +678,7 @@ export default runExtension(async ({ extensionAPI }) => { text: "Could not find custom workflow with the name:", children: [{ text: workflowName }], }, - parentUid, + parentUid: resolvedParentUid, }); } else { const keepButton = @@ -651,29 +702,29 @@ export default runExtension(async ({ extensionAPI }) => { mutableCursor: !( workflows.find((w) => w.uid === srcUid)?.name || "" ).includes("<%NOCURSOR%>"), - triggerUid: parentUid, + triggerUid: resolvedParentUid, }; if (applyToSibling) { const sbParentTree = getShallowTreeByParentUid( - getParentUidByBlockUid(parentUid) + getParentUidByBlockUid(resolvedParentUid) ); const siblingIndex = - sbParentTree.findIndex((obj) => obj.uid === parentUid) + + sbParentTree.findIndex((obj) => obj.uid === resolvedParentUid) + (applyToSibling === "previous" ? -1 : 1); const siblingUid = sbParentTree[siblingIndex]?.uid; const siblingText = getTextByBlockUid(siblingUid); updateBlock({ - uid: parentUid, + uid: resolvedParentUid, text: clearBlock && keepButton ? full : clearBlock ? "" : keepButton - ? text - : `${text.substring(0, index)}${text.substring( + ? resolvedText + : `${resolvedText.substring(0, index)}${resolvedText.substring( index + full.length )}`, }); @@ -692,7 +743,7 @@ export default runExtension(async ({ extensionAPI }) => { ) : createBlock({ node: { text: "" }, - parentUid: getParentUidByBlockUid(parentUid), + parentUid: getParentUidByBlockUid(resolvedParentUid), order: siblingIndex === -1 ? 0 : siblingIndex, }).then((targetUid) => sbBomb({ @@ -717,7 +768,7 @@ export default runExtension(async ({ extensionAPI }) => { }) : createBlock({ node: { text: "" }, - parentUid, + parentUid: resolvedParentUid, order, }).then((targetUid) => sbBomb({ @@ -733,23 +784,23 @@ export default runExtension(async ({ extensionAPI }) => { ), clearBlock ? updateBlock({ - uid: parentUid, + uid: resolvedParentUid, text: full, }) : ""; } else { updateBlock({ - uid: parentUid, + uid: resolvedParentUid, text: clearBlock ? "" - : `${text.substring(0, index)}${text.substring( + : `${resolvedText.substring(0, index)}${resolvedText.substring( index + full.length )}`, }).then(() => sbBomb({ ...props, target: { - uid: parentUid, + uid: resolvedParentUid, start: index, end: index, },