diff --git a/_extensions/div-anchors/div-anchors.js b/_extensions/div-anchors/div-anchors.js index 23ae262d..a102af24 100644 --- a/_extensions/div-anchors/div-anchors.js +++ b/_extensions/div-anchors/div-anchors.js @@ -17,15 +17,30 @@ const theoremLikeClasses = new Set([ "exr", "exercise", "proof", + "rem", "remark", + "sol", "solution" ]); +const theoremLikePrefixes = [ + "thm-", + "lem-", + "cor-", + "prp-", + "cnj-", + "def-", + "exm-", + "exr-", + "rem-", + "sol-" +]; const inlineAnchorSeparator = "\u00A0"; const maxAnchorRetryAttempts = 5; const anchorRetryDelayMs = 50; const isTheoremLikeDiv = (div) => - Array.from(div.classList).some((className) => theoremLikeClasses.has(className)); + Array.from(div.classList).some((className) => theoremLikeClasses.has(className)) || + (div.id && theoremLikePrefixes.some((prefix) => div.id.startsWith(prefix))); const addTheoremLikeDivAnchors = () => { for (const theoremDiv of window.document.querySelectorAll("div[id]")) { @@ -85,7 +100,7 @@ const moveTheoremDivAnchorsInline = () => { continue; } - const theoremTitle = theoremDiv.querySelector(".theorem-title"); + const theoremTitle = theoremDiv.querySelector(".theorem-title, .proof-title"); if (!theoremTitle) { continue; } @@ -107,6 +122,22 @@ const moveTheoremDivAnchorsInline = () => { } anchorLink.classList.remove("external"); + + // If the title ends with whitespace (e.g. Quarto's proof-title ending in ". "), + // trim the trailing whitespace so the non-breaking separator and anchor stay attached + // to the title text, and ensure a trailing space separates the anchor from following content. + let lastTextNode = theoremTitle.lastChild; + while (lastTextNode && lastTextNode.nodeType !== Node.TEXT_NODE && lastTextNode.lastChild) { + lastTextNode = lastTextNode.lastChild; + } + if (lastTextNode && lastTextNode.nodeType === Node.TEXT_NODE && /\s+$/.test(lastTextNode.textContent)) { + lastTextNode.textContent = lastTextNode.textContent.replace(/\s+$/, ""); + if (theoremTitle.nextSibling && + !(theoremTitle.nextSibling.nodeType === Node.TEXT_NODE && /^\s/.test(theoremTitle.nextSibling.textContent))) { + theoremTitle.after(" "); + } + } + theoremTitle.append(inlineAnchorSeparator); theoremTitle.append(anchorLink); } diff --git a/_extensions/div-anchors/div-anchors.lua b/_extensions/div-anchors/div-anchors.lua index 4a6137ad..668d00b8 100644 --- a/_extensions/div-anchors/div-anchors.lua +++ b/_extensions/div-anchors/div-anchors.lua @@ -16,10 +16,39 @@ local theorem_div_classes = { "exr", "exercise", "proof", + "rem", "remark", + "sol", "solution" } +local theorem_id_prefixes = { + "thm-", + "lem-", + "cor-", + "prp-", + "cnj-", + "def-", + "exm-", + "exr-", + "rem-", + "sol-" +} + +local function id_is_theorem_like(id) + if not id then + return false + end + + for _, prefix in ipairs(theorem_id_prefixes) do + if id:sub(1, #prefix) == prefix then + return true + end + end + + return false +end + local function class_is_theorem_like(class) for _, theorem_class in ipairs(theorem_div_classes) do if class == theorem_class then @@ -31,6 +60,10 @@ local function class_is_theorem_like(class) end local function is_theorem_div(div) + if id_is_theorem_like(div.identifier) then + return true + end + for _, class in ipairs(div.classes) do if class_is_theorem_like(class) then return true