reported by Mark L via slack.
tl;dr What's left
Notes
I started looking into this, but didn't get a chance to finish. Here were my findings:
If a SmartBlock button is part of roam {{[[table]]}} the observer doesn't catch it because it's parent blockUid is actually the table block, so the match check fails as there is no SmartBlock button in it's textContent.

It doesn't look like there the original uid that holds the SmartBlock button (VeSLtlz0N) is accessible in the DOM

Possible solution:
|
const registerElAsSmartBlockTrigger = ({ |
|
textContent, |
|
text, |
|
el, |
|
parentUid, |
|
hideIcon, |
|
}: { |
|
textContent: string; |
|
text: string; |
|
el: HTMLElement; |
|
parentUid: string; |
|
hideIcon?: false; |
|
}) => { |
|
// We include textcontent here bc there could be multiple smartblocks in a block |
|
const regex = new RegExp( |
|
`{{(${textContent.replace(/\+/g, "\\+")}):(?:42)?SmartBlock:(.*?)}}` |
|
); |
|
const match = regex.exec(text); |
|
if (match) { |
If !match we could check text (which is parentUid text) for {{[[table]]}}
If true
- calculate row/column position based on DOM (
el is the button element in the roam ) - get the tree of
parentUid - get original
uid based on row/column something like:
// check if parent is roam {{[[table]]}}
const getMatchFromRoamTable = () => {
const parentText = getTextByBlockUid(parentUid);
const roamTablePattern = /\{\{\[\[table\]\]\}\}/;
const isInRoamTable = roamTablePattern.exec(parentText);
if (!isInRoamTable) return null;
const tableEl = el.closest("table");
if (!tableEl) return null;
// Get the row and column of the button
const rows = Array.from(tableEl.querySelectorAll("tr")).filter(
(row) => row.innerHTML.trim() !== "" // first row is blank?
);
let position = { row: 0, column: 0 };
rows.map((row, rowIndex) => {
const cells = Array.from(row.querySelectorAll("td"));
cells.map((cell, colIndex) => {
if (cell.contains(el)) {
position = { row: rowIndex + 1, column: colIndex + 1 };
}
});
});
if (!position.row || !position.column) return null;
// Get UID from tree based position
const tree = getBasicTreeByParentUid(parentUid);
const uid = getUidFromTablePosition() // need to create this
const tableButtonText = getTextByBlockUid(uid);
return regex.exec(tableButtonText);
};
if (!match) match = getMatchFromRoamTable();but the getUidFromTablePosition() gets a little tricky as there are multiple ways to construct a table

It looks like
- node with no children = 1 row
- node with 1 child = 1 row
- node with 1+n children = 1+n rows
I didn't get a chance to finish writing that, but unless I missed something, it seems quite possible.
Oh, also, should consider if the {{[[table]]}} block ALSO has a {{SmartBlock}} button ... check to make sure it gets the data-roamjs-smartblock-button first.
reported by Mark L via slack.
tl;dr What's left
getUidFromTablePosition(){{[[table]]}}block ALSO has a{{SmartBlock}}buttonNotes
I started looking into this, but didn't get a chance to finish. Here were my findings:
If a SmartBlock button is part of roam
{{[[table]]}}the observer doesn't catch it because it's parentblockUidis actually the table block, so thematchcheck fails as there is no SmartBlock button in it'stextContent.It doesn't look like there the original
uidthat holds the SmartBlock button (VeSLtlz0N) is accessible in the DOMPossible solution:
smartblocks/src/index.ts
Lines 543 to 561 in 170690d
If
!matchwe could checktext(which isparentUidtext) for{{[[table]]}}If true
elis the button element in the roam )parentUiduidbased on row/columnsomething like:
but the
getUidFromTablePosition()gets a little tricky as there are multiple ways to construct a tableIt looks like
I didn't get a chance to finish writing that, but unless I missed something, it seems quite possible.
Oh, also, should consider if the
{{[[table]]}}block ALSO has a{{SmartBlock}}button ... check to make sure it gets thedata-roamjs-smartblock-buttonfirst.