v0.2.55
This commit is contained in:
@@ -461,15 +461,16 @@ export function renderMarkdown(source, lineOffset = 0) {
|
||||
let end = index + 1;
|
||||
while (end < lines.length && !/^<\/details>\s*$/i.test(lines[end].trim())) end++;
|
||||
if (end < lines.length) {
|
||||
const block = lines.slice(index + 1, end);
|
||||
let bodyStart = index + 1;
|
||||
let summary = "Details";
|
||||
while (block.length && !block[0].trim()) block.shift();
|
||||
if (block.length) {
|
||||
const summaryMatch = block[0].trim().match(/^<summary>([\s\S]*?)<\/summary>$/i);
|
||||
if (summaryMatch) { summary = summaryMatch[1].trim() || "Details"; block.shift(); }
|
||||
while (bodyStart < end && !lines[bodyStart].trim()) bodyStart++;
|
||||
if (bodyStart < end) {
|
||||
const summaryMatch = lines[bodyStart].trim().match(/^<summary>([\s\S]*?)<\/summary>$/i);
|
||||
if (summaryMatch) { summary = summaryMatch[1].trim() || "Details"; bodyStart++; }
|
||||
}
|
||||
while (block.length && !block[0].trim()) block.shift();
|
||||
html += `<details class="markdown-details preview-source-line" data-source-line="${index + lineOffset + 1}"><summary>${inline(summary)}</summary><div class="markdown-details__content">${renderMarkdown(block.join("\n"), lineOffset + index + 1)}</div></details>`;
|
||||
while (bodyStart < end && !lines[bodyStart].trim()) bodyStart++;
|
||||
const body = lines.slice(bodyStart, end).join("\n");
|
||||
html += `<details class="markdown-details preview-source-line" data-source-line="${index + lineOffset + 1}" data-source-end-line="${end + lineOffset + 1}"><summary>${inline(summary)}</summary><div class="markdown-details__content">${renderMarkdown(body, lineOffset + bodyStart)}</div></details>`;
|
||||
index = end;
|
||||
continue;
|
||||
}
|
||||
|
||||
+39
-14
@@ -920,15 +920,23 @@ export function startNoteEditor(adapter) {
|
||||
preview.querySelectorAll(".preview-source-line[data-source-line]").forEach(node => {
|
||||
const sourceLine = Number(node.dataset.sourceLine);
|
||||
if (!Number.isFinite(sourceLine) || sourceLine < 1 || !node.getClientRects().length) return;
|
||||
const rect = node.getBoundingClientRect();
|
||||
const isDetails = node.matches("details.markdown-details");
|
||||
const geometryNode = isDetails && node.open ? node.querySelector(":scope > summary") : node;
|
||||
if (!geometryNode?.getClientRects().length) return;
|
||||
const rect = geometryNode.getBoundingClientRect();
|
||||
const declaredEnd = Number(node.dataset.sourceEndLine);
|
||||
const sourceEndLine = isDetails && !node.open && Number.isFinite(declaredEnd) && declaredEnd >= sourceLine
|
||||
? declaredEnd
|
||||
: sourceLine;
|
||||
positions.push({
|
||||
node,
|
||||
sourceLine,
|
||||
sourceEndLine,
|
||||
top: rect.top - previewRect.top + preview.scrollTop,
|
||||
bottom: rect.bottom - previewRect.top + preview.scrollTop,
|
||||
});
|
||||
});
|
||||
return positions;
|
||||
return positions.sort((left, right) => left.top - right.top || left.sourceLine - right.sourceLine);
|
||||
}
|
||||
|
||||
function previewScrollAnchor() {
|
||||
@@ -940,11 +948,15 @@ export function startNoteEditor(adapter) {
|
||||
let currentIndex = positions.findIndex(position => position.bottom > viewportTop + 0.5);
|
||||
if (currentIndex < 0) currentIndex = positions.length - 1;
|
||||
const current = positions[currentIndex];
|
||||
const next = positions.slice(currentIndex + 1).find(position => position.sourceLine > current.sourceLine);
|
||||
const progress = Math.max(0, Math.min(1, (viewportTop - current.top) / Math.max(1, current.bottom - current.top)));
|
||||
const sourceLine = next
|
||||
? current.sourceLine + progress * (next.sourceLine - current.sourceLine)
|
||||
: current.sourceLine;
|
||||
if (current.sourceEndLine > current.sourceLine) {
|
||||
const progress = Math.max(0, Math.min(1, (viewportTop - current.top) / Math.max(1, current.bottom - current.top)));
|
||||
const sourceLine = current.sourceLine + progress * (current.sourceEndLine - current.sourceLine);
|
||||
return { sourceLine, ...state };
|
||||
}
|
||||
const next = positions.slice(currentIndex + 1).find(position => position.sourceLine > current.sourceEndLine && position.top > current.top + 0.5);
|
||||
if (!next) return { sourceLine: current.sourceLine, ...state };
|
||||
const progress = Math.max(0, Math.min(1, (viewportTop - current.top) / Math.max(1, next.top - current.top)));
|
||||
const sourceLine = current.sourceEndLine + progress * (next.sourceLine - current.sourceEndLine);
|
||||
return { sourceLine, ...state };
|
||||
}
|
||||
|
||||
@@ -982,13 +994,18 @@ export function startNoteEditor(adapter) {
|
||||
return;
|
||||
}
|
||||
const sourceLine = Math.max(1, anchor.sourceLine);
|
||||
const exact = positions.find(position => position.sourceLine === sourceLine);
|
||||
let targetTop = exact?.top;
|
||||
const covering = positions.find(position => position.sourceLine <= sourceLine && sourceLine <= position.sourceEndLine);
|
||||
let targetTop;
|
||||
if (covering) {
|
||||
const sourceSpan = covering.sourceEndLine - covering.sourceLine;
|
||||
const progress = sourceSpan > 0 ? (sourceLine - covering.sourceLine) / sourceSpan : 0;
|
||||
targetTop = covering.top + progress * Math.max(0, covering.bottom - covering.top);
|
||||
}
|
||||
if (!Number.isFinite(targetTop)) {
|
||||
const before = [...positions].reverse().find(position => position.sourceLine <= sourceLine);
|
||||
const before = [...positions].reverse().find(position => position.sourceEndLine <= sourceLine);
|
||||
const after = positions.find(position => position.sourceLine >= sourceLine);
|
||||
if (before && after && after.sourceLine > before.sourceLine) {
|
||||
const progress = (sourceLine - before.sourceLine) / (after.sourceLine - before.sourceLine);
|
||||
if (before && after && after.sourceLine > before.sourceEndLine) {
|
||||
const progress = (sourceLine - before.sourceEndLine) / (after.sourceLine - before.sourceEndLine);
|
||||
targetTop = before.top + progress * (after.top - before.top);
|
||||
} else targetTop = (before || after)?.top;
|
||||
}
|
||||
@@ -1053,9 +1070,15 @@ export function startNoteEditor(adapter) {
|
||||
function renderNow() {
|
||||
const previewViewport = pendingPreviewViewport;
|
||||
pendingPreviewViewport = null;
|
||||
const openDetailsLines = uiState.mode === "markdown"
|
||||
? new Set([...preview.querySelectorAll("details.markdown-details[open][data-source-line]")].map(node => node.dataset.sourceLine))
|
||||
: new Set();
|
||||
if (uiState.mode === "markdown") {
|
||||
preview.classList.remove("preview--raw");
|
||||
preview.innerHTML = renderMarkdown(editor.value);
|
||||
preview.querySelectorAll("details.markdown-details[data-source-line]").forEach(node => {
|
||||
node.open = openDetailsLines.has(node.dataset.sourceLine);
|
||||
});
|
||||
scheduleAliasFileRefresh(editor.value);
|
||||
document.querySelector("#preview-label").textContent = "Preview (media / mermaid / markdown)";
|
||||
renderMermaid();
|
||||
@@ -1143,6 +1166,8 @@ export function startNoteEditor(adapter) {
|
||||
function restoreHistorySnapshot(snapshot) {
|
||||
if (!snapshot || !canEditDocument()) return;
|
||||
const previous = editor.value;
|
||||
const viewportScrollTop = editor.scrollTop;
|
||||
const viewportScrollLeft = editor.scrollLeft;
|
||||
const maxOffset = snapshot.content.length;
|
||||
const selectionStart = Math.min(snapshot.selectionStart ?? maxOffset, maxOffset);
|
||||
const selectionEnd = Math.min(snapshot.selectionEnd ?? selectionStart, maxOffset);
|
||||
@@ -1152,8 +1177,8 @@ export function startNoteEditor(adapter) {
|
||||
previousContent = snapshot.content;
|
||||
editor.setSelectionRange(selectionStart, selectionEnd, snapshot.selectionDirection || "none");
|
||||
render();
|
||||
editor.scrollTop = snapshot.scrollTop || 0;
|
||||
editor.scrollLeft = snapshot.scrollLeft || 0;
|
||||
editor.scrollTop = viewportScrollTop;
|
||||
editor.scrollLeft = viewportScrollLeft;
|
||||
syncEditorLayers();
|
||||
applyingHistory = false;
|
||||
editor.focus({ preventScroll: true });
|
||||
|
||||
Reference in New Issue
Block a user