mirror of
https://github.com/scotttomaszewski/obsidian-disciples-journal.git
synced 2026-07-22 05:42:13 +00:00
Render ESV HTML via sanitizeHTMLToDom instead of innerHTML
Resolves FOLLOWUP.md #3. All four sites in BibleReferenceRenderer that assigned the ESV API response to innerHTML now run it through Obsidian's sanitizeHTMLToDom() and append the resulting DocumentFragment, dropping the inline no-unsanitized/property and no-inner-html eslint-disable comments. The verse-preview extraction queries/clones paragraphs off the sanitized fragment instead of a temporary innerHTML div. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d01fc5f202
commit
5813205586
3 changed files with 21 additions and 20 deletions
|
|
@ -1,5 +1,9 @@
|
|||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Renders ESV passage HTML through Obsidian's `sanitizeHTMLToDom()` and appends the resulting fragment, instead of assigning the raw API response to `innerHTML`
|
||||
|
||||
## 0.13.0
|
||||
|
||||
- Brings the plugin in line with current Obsidian community standards
|
||||
|
|
|
|||
16
FOLLOWUP.md
16
FOLLOWUP.md
|
|
@ -65,18 +65,20 @@ callbacks reuse the shared instance instead of constructing new ones. The file-l
|
|||
|
||||
---
|
||||
|
||||
## 3. Rendering ESV HTML via `innerHTML`
|
||||
## 3. Rendering ESV HTML via `innerHTML` — ✅ RESOLVED
|
||||
|
||||
**File:** `src/components/BibleReferenceRenderer.ts` (4 sites)
|
||||
|
||||
**What's wrong:** passage HTML returned by the ESV API is injected with
|
||||
**What was wrong:** passage HTML returned by the ESV API was injected with
|
||||
`element.innerHTML = passage.html`. Flagged by `no-unsanitized/property` and
|
||||
`@microsoft/sdl/no-inner-html`. The content is trusted (comes from the ESV API
|
||||
over HTTPS), so this is currently accepted and disabled inline at each site.
|
||||
`@microsoft/sdl/no-inner-html`.
|
||||
|
||||
**Suggested fix:** parse the HTML and rebuild it with Obsidian DOM helpers
|
||||
(`createEl`/`createDiv`), or sanitize before insertion, so no raw HTML string is
|
||||
written to the DOM.
|
||||
**Fix applied:** all four sites now run the passage HTML through Obsidian's
|
||||
`sanitizeHTMLToDom()` and append the returned `DocumentFragment`, so no raw HTML
|
||||
string is written to the DOM. The verse-preview extraction (`showVersePreview`)
|
||||
parses into the sanitized fragment and queries/clones paragraphs off of it
|
||||
instead of a temporary `innerHTML` div. The inline `eslint-disable` comments at
|
||||
each site were removed.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Notice} from "obsidian";
|
||||
import {Notice, sanitizeHTMLToDom} from "obsidian";
|
||||
import {BibleContentService} from "../services/BibleContentService";
|
||||
import {BibleNavigation} from "./BibleNavigation";
|
||||
import DisciplesJournalPlugin from "src/core/DisciplesJournalPlugin";
|
||||
|
|
@ -133,8 +133,7 @@ export class BibleReferenceRenderer {
|
|||
// Add verses
|
||||
const passageEl = el.doc.createElement('div');
|
||||
passageEl.classList.add('bible-passage-text');
|
||||
// eslint-disable-next-line no-unsanitized/property, @microsoft/sdl/no-inner-html -- deferred: ESV API returns trusted formatted HTML; see FOLLOWUP.md
|
||||
passageEl.innerHTML = response.passage.html;
|
||||
passageEl.appendChild(sanitizeHTMLToDom(response.passage.html));
|
||||
|
||||
containerEl.appendChild(passageEl);
|
||||
el.appendChild(containerEl);
|
||||
|
|
@ -187,18 +186,16 @@ export class BibleReferenceRenderer {
|
|||
// Use the HTML content directly, but try to extract just the portion we need
|
||||
// for the preview (to avoid showing footnotes, chapter headings, etc.)
|
||||
try {
|
||||
// Create a temporary element to parse the HTML
|
||||
const tempEl = element.doc.createElement('div');
|
||||
// eslint-disable-next-line no-unsanitized/property, @microsoft/sdl/no-inner-html -- deferred: ESV API returns trusted formatted HTML; see FOLLOWUP.md
|
||||
tempEl.innerHTML = passage.html;
|
||||
// Parse and sanitize the HTML into a detached fragment we can inspect
|
||||
const parsed = sanitizeHTMLToDom(passage.html);
|
||||
|
||||
// Remove footnote sections before extracting paragraphs
|
||||
if (this.plugin.settings.hideFootnotesInPreview) {
|
||||
tempEl.querySelectorAll('.footnotes, .extra_text').forEach(el => el.remove());
|
||||
parsed.querySelectorAll('.footnotes, .extra_text').forEach(el => el.remove());
|
||||
}
|
||||
|
||||
// Find and extract the main verse content (paragraphs)
|
||||
const paragraphs = tempEl.querySelectorAll('p:not(.extra_text)');
|
||||
const paragraphs = parsed.querySelectorAll('p:not(.extra_text)');
|
||||
if (paragraphs.length > 0) {
|
||||
for (let i = 0; i < paragraphs.length; i++) {
|
||||
const cloned = paragraphs[i].cloneNode(true);
|
||||
|
|
@ -213,13 +210,11 @@ export class BibleReferenceRenderer {
|
|||
}
|
||||
} else {
|
||||
// Fallback if we can't extract the verses properly
|
||||
// eslint-disable-next-line no-unsanitized/property, @microsoft/sdl/no-inner-html -- deferred: ESV API returns trusted formatted HTML; see FOLLOWUP.md
|
||||
contentEl.innerHTML = passage.html;
|
||||
contentEl.appendChild(sanitizeHTMLToDom(passage.html));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error extracting verse content from HTML:", error);
|
||||
// eslint-disable-next-line no-unsanitized/property, @microsoft/sdl/no-inner-html -- deferred: ESV API returns trusted formatted HTML; see FOLLOWUP.md
|
||||
contentEl.innerHTML = passage.html;
|
||||
contentEl.appendChild(sanitizeHTMLToDom(passage.html));
|
||||
}
|
||||
|
||||
versePreviewEl.appendChild(contentEl);
|
||||
|
|
|
|||
Loading…
Reference in a new issue