0.102.19: plugin-store review round 2 — sanitizeHTMLToDom + minAppVersion 1.13.0

This commit is contained in:
Human 2026-06-14 11:44:54 -07:00
parent d3c5409b2a
commit c633cd146d
5 changed files with 36 additions and 17 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,8 +1,8 @@
{
"id": "stashpad",
"name": "Stashpad",
"version": "0.102.16",
"minAppVersion": "1.7.0",
"version": "0.102.19",
"minAppVersion": "1.13.0",
"description": "A chat-style, nested-notes workspace: rapid capture, outliner navigation, in-place editing, fast search, tasks, and per-folder templates, with one-click Open Knowledge Format (OKF) export so your notes are readable by LLMs and agents.",
"author": "Human",
"isDesktopOnly": false

View file

@ -1,6 +1,6 @@
{
"name": "stashpad-obsidian",
"version": "0.102.16",
"version": "0.102.19",
"private": true,
"scripts": {
"dev": "node esbuild.config.mjs",

19
release-notes/0.102.19.md Normal file
View file

@ -0,0 +1,19 @@
# 0.102.19 — Plugin-store review compliance (round 2)
Housekeeping release continuing the community-plugin-store review pass. No feature
changes. Still alpha; keep backups.
## Compatibility
- **Minimum Obsidian version is now 1.13.0.** Stashpad leans on APIs (the declarative
settings/search, workspace and encryption APIs) that the store review requires the
manifest to declare. The plugin already ran against 1.13+; this just makes the floor
explicit. If you're on an older Obsidian, update to 1.13 or later to install.
## Under the hood
- Cached note bodies are now re-hydrated with Obsidian's own `sanitizeHTMLToDom`
(the sanctioned, safe HTML-to-DOM API) instead of a lower-level call the review
flagged. Rendering is unchanged.
- Fixed an internal lint nit: a regex that strips a leading byte-order mark now uses an
escape sequence instead of a literal invisible character. No behavior change.

View file

@ -1,7 +1,7 @@
import {
App, ItemView, MarkdownRenderer, Menu, Notice, Platform,
Scope, SuggestModal, TFile, TFolder, WorkspaceLeaf, debounce,
moment, setIcon,
moment, sanitizeHTMLToDom, setIcon,
} from "obsidian";
import {
ROOT_ID, STASHPAD_VIEW_TYPE, RESERVED_FRONTMATTER, fmHasTag, fmAddTag, fmRemoveTag, parseAssignees, parseAuthorRef, attachmentLinkPath, toAttachmentLink,
@ -4419,16 +4419,16 @@ export class StashpadView extends ItemView {
} else {
// Re-hydrate the cached markdown HTML. The string was produced by
// Obsidian's own MarkdownRenderer from the user's note and persisted in
// the render cache; we parse it back into nodes and append them to the
// (freshly emptied) text element rather than assigning innerHTML
// (Obsidian lint: no-unsafe-innerHTML). createContextualFragment yields
// identical DOM — and, like innerHTML, never executes <script> — so
// event delegation for internal links / tags / embeds still wires up
// without a fresh MarkdownRenderer pass. (Live-rendered widgets like
// Mermaid/MathJax are the one weak spot — they won't re-execute from
// cached HTML, but they're rare in chat-style notes and re-render on
// the next mtime change anyway.)
textEl.append(document.createRange().createContextualFragment(html));
// the render cache; we parse it back into DOM with Obsidian's own
// sanitizeHTMLToDom() and append the fragment to the (freshly emptied)
// text element. This is the API the plugin-review linter blesses for
// "HTML string → DOM" (vs. innerHTML / createContextualFragment, both
// flagged). Event delegation for internal links / tags / embeds still
// wires up without a fresh MarkdownRenderer pass. (Live-rendered widgets
// like Mermaid/MathJax are the one weak spot — they won't re-execute from
// cached HTML, but they're rare in chat-style notes and re-render on the
// next mtime change anyway.)
textEl.append(sanitizeHTMLToDom(html));
}
if (attachments.length > 0) this.renderAttachmentRail(container, attachments);
// Multiplayer footer: author / contributors / last-edit. Each
@ -9548,7 +9548,7 @@ export class StashpadView extends ItemView {
/** public: called by AuthorshipTracker (the host interface). */
stripFrontmatter(md: string): string {
// Strip BOM if present so the opening-fence detection still works.
const text = md.replace(/^/, "");
const text = md.replace(/^\uFEFF/, "");
// Match: optional leading whitespace, "---", newline, anything (lazy),
// newline, "---", optional trailing whitespace, then either a newline
// or end-of-string. This covers \r\n line endings, missing trailing