complete local markdown resource lifecycle contract

This commit is contained in:
lix-2026
2026-05-24 03:22:03 +08:00
parent 6df74fb4e0
commit 36eac664f2
8 changed files with 269 additions and 33 deletions
@@ -122,6 +122,10 @@ const SIDEBAR_TREE_JS: &str = r##"
var stored = Number(window.localStorage.getItem(storageKey) || '');
if (stored) applyWidth(stored);
} catch (_) {}
resizer.addEventListener('wheel', function(event) {
event.preventDefault();
event.stopPropagation();
}, { passive: false });
resizer.addEventListener('pointerdown', function(event) {
if (event.button !== 0) return;
event.preventDefault();
@@ -2429,6 +2433,7 @@ const SIDEBAR_TREE_JS: &str = r##"
syncSidebarFileTreeSelection();
schedulePendingLocalFolderRestoreFocus();
restoreSidebarTreeTab();
refreshEditorLocalAttachmentExistence();
document.documentElement.setAttribute('data-mnote-local-folder-watch-applied', 'projection');
return true;
}
@@ -8665,6 +8670,62 @@ const SIDEBAR_TREE_JS: &str = r##"
}
}
function localFileOpenRootUriFromHref(href) {
try {
var url = new URL(String(href || ''), window.location.origin);
if (url.pathname !== '/api/local-folder/files/open') return '';
return String(url.searchParams.get('rootUri') || '').trim();
} catch (_) {
return '';
}
}
function buildLocalFileStatusUrl(relativePath, rootUri) {
var effectiveRootUri = String(rootUri || currentRootUri() || '').trim();
if (!effectiveRootUri || !relativePath) return '';
var url = new URL('/api/local-folder/files/stat', window.location.origin);
url.searchParams.set('rootUri', effectiveRootUri);
url.searchParams.set('path', relativePath);
return url.toString();
}
function setEditorAttachmentMissingState(link, missing) {
if (!(link instanceof HTMLAnchorElement)) return;
var value = Boolean(missing);
if (value) {
link.setAttribute('data-mnote-attachment-missing', 'true');
link.classList.add('mnote-uploaded-attachment-missing');
link.setAttribute('aria-label', (link.textContent || '') + '');
} else {
if (link.getAttribute('data-mnote-attachment-missing') !== 'true') return;
link.removeAttribute('data-mnote-attachment-missing');
link.classList.remove('mnote-uploaded-attachment-missing');
link.removeAttribute('aria-label');
}
}
async function refreshLocalAttachmentExistence(link) {
if (!(link instanceof HTMLAnchorElement)) return;
var href = link.getAttribute('href') || link.href || '';
var localFilePath = localFileOpenPathFromHref(href);
if (!localFilePath) return;
var statusUrl = buildLocalFileStatusUrl(localFilePath, localFileOpenRootUriFromHref(href));
if (!statusUrl) return;
try {
var response = await fetch(statusUrl, { headers: { accept: 'application/json' }, cache: 'no-store' });
var payload = await response.json().catch(function() { return null; });
var exists = Boolean(response.ok && payload && payload.ok === true && payload.result && payload.result.exists === true);
setEditorAttachmentMissingState(link, !exists);
} catch (_) {}
}
function refreshEditorLocalAttachmentExistence() {
document.querySelectorAll('.editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(link) {
if (link instanceof HTMLAnchorElement) void refreshLocalAttachmentExistence(link);
});
}
window.__mnoteRefreshEditorLocalAttachmentExistence = refreshEditorLocalAttachmentExistence;
function fileNameFromPath(path) {
var value = String(path || '').trim();
return value.indexOf('/') >= 0 ? value.split('/').pop() : value;
@@ -8785,6 +8846,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|| Boolean(localFilePath);
if (!shouldEnhance) return;
if (localFilePath && !isOnlyOfficeAttachmentHref(href)) {
void refreshLocalAttachmentExistence(link);
return;
}
link.setAttribute('data-mnote-attachment-link', 'true');
@@ -10174,6 +10236,7 @@ const SIDEBAR_TREE_JS: &str = r##"
window.addEventListener('tree:resync', function(event) {
var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
if (renderSidebarSnapshot(payload)) {
refreshEditorLocalAttachmentExistence();
document.documentElement.setAttribute('data-mnote-tree-live-applied', 'resync');
return;
}
+11
View File
@@ -256,6 +256,7 @@ a:hover {
cursor: col-resize;
position: relative;
flex: 0 0 auto;
overscroll-behavior: none;
}
.mnote-sidebar-resizer::before {
@@ -1871,6 +1872,12 @@ body {
text-decoration: none !important;
}
.document-shell .editor-surface .ProseMirror a[data-mnote-attachment-missing="true"] {
color: #9f1239 !important;
background: #fff1f2 !important;
box-shadow: inset 0 0 0 1px #fecdd3 !important;
}
.document-shell .editor-surface .ProseMirror a.mnote-uploaded-attachment-row::before,
.document-shell .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]::before {
content: "" !important;
@@ -1883,6 +1890,10 @@ body {
box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.12) !important;
}
.document-shell .editor-surface .ProseMirror a[data-mnote-attachment-missing="true"]::before {
background: #e11d48 !important;
}
.document-shell .editor-surface .ProseMirror a.mnote-uploaded-attachment-word::before {
background: #4f7df3;
}