fix local markdown attachment regressions

This commit is contained in:
lix-2026
2026-05-29 11:13:05 +08:00
parent 1109e3c0d8
commit cbe789e034
63 changed files with 3249 additions and 1502 deletions
@@ -11,7 +11,6 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
currentRootUri,
currentWorkspaceSourcePayload,
fileTreeIconKindForFileName,
healLegacyOfficeAttachmentParagraphs,
hydrateEditorAttachmentMeta: injectedHydrateEditorAttachmentMeta,
inferCodeAttachmentLanguage,
inferOnlyOfficeFileType,
@@ -38,7 +37,8 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
var attachmentActionsHideTimer = 0;
var editorAttachmentMissingByKey = new Map();
var editorAttachmentRefreshSeqByKey = new Map();
var editorAttachmentLinkSelector = '.editor-surface .ProseMirror a[data-mnote-attachment-link="true"], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"], .editor-surface .ProseMirror a[href*="/office-preview"]';
var editorAttachmentLinkSelector = '.editor-surface .ProseMirror a.mnote-uploaded-attachment-row';
var editorAttachmentEnhanceSelector = '.editor-surface .ProseMirror a[href], ' + editorAttachmentLinkSelector;
function attachmentQueryParams(href) {
try {
@@ -58,6 +58,51 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
}
function decodeLocalEncodedPath(value) {
var path = String(value || '').trim().replace(/~([0-9A-Fa-f]{2})/g, '%$1');
if (!path) return '';
try {
return decodeURIComponent(path);
} catch (_) {
return path;
}
}
function localMarkdownPathFromDocumentId(documentId) {
var raw = String(documentId || '').trim();
if (raw.indexOf('local-md:') !== 0) return '';
return decodeLocalEncodedPath(raw.slice('local-md:'.length));
}
function normalizeLocalRelativePath(path) {
var parts = String(path || '').replace(/\\/g, '/').split('/');
var normalized = [];
for (var i = 0; i < parts.length; i += 1) {
var part = parts[i];
if (!part || part === '.') continue;
if (part === '..') {
if (normalized.length) normalized.pop();
continue;
}
normalized.push(part);
}
return normalized.join('/');
}
function localMarkdownAttachmentPathFromHref(href, documentId) {
var raw = String(href || '').trim();
if (!raw || raw.indexOf('#') === 0 || /^[a-z][a-z0-9+.-]*:/i.test(raw)) return '';
var documentPath = localMarkdownPathFromDocumentId(documentId);
if (!documentPath) return '';
var slashIndex = documentPath.lastIndexOf('/');
var documentDir = slashIndex >= 0 ? documentPath.slice(0, slashIndex) : '';
var decoded = raw;
try { decoded = decodeURIComponent(raw); } catch (_) {}
if (decoded.indexOf('../') === 0 || decoded.indexOf('/../') >= 0) return '';
var joined = documentDir ? documentDir + '/' + decoded : decoded;
return normalizeLocalRelativePath(joined);
}
function localFileOpenRootUriFromHref(href) {
try {
var url = new URL(String(href || ''), window.location.origin);
@@ -84,6 +129,77 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
return url.toString();
}
function buildLocalFileOpenUrlForRoot(relativePath, rootUri, download) {
var effectiveRootUri = String(rootUri || currentRootUri() || '').trim();
if (!effectiveRootUri || !relativePath) return '';
var url = new URL('/api/local-folder/files/open', window.location.origin);
url.searchParams.set('rootUri', effectiveRootUri);
url.searchParams.set('path', relativePath);
if (download) url.searchParams.set('download', 'true');
return url.toString();
}
function fileUriToPath(uri) {
var value = String(uri || '').trim();
if (value.indexOf('file://') !== 0) return '';
try {
var url = new URL(value);
return decodeURIComponent(url.pathname || '');
} catch (_) {
var raw = value.slice('file://'.length);
if (raw.indexOf('localhost/') === 0) raw = raw.slice('localhost'.length);
if (raw.charAt(0) !== '/') raw = '/' + raw;
try { raw = decodeURIComponent(raw); } catch (_) {}
return raw;
}
}
function fileUriFromPath(path) {
var value = String(path || '').trim();
if (!value) return '';
return 'file://' + value.split('/').map(function(part, index) {
return index === 0 ? '' : encodeURIComponent(part);
}).join('/');
}
function localAttachmentOpenParts(rawHref, attachmentRef, paneContext) {
if (attachmentRef && typeof attachmentRef === 'object') {
var refRelativePath = String(attachmentRef.relativePath || '').trim();
if (refRelativePath) {
return {
rootUri: String(attachmentRef.ownerRootUri || currentRootUri() || '').trim(),
relativePath: refRelativePath
};
}
var absolutePath = String(attachmentRef.resolvedAbsolutePath || '').trim()
|| fileUriToPath(attachmentRef.resolvedUri);
if (absolutePath) {
var slash = absolutePath.lastIndexOf('/');
if (slash > 0) {
return {
rootUri: fileUriFromPath(absolutePath.slice(0, slash)),
relativePath: absolutePath.slice(slash + 1)
};
}
}
}
var apiPath = localFileOpenPathFromHref(rawHref);
if (apiPath) {
return {
rootUri: localFileOpenRootUriFromHref(rawHref) || currentRootUri() || '',
relativePath: apiPath
};
}
var markdownPath = localMarkdownAttachmentPathFromHref(rawHref, paneContext && paneContext.documentId);
if (markdownPath) {
return {
rootUri: currentRootUri() || '',
relativePath: markdownPath
};
}
return null;
}
function buildPdfPreviewOpenUrl(fileUrl, fileName) {
if (typeof injectedBuildPdfPreviewOpenUrl === 'function') {
return injectedBuildPdfPreviewOpenUrl(fileUrl, fileName);
@@ -112,24 +228,43 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
}
function setEditorAttachmentUnauthorizedState(link, unauthorized) {
if (!(link instanceof HTMLAnchorElement)) return;
var value = Boolean(unauthorized);
if (value) {
if (link.getAttribute('data-mnote-attachment-unauthorized') === 'true' && link.classList.contains('mnote-uploaded-attachment-unauthorized')) return;
setAttributeIfChanged(link, 'data-mnote-attachment-unauthorized', 'true');
link.classList.add('mnote-uploaded-attachment-unauthorized');
setAttributeIfChanged(link, 'aria-label', (link.textContent || '附件') + '(无权访问)');
} else {
if (link.getAttribute('data-mnote-attachment-unauthorized') !== 'true') return;
link.removeAttribute('data-mnote-attachment-unauthorized');
link.classList.remove('mnote-uploaded-attachment-unauthorized');
if (link.getAttribute('data-mnote-attachment-missing') !== 'true') link.removeAttribute('aria-label');
}
}
function setAttributeIfChanged(element, name, value) {
var nextValue = String(value || '');
if (element.getAttribute(name) === nextValue) return;
element.setAttribute(name, nextValue);
}
function setEditorAttachmentMissingStateByHref(href, missing) {
var targetKey = localFileOpenKeyFromHref(href);
function setEditorAttachmentMissingStateByHref(href, missing, targetKeyOverride) {
var targetKey = String(targetKeyOverride || '').trim() || localFileOpenKeyFromHref(href);
if (!targetKey) return;
if (missing) {
editorAttachmentMissingByKey.set(targetKey, true);
} else {
editorAttachmentMissingByKey.delete(targetKey);
}
document.querySelectorAll('.editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(candidate) {
document.querySelectorAll(editorAttachmentEnhanceSelector + ', .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(candidate) {
if (!(candidate instanceof HTMLAnchorElement)) return;
var candidateHref = candidate.getAttribute('href') || candidate.href || '';
if (localFileOpenKeyFromHref(candidateHref) !== targetKey) return;
var candidateRef = attachmentRefForHref(candidateHref, editorAttachmentPaneContext(candidate), candidate.textContent || '');
var candidateParts = localAttachmentOpenParts(candidateHref, candidateRef, editorAttachmentPaneContext(candidate));
var candidateKey = candidateParts ? String(candidateParts.rootUri || '').trim() + '\n' + String(candidateParts.relativePath || '').trim() : localFileOpenKeyFromHref(candidateHref);
if (candidateKey !== targetKey) return;
setEditorAttachmentMissingState(candidate, missing);
});
}
@@ -137,35 +272,41 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
async function refreshLocalAttachmentExistence(link) {
if (!(link instanceof HTMLAnchorElement)) return;
var href = link.getAttribute('href') || link.href || '';
var attachmentKey = localFileOpenKeyFromHref(href);
var paneContext = editorAttachmentPaneContext(link);
var attachmentRef = attachmentRefForHref(href, paneContext, link ? link.textContent : '');
var openParts = localAttachmentOpenParts(href, attachmentRef, paneContext);
var attachmentKey = openParts ? String(openParts.rootUri || '').trim() + '\n' + String(openParts.relativePath || '').trim() : localFileOpenKeyFromHref(href);
if (!attachmentKey) return;
var refreshSeq = (editorAttachmentRefreshSeqByKey.get(attachmentKey) || 0) + 1;
editorAttachmentRefreshSeqByKey.set(attachmentKey, refreshSeq);
var localFilePath = localFileOpenPathFromHref(href);
var localFilePath = openParts ? openParts.relativePath : localFileOpenPathFromHref(href);
if (!localFilePath) return;
var statusUrl = buildLocalFileStatusUrl(localFilePath, localFileOpenRootUriFromHref(href));
var statusUrl = buildLocalFileStatusUrl(localFilePath, openParts ? openParts.rootUri : 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; });
if (editorAttachmentRefreshSeqByKey.get(attachmentKey) !== refreshSeq) return;
if (!response.ok || !payload || payload.ok !== true || !payload.result) {
setEditorAttachmentStatusErrorByHref(href, String(response.status || 'stat_failed'));
setEditorAttachmentStatusErrorByHref(href, String(response.status || 'stat_failed'), attachmentKey);
return;
}
var exists = Boolean(response.ok && payload && payload.ok === true && payload.result && payload.result.exists === true);
setEditorAttachmentStatusErrorByHref(href, '');
setEditorAttachmentMissingStateByHref(href, !exists);
setEditorAttachmentStatusErrorByHref(href, '', attachmentKey);
setEditorAttachmentMissingStateByHref(href, !exists, attachmentKey);
} catch (_) {}
}
function setEditorAttachmentStatusErrorByHref(href, status) {
var targetKey = localFileOpenKeyFromHref(href);
function setEditorAttachmentStatusErrorByHref(href, status, targetKeyOverride) {
var targetKey = String(targetKeyOverride || '').trim() || localFileOpenKeyFromHref(href);
if (!targetKey) return;
document.querySelectorAll('.editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(candidate) {
document.querySelectorAll(editorAttachmentEnhanceSelector + ', .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(candidate) {
if (!(candidate instanceof HTMLAnchorElement)) return;
var candidateHref = candidate.getAttribute('href') || candidate.href || '';
if (localFileOpenKeyFromHref(candidateHref) !== targetKey) return;
var candidateRef = attachmentRefForHref(candidateHref, editorAttachmentPaneContext(candidate), candidate.textContent || '');
var candidateParts = localAttachmentOpenParts(candidateHref, candidateRef, editorAttachmentPaneContext(candidate));
var candidateKey = candidateParts ? String(candidateParts.rootUri || '').trim() + '\n' + String(candidateParts.relativePath || '').trim() : localFileOpenKeyFromHref(candidateHref);
if (candidateKey !== targetKey) return;
if (status) {
setAttributeIfChanged(candidate, 'data-mnote-attachment-status-error', status);
} else {
@@ -175,15 +316,18 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
function refreshEditorLocalAttachmentExistence() {
document.querySelectorAll('.editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(link) {
document.querySelectorAll(editorAttachmentEnhanceSelector + ', .editor-surface .ProseMirror a[href*="/api/local-folder/files/open"]').forEach(function(link) {
if (link instanceof HTMLAnchorElement) void refreshLocalAttachmentExistence(link);
});
}
window.__mnoteRefreshEditorLocalAttachmentExistence = refreshEditorLocalAttachmentExistence;
var attachmentExistenceRefreshFrame = 0;
function scheduleEditorLocalAttachmentExistenceRefresh() {
[120, 500, 1200].forEach(function(delayMs) {
window.setTimeout(refreshEditorLocalAttachmentExistence, delayMs);
if (attachmentExistenceRefreshFrame) return;
attachmentExistenceRefreshFrame = window.requestAnimationFrame(function() {
attachmentExistenceRefreshFrame = 0;
refreshEditorLocalAttachmentExistence();
});
}
@@ -254,19 +398,57 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
};
}
function currentPageAggregate() {
var script = document.getElementById('__MNOTE_PAGE_AGGREGATE__');
if (!(script instanceof HTMLScriptElement)) return null;
try {
return JSON.parse(script.textContent || 'null');
} catch (_) {
return null;
}
}
function attachmentRefForHref(rawHref, paneContext, label) {
var aggregate = currentPageAggregate();
var refs = Array.isArray(aggregate?.body?.attachmentRefs) ? aggregate.body.attachmentRefs : [];
if (!refs.length) return null;
var href = String(rawHref || '').trim();
var textLabel = String(label || '').trim();
var absoluteHref = '';
try {
absoluteHref = new URL(href, window.location.href).href;
} catch (_) {}
return refs.find(function(ref) {
if (!ref || typeof ref !== 'object') return false;
return String(ref.rawHref || '') === href
|| String(ref.normalizedHref || '') === href
|| String(ref.resolvedUri || '') === href
|| (absoluteHref && String(ref.resolvedUri || '') === absoluteHref)
|| (!href && textLabel && String(ref.label || '').trim() === textLabel);
}) || null;
}
function detailFromEditorAttachmentLink(link) {
var rawHref = link instanceof HTMLAnchorElement ? link.href : '';
var rawHref = link instanceof HTMLAnchorElement ? (link.getAttribute('href') || '') : '';
var params = attachmentQueryParams(rawHref);
var paneContext = editorAttachmentPaneContext(link);
var localFilePath = localFileOpenPathFromHref(rawHref);
var fileName = params.get('fileName') || fileNameFromPath(localFilePath) || (link ? link.textContent : '') || '未命名附件';
var fileType = params.get('fileType') || inferOnlyOfficeFileType(fileName, '');
var attachmentRef = attachmentRefForHref(rawHref, paneContext, link ? link.textContent : '');
if (!rawHref && attachmentRef) rawHref = String(attachmentRef.rawHref || attachmentRef.normalizedHref || attachmentRef.resolvedUri || '').trim();
var openParts = localAttachmentOpenParts(rawHref, attachmentRef, paneContext);
var localFilePath = openParts && openParts.relativePath ? openParts.relativePath : (
String(attachmentRef?.relativePath || '').trim()
|| localFileOpenPathFromHref(rawHref)
|| localMarkdownAttachmentPathFromHref(rawHref, paneContext.documentId)
);
var localRootUri = openParts && openParts.rootUri ? openParts.rootUri : currentRootUri();
var fileName = params.get('fileName') || String(attachmentRef?.label || '').trim() || fileNameFromPath(localFilePath) || (link ? link.textContent : '') || '未命名附件';
var fileType = params.get('fileType') || inferOnlyOfficeFileType(fileName, '') || String(attachmentRef?.ext || '').trim();
var assetId = params.get('assetId') || (link ? link.getAttribute('data-asset-id') : '') || (localFilePath ? 'local-file:' + localFilePath : '');
var fileUrl = params.get('fileUrl') || '';
var fileUrl = params.get('fileUrl') || (localFilePath ? buildLocalFileOpenUrlForRoot(localFilePath, localRootUri, false) : '') || String(attachmentRef?.resolvedUri || '').trim();
var documentId = params.get('documentId') || paneContext.documentId || '';
var href = rawHref;
if (!isOnlyOfficeAttachmentHref(rawHref) && fileType) {
fileUrl = rawHref;
fileUrl = localFilePath ? buildLocalFileOpenUrlForRoot(localFilePath, localRootUri, false) : rawHref;
href = buildOnlyOfficeOpenUrl({
fileUrl: fileUrl,
fileName: fileName,
@@ -289,33 +471,53 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
documentId: documentId,
workspaceId: paneContext.workspaceId,
paneRole: paneContext.paneRole,
fileSize: (link ? link.getAttribute('data-file-size') : '') || ''
localRootUri: localRootUri,
localRelativePath: localFilePath,
fileSize: (link ? link.getAttribute('data-file-size') : '') || '',
attachmentRef: attachmentRef || null,
authorized: typeof attachmentRef?.authorized === 'boolean' ? attachmentRef.authorized : null,
exists: typeof attachmentRef?.exists === 'boolean' ? attachmentRef.exists : null,
openKind: String(attachmentRef?.openKind || '').trim()
};
}
function enhanceEditorAttachmentLink(link) {
if (!(link instanceof HTMLAnchorElement)) return;
var href = link.getAttribute('href') || '';
var params = attachmentQueryParams(href);
var localFilePath = localFileOpenPathFromHref(href);
var paneContext = editorAttachmentPaneContext(link);
var fileName = params.get('fileName') || fileNameFromPath(localFilePath) || link.textContent || '';
var attachmentRef = attachmentRefForHref(href, paneContext, link ? link.textContent : '');
if (!href && attachmentRef) href = String(attachmentRef.rawHref || attachmentRef.normalizedHref || attachmentRef.resolvedUri || '').trim();
var openParts = localAttachmentOpenParts(href, attachmentRef, paneContext);
var localFilePath = openParts && openParts.relativePath ? openParts.relativePath : (localFileOpenPathFromHref(href) || localMarkdownAttachmentPathFromHref(href, paneContext.documentId));
var resolvedPathName = fileNameFromPath(localFilePath || fileUriToPath(attachmentRef && attachmentRef.resolvedUri));
var fileName = params.get('fileName') || resolvedPathName || link.textContent || '';
var className = link.getAttribute('class') || '';
var shouldEnhance = isOnlyOfficeAttachmentHref(href)
|| className.indexOf('mnote-uploaded-attachment-row') >= 0
|| isOfficeFileName(fileName)
|| Boolean(localFilePath);
if (!shouldEnhance) return;
setAttributeIfChanged(link, 'data-mnote-attachment-link', 'true');
var assetId = params.get('assetId') || link.getAttribute('data-asset-id') || (localFilePath ? 'local-file:' + localFilePath : '');
if (assetId) setAttributeIfChanged(link, 'data-asset-id', assetId);
attachmentClassForFileName(fileName).split(/\s+/).forEach(function(name) {
if (name) link.classList.add(name);
});
if (attachmentRef && typeof attachmentRef === 'object') {
if (typeof attachmentRef.exists === 'boolean') {
setEditorAttachmentMissingState(link, attachmentRef.exists === false);
}
if (typeof attachmentRef.authorized === 'boolean') {
setEditorAttachmentUnauthorizedState(link, attachmentRef.authorized === false);
}
}
setAttributeIfChanged(link, 'target', '_blank');
setAttributeIfChanged(link, 'rel', 'noopener noreferrer nofollow');
if (localFilePath && !isOnlyOfficeAttachmentHref(href)) {
setEditorAttachmentMissingState(link, editorAttachmentMissingByKey.has(localFileOpenKeyFromHref(href)));
var localAttachmentKey = openParts
? String(openParts.rootUri || '').trim() + '\n' + String(openParts.relativePath || '').trim()
: localFileOpenKeyFromHref(href);
var isProjectionMissing = typeof attachmentRef?.exists === 'boolean' && attachmentRef.exists === false;
setEditorAttachmentMissingState(link, isProjectionMissing || editorAttachmentMissingByKey.has(localAttachmentKey));
void refreshLocalAttachmentExistence(link);
return;
}
@@ -334,26 +536,12 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
function enhanceEditorAttachmentLinks() {
document.querySelectorAll('.editor-surface .ProseMirror a[href]').forEach(enhanceEditorAttachmentLink);
void healLegacyOfficeAttachmentParagraphs();
document.querySelectorAll(editorAttachmentEnhanceSelector).forEach(enhanceEditorAttachmentLink);
}
window.__mnoteEnhanceEditorAttachmentLinks = function() {
observeEditorAttachmentRoots();
enhanceEditorAttachmentLinks();
};
var attachmentInitialEnhanceAttempts = 0;
var attachmentInitialEnhanceTimer = window.setInterval(function() {
attachmentInitialEnhanceAttempts += 1;
enhanceEditorAttachmentLinks();
if (attachmentInitialEnhanceAttempts >= 120) window.clearInterval(attachmentInitialEnhanceTimer);
}, 500);
var attachmentExistenceRefreshTimer = window.setInterval(function() {
refreshEditorLocalAttachmentExistence();
}, 2500);
window.addEventListener('beforeunload', function() {
if (attachmentExistenceRefreshTimer) window.clearInterval(attachmentExistenceRefreshTimer);
attachmentExistenceRefreshTimer = 0;
});
var lastEditorAttachmentMouseOpen = { at: 0, href: '' };
function ensureAttachmentActions() {
@@ -394,25 +582,53 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
async function openEditorAttachmentDetail(detail) {
if (!detail || !detail.href) return;
var localFilePath = localFilePathFromAssetId(detail.assetId);
if (!detail) return;
if (detail.authorized === false) {
document.documentElement.setAttribute('data-mnote-attachment-open-blocked', 'unauthorized');
return;
}
if (detail.exists === false) {
document.documentElement.setAttribute('data-mnote-attachment-open-blocked', 'missing');
return;
}
if (!detail.href) return;
document.documentElement.removeAttribute('data-mnote-attachment-open-blocked');
var localFilePath = localFilePathFromAssetId(detail.assetId) || String(detail.localRelativePath || '').trim();
if (localFilePath) {
if (await openLocalOfficeFileInActiveTab(detail, 'view')) return;
var localRootUri = String(detail.localRootUri || currentRootUri() || '').trim();
if (!detail.localRootUri && await openLocalOfficeFileInActiveTab(detail, 'view')) return;
var localFileName = detail.fileName || localFilePath.split('/').pop() || localFilePath;
var localFileUrl = buildLocalFileOpenUrl(localFilePath, false);
var localFileUrl = buildLocalFileOpenUrlForRoot(localFilePath, localRootUri, false);
var localOpenUrl = isPdfAttachmentFileName(localFileName) ? buildPdfPreviewOpenUrl(localFileUrl, localFileName) : localFileUrl;
var localOfficeType = inferOnlyOfficeFileType(localFileName, '');
var localOfficeUrl = localOfficeType
? buildOnlyOfficeOpenUrl({
fileUrl: localFileUrl,
fileName: localFileName,
fileType: localOfficeType,
assetId: detail.assetId || ('local-file:' + localFilePath),
documentId: detail.documentId || currentDocumentId() || '',
userId: '',
mode: 'view',
workspaceId: detail.workspaceId || resolveWorkspaceId(document.body) || '',
sourceKind: 'local_folder',
rootUri: localRootUri
})
: '';
// 非 Office 本地文件:用对应图标类型打开 active tab,失败则新窗口
void openLocalResourceInActiveTab({
path: localFilePath,
title: localFileName,
kind: fileTreeIconKindForFileName(localFileName),
kind: localOfficeType ? 'office' : fileTreeIconKindForFileName(localFileName),
assetId: detail.assetId,
documentId: detail.documentId || currentDocumentId() || '',
workspaceId: detail.workspaceId || resolveWorkspaceId(document.body) || '',
href: localOpenUrl,
officeUrl: localOfficeUrl,
rootUri: localRootUri,
paneRole: detail.paneRole || 'primary'
}).then(function(opened) {
if (!opened) window.open(localOpenUrl || detail.href, '_blank', 'noopener,noreferrer');
if (!opened) window.open(localOfficeUrl || localOpenUrl || detail.href, '_blank', 'noopener,noreferrer');
});
return;
}
@@ -631,9 +847,9 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
async function openEditorAttachmentDownload(detail) {
if (!detail) return;
var localFilePath = localFilePathFromAssetId(detail.assetId);
var localFilePath = localFilePathFromAssetId(detail.assetId) || String(detail.localRelativePath || '').trim();
if (localFilePath) {
var localDownloadUrl = buildLocalFileOpenUrl(localFilePath, true);
var localDownloadUrl = buildLocalFileOpenUrlForRoot(localFilePath, detail.localRootUri || currentRootUri(), true);
if (localDownloadUrl) {
triggerBrowserDownload(localDownloadUrl);
return;
@@ -693,8 +909,8 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
}
function addedNodeMayContainEditorAttachmentLink(node) {
return node instanceof HTMLElement && (
node.matches('.editor-surface .ProseMirror, .editor-surface .ProseMirror a[href], .editor-surface .ProseMirror p, .editor-surface .ProseMirror span, .editor-surface .ProseMirror div')
|| node.querySelector?.('.editor-surface .ProseMirror, .editor-surface .ProseMirror a[href]')
node.matches('.editor-surface .ProseMirror, .editor-surface .ProseMirror a[href], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row, .editor-surface .ProseMirror p, .editor-surface .ProseMirror span, .editor-surface .ProseMirror div')
|| node.querySelector?.('.editor-surface .ProseMirror, .editor-surface .ProseMirror a[href], .editor-surface .ProseMirror a.mnote-uploaded-attachment-row')
);
}
function observeEditorAttachmentRoots() {
@@ -706,10 +922,34 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
attachmentEditorObserver.observe(editor, { childList: true, subtree: true });
});
}
var attachmentAggregateObserver = null;
var attachmentObservedAggregateScript = null;
function observePageAggregateScript() {
if (typeof MutationObserver !== 'function') return;
var script = document.getElementById('__MNOTE_PAGE_AGGREGATE__');
if (!(script instanceof HTMLScriptElement)) return;
if (script === attachmentObservedAggregateScript) return;
if (attachmentAggregateObserver) attachmentAggregateObserver.disconnect();
attachmentObservedAggregateScript = script;
attachmentAggregateObserver = new MutationObserver(function() {
scheduleEditorAttachmentEnhance();
scheduleEditorLocalAttachmentExistenceRefresh();
});
attachmentAggregateObserver.observe(script, {
attributes: true,
characterData: true,
childList: true,
subtree: true
});
}
attachmentEditorObserver = new MutationObserver(function(records) {
var shouldEnhance = Array.isArray(records) && records.some(function(record) {
if (!record || record.type !== 'childList') return false;
return Array.from(record.addedNodes || []).some(function(node) {
if (node instanceof HTMLElement && node.id === '__MNOTE_PAGE_AGGREGATE__') {
observePageAggregateScript();
return true;
}
return addedNodeMayContainEditorAttachmentLink(node);
});
});
@@ -718,10 +958,21 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
});
attachmentEditorObserver.observe(document.documentElement, { childList: true, subtree: true });
observeEditorAttachmentRoots();
observePageAggregateScript();
window.addEventListener('mnote:editor-attachment-links-changed', function() {
window.__mnoteEnhanceEditorAttachmentLinks();
scheduleEditorAttachmentEnhance();
});
window.addEventListener('mnote:page-aggregate-synced', function() {
window.__mnoteEnhanceEditorAttachmentLinks();
scheduleEditorAttachmentEnhance();
scheduleEditorLocalAttachmentExistenceRefresh();
});
window.addEventListener('mnote:primary-document-activated', function() {
window.__mnoteEnhanceEditorAttachmentLinks();
scheduleEditorAttachmentEnhance();
scheduleEditorLocalAttachmentExistenceRefresh();
});
window.addEventListener('tree:delta', scheduleEditorLocalAttachmentExistenceRefresh);
window.addEventListener('tree:resync', scheduleEditorLocalAttachmentExistenceRefresh);
[
@@ -732,18 +983,8 @@ export const createSidebarAttachmentOpenRuntime = (dependencies = {}) => {
window.addEventListener(eventName, function() {
enhanceEditorAttachmentLinks();
observeEditorAttachmentRoots();
window.setTimeout(function() {
enhanceEditorAttachmentLinks();
observeEditorAttachmentRoots();
}, 120);
}, true);
});
[120, 500, 1200, 2500].forEach(function(delayMs) {
window.setTimeout(function() {
enhanceEditorAttachmentLinks();
observeEditorAttachmentRoots();
}, delayMs);
});
function interceptEditorAttachmentLink(event) {
var editorAttachmentLink = closestAction(event.target, editorAttachmentLinkSelector);