From a5e284e27b4061ce2674c6d45a98b5400daed550 Mon Sep 17 00:00:00 2001 From: morri313 Date: Tue, 6 Oct 2026 17:40:07 -0700 Subject: [PATCH] fix: place remark and proof-like div anchors inline Port div-anchors extension fix from Morrison-Lab/qwt#160 (Morrison-Lab/qwt#159). Quarto theorem environments render titles with class .theorem-title, while proof-like environments (proof, remark, solution) render titles with class .proof-title. Previously, div-anchors.js only queried .theorem-title when relocating AnchorJS anchor links inline, causing remark and other proof-like divs to leave the anchor link at the bottom of the div rather than next to the title. - Support .proof-title alongside .theorem-title in div-anchors.js - Trim trailing whitespace from .proof-title (which ends with '. ') so the non-breaking separator and anchor stay attached to the title, and ensure a space separates the anchor from subsequent body content - Add 'rem' and 'sol' aliases and crossref ID prefix matching (rem-, thm-, def-, etc.) to is_theorem_div in both Lua and JS --- _extensions/div-anchors/div-anchors.js | 35 +++++++++++++++++++++++-- _extensions/div-anchors/div-anchors.lua | 33 +++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) 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