mirror of
https://github.com/vicky469/aside.git
synced 2026-07-22 07:01:57 +00:00
Removes the resolved/unresolve comment feature entirely. Comments are now always visible — there is no archived state or toggle. - Removes `resolved?: boolean` from CommentThread, Comment, and all storage/normalization paths - Removes resolveComment/unresolveComment from CommentManager, CommentMutationController, and public plugin API - Removes shouldShowResolvedComments/setShowResolvedComments from session, mutation, and persistence controllers - Removes sidebar resolve button, toolbar chip, and resolved empty states from AsideView - Removes setThreadResolved sync event generation; keeps the op in the union type as a backward-compatible no-op so old stored events parse without error - Deletes resolvedCommentVisibility.ts, commentSelectionVisibility.ts, and resolve-note-comment.mjs scripts - Updates README to remove resolved feature mentions - Updates all tests accordingly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
265 lines
8.6 KiB
TypeScript
265 lines
8.6 KiB
TypeScript
import * as assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import type { Comment } from "../src/commentManager";
|
|
import { findClickedHighlightCommentId } from "../src/comments/commentHighlightClickTarget";
|
|
import {
|
|
findClickedIndexLivePreviewTarget,
|
|
isIndexNativeCollapseControlTarget,
|
|
shouldBlockIndexPreviewBackgroundTarget,
|
|
shouldUseIndexPreviewRowActivator,
|
|
shouldUseIndexLivePreviewLineFallback,
|
|
} from "../src/comments/commentIndexClickTarget";
|
|
import { buildPreviewHighlightWraps } from "../src/comments/commentHighlightPlanner";
|
|
|
|
function createComment(overrides: Partial<Comment> = {}): Comment {
|
|
return {
|
|
id: "comment-1",
|
|
filePath: "note.md",
|
|
startLine: 0,
|
|
startChar: 0,
|
|
endLine: 0,
|
|
endChar: 4,
|
|
selectedText: "beta",
|
|
selectedTextHash: "hash-beta",
|
|
comment: "note",
|
|
timestamp: 1710000000000,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test("buildPreviewHighlightWraps follows the source occurrence when rendered text repeats", () => {
|
|
const wraps = buildPreviewHighlightWraps(
|
|
"beta one beta",
|
|
0,
|
|
"beta one beta",
|
|
[createComment({
|
|
startChar: 9,
|
|
endChar: 13,
|
|
selectedText: "beta",
|
|
})],
|
|
);
|
|
|
|
assert.equal(wraps.length, 1);
|
|
assert.equal(wraps[0].start, 9);
|
|
assert.equal(wraps[0].end, 13);
|
|
assert.equal(wraps[0].comment.id, "comment-1");
|
|
});
|
|
|
|
test("buildPreviewHighlightWraps respects section line offsets for later lines", () => {
|
|
const wraps = buildPreviewHighlightWraps(
|
|
"alpha beta\nsecond beta",
|
|
10,
|
|
"alpha beta\nsecond beta",
|
|
[createComment({
|
|
id: "comment-2",
|
|
startLine: 11,
|
|
startChar: 7,
|
|
endLine: 11,
|
|
endChar: 11,
|
|
selectedText: "beta",
|
|
})],
|
|
);
|
|
|
|
assert.equal(wraps.length, 1);
|
|
assert.equal(wraps[0].start, 18);
|
|
assert.equal(wraps[0].end, 22);
|
|
assert.equal(wraps[0].comment.id, "comment-2");
|
|
});
|
|
|
|
test("findClickedHighlightCommentId returns the clicked highlight comment id", () => {
|
|
const target = {
|
|
closest: (selector: string) => {
|
|
assert.equal(selector, ".aside-highlight");
|
|
return {
|
|
getAttribute: (name: string) => {
|
|
assert.equal(name, "data-comment-id");
|
|
return "comment-7";
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
assert.equal(findClickedHighlightCommentId(target), "comment-7");
|
|
});
|
|
|
|
test("findClickedHighlightCommentId returns null when the target is not inside a highlight", () => {
|
|
const target = {
|
|
closest: () => null,
|
|
};
|
|
|
|
assert.equal(findClickedHighlightCommentId(target), null);
|
|
assert.equal(findClickedHighlightCommentId(null), null);
|
|
});
|
|
|
|
test("findClickedIndexLivePreviewTarget resolves comment links from live preview DOM", () => {
|
|
const target = {
|
|
closest: (selector: string) => {
|
|
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
|
|
return {
|
|
dataset: {
|
|
asideCommentUrl: "obsidian://aside-comment?vault=public&file=books%2FNote.md&commentId=comment-7",
|
|
},
|
|
getAttribute: () => null,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
};
|
|
|
|
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
|
|
kind: "comment",
|
|
filePath: "books/Note.md",
|
|
commentId: "comment-7",
|
|
});
|
|
});
|
|
|
|
test("findClickedIndexLivePreviewTarget resolves file headings from live preview DOM", () => {
|
|
const target = {
|
|
closest: (selector: string) => {
|
|
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
|
|
return null;
|
|
}
|
|
if (selector.includes(".aside-index-heading-label[title]")) {
|
|
return {
|
|
dataset: {},
|
|
getAttribute: (name: string) => {
|
|
assert.equal(name, "title");
|
|
return "books/Note.md";
|
|
},
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
};
|
|
|
|
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
|
|
kind: "file",
|
|
filePath: "books/Note.md",
|
|
});
|
|
});
|
|
|
|
test("findClickedIndexLivePreviewTarget resolves plain generated file links", () => {
|
|
const target = {
|
|
closest: (selector: string) => {
|
|
if (selector.includes("a[href^=\"obsidian://open\"]")) {
|
|
return {
|
|
dataset: {},
|
|
getAttribute: (name: string) => {
|
|
assert.equal(name, "href");
|
|
return "obsidian://open?vault=public&file=books%2FNote.md";
|
|
},
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
};
|
|
|
|
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
|
|
kind: "file",
|
|
filePath: "books/Note.md",
|
|
});
|
|
});
|
|
|
|
test("findClickedIndexLivePreviewTarget leaves native collapse controls alone", () => {
|
|
const target = {
|
|
closest: (selector: string) => {
|
|
if (selector.includes(".collapse-indicator")) {
|
|
return {
|
|
dataset: {},
|
|
getAttribute: () => null,
|
|
};
|
|
}
|
|
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
|
|
return {
|
|
dataset: {
|
|
asideCommentUrl: "obsidian://aside-comment?vault=public&file=books%2FNote.md&commentId=comment-7",
|
|
},
|
|
getAttribute: () => null,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
},
|
|
};
|
|
|
|
assert.equal(isIndexNativeCollapseControlTarget(target), true);
|
|
assert.equal(findClickedIndexLivePreviewTarget(target), null);
|
|
});
|
|
|
|
test("findClickedIndexLivePreviewTarget returns null for non-index elements", () => {
|
|
const target = {
|
|
closest: () => null,
|
|
};
|
|
|
|
assert.equal(findClickedIndexLivePreviewTarget(target), null);
|
|
assert.equal(findClickedIndexLivePreviewTarget(null), null);
|
|
});
|
|
|
|
test("index live preview line fallback ignores clicks on blank line space", () => {
|
|
const lineEl = {};
|
|
const childTarget = {};
|
|
|
|
assert.equal(shouldUseIndexLivePreviewLineFallback(lineEl, lineEl), false);
|
|
assert.equal(shouldUseIndexLivePreviewLineFallback(childTarget, lineEl), false);
|
|
});
|
|
|
|
test("index preview row activator ignores clicks on blank row space", () => {
|
|
const rowEl = {};
|
|
const childTarget = {};
|
|
|
|
assert.equal(shouldUseIndexPreviewRowActivator(rowEl, rowEl), false);
|
|
assert.equal(shouldUseIndexPreviewRowActivator(childTarget, rowEl), false);
|
|
});
|
|
|
|
test("index preview background clicks are blocked only on generated index rows", () => {
|
|
const generatedRow = {
|
|
getAttribute: () => null,
|
|
querySelector: (selector: string) =>
|
|
selector.includes("a[href^=\"obsidian://open\"]")
|
|
? { getAttribute: () => "obsidian://open?vault=dev&file=test.md" }
|
|
: null,
|
|
};
|
|
const rowBackgroundTarget = {
|
|
closest: (selector: string) => selector === "p, li" ? generatedRow : null,
|
|
};
|
|
const linkTarget = {
|
|
closest: (selector: string) => {
|
|
if (selector.includes("a[href^=\"obsidian://open\"]")) {
|
|
return {
|
|
dataset: {},
|
|
getAttribute: () => "obsidian://open?vault=dev&file=test.md",
|
|
};
|
|
}
|
|
if (selector === "p, li") {
|
|
return generatedRow;
|
|
}
|
|
return null;
|
|
},
|
|
};
|
|
const normalRowTarget = {
|
|
closest: (selector: string) => selector === "p, li"
|
|
? { getAttribute: () => null, querySelector: () => null }
|
|
: null,
|
|
};
|
|
|
|
assert.equal(shouldBlockIndexPreviewBackgroundTarget(rowBackgroundTarget), true);
|
|
assert.equal(shouldBlockIndexPreviewBackgroundTarget(linkTarget), false);
|
|
assert.equal(shouldBlockIndexPreviewBackgroundTarget(normalRowTarget), false);
|
|
});
|
|
|
|
test("index preview background clicks are blocked on the generated preview surface", () => {
|
|
const indexPreviewBackgroundTarget = {
|
|
closest: () => null,
|
|
matches: (selector: string) => selector.includes(".aside-index-note-view .markdown-preview-sizer"),
|
|
};
|
|
const normalPreviewBackgroundTarget = {
|
|
closest: () => null,
|
|
matches: () => false,
|
|
};
|
|
|
|
assert.equal(shouldBlockIndexPreviewBackgroundTarget(indexPreviewBackgroundTarget), true);
|
|
assert.equal(shouldBlockIndexPreviewBackgroundTarget(normalPreviewBackgroundTarget), false);
|
|
});
|