fix local markdown attachment regressions
This commit is contained in:
@@ -363,27 +363,77 @@ export const mergeClassNames = (...values) => {
|
||||
|
||||
export const localAttachmentClassForTiptapHref = (href) => {
|
||||
const localFilePath = localFileOpenPathFromTiptapHref(href);
|
||||
return localFilePath ? attachmentClassForFileName(fileNameFromPath(localFilePath)) : '';
|
||||
if (localFilePath) return attachmentClassForFileName(fileNameFromPath(localFilePath));
|
||||
const value = String(href || '').trim();
|
||||
if (!value || isExternalOrSpecialUrl(value)) return '';
|
||||
if (value.startsWith('../') || value.includes('/../')) return '';
|
||||
return attachmentClassForFileName(fileNameFromPath(value));
|
||||
};
|
||||
|
||||
const attachmentRefsFromContext = (context) => {
|
||||
if (Array.isArray(context?.attachmentRefs)) return context.attachmentRefs;
|
||||
if (Array.isArray(context?.attachment_refs)) return context.attachment_refs;
|
||||
if (Array.isArray(context?.body?.attachmentRefs)) return context.body.attachmentRefs;
|
||||
if (Array.isArray(context?.body?.attachment_refs)) return context.body.attachment_refs;
|
||||
if (Array.isArray(context?.latestAggregate?.body?.attachmentRefs)) return context.latestAggregate.body.attachmentRefs;
|
||||
if (Array.isArray(context?.latestAggregate?.body?.attachment_refs)) return context.latestAggregate.body.attachment_refs;
|
||||
if (Array.isArray(context?.aggregate?.body?.attachmentRefs)) return context.aggregate.body.attachmentRefs;
|
||||
if (Array.isArray(context?.aggregate?.body?.attachment_refs)) return context.aggregate.body.attachment_refs;
|
||||
return [];
|
||||
};
|
||||
|
||||
const attachmentRefForTiptapHref = (href, context) => {
|
||||
const value = String(href || '').trim();
|
||||
if (!value) return null;
|
||||
return attachmentRefsFromContext(context).find((ref) => (
|
||||
ref && typeof ref === 'object' && (
|
||||
String(ref.rawHref || '') === value
|
||||
|| String(ref.normalizedHref || '') === value
|
||||
|| String(ref.resolvedUri || '') === value
|
||||
)
|
||||
)) || null;
|
||||
};
|
||||
|
||||
const withAttachmentProjectionAttrs = (attrs, attachmentRef) => {
|
||||
if (!attachmentRef || typeof attachmentRef !== 'object') return attrs;
|
||||
const next = { ...attrs };
|
||||
if (attachmentRef.exists === false) {
|
||||
next.class = mergeClassNames(next.class, 'mnote-uploaded-attachment-missing');
|
||||
next['data-mnote-attachment-missing'] = 'true';
|
||||
next['aria-label'] = `${String(attachmentRef.label || '附件')}(文件不存在)`;
|
||||
}
|
||||
if (attachmentRef.authorized === false) {
|
||||
next.class = mergeClassNames(next.class, 'mnote-uploaded-attachment-unauthorized');
|
||||
next['data-mnote-attachment-unauthorized'] = 'true';
|
||||
next['aria-label'] = `${String(attachmentRef.label || '附件')}(无权访问)`;
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
export const localizeTiptapAssetUrls = (node, context) => {
|
||||
if (!node || typeof node !== 'object') return node;
|
||||
if (node.type === 'image' && node.attrs && typeof node.attrs.src === 'string') {
|
||||
node.attrs = { ...node.attrs, src: localFileOpenUrlForTiptap(node.attrs.src, context) };
|
||||
const originalSrc = String(node.attrs.src || '').trim();
|
||||
node.attrs = {
|
||||
...node.attrs,
|
||||
src: localFileOpenUrlForTiptap(originalSrc, context),
|
||||
mnoteMarkdownSrc: node.attrs.mnoteMarkdownSrc || originalSrc,
|
||||
};
|
||||
}
|
||||
if (Array.isArray(node.marks)) {
|
||||
node.marks = node.marks.map((mark) => {
|
||||
if (!mark || mark.type !== 'link' || !mark.attrs || typeof mark.attrs.href !== 'string') return mark;
|
||||
const href = localFileOpenUrlForTiptap(mark.attrs.href, context);
|
||||
const href = String(mark.attrs.href || '').trim();
|
||||
const attachmentClass = localAttachmentClassForTiptapHref(href);
|
||||
const attachmentRef = attachmentRefForTiptapHref(href, context);
|
||||
const attrs = attachmentClass
|
||||
? {
|
||||
? withAttachmentProjectionAttrs({
|
||||
...mark.attrs,
|
||||
href,
|
||||
class: mergeClassNames(mark.attrs.class, attachmentClass),
|
||||
target: mark.attrs.target || '_blank',
|
||||
rel: mark.attrs.rel || 'noopener noreferrer nofollow',
|
||||
}
|
||||
}, attachmentRef)
|
||||
: { ...mark.attrs, href };
|
||||
return { ...mark, attrs };
|
||||
});
|
||||
@@ -405,12 +455,13 @@ export const pageBodyTiptapDocumentSource = (body, fallbackText = '') => {
|
||||
};
|
||||
|
||||
export const pageBodyTiptapDocument = (body, fallbackText = '', context = null) => {
|
||||
const projectionContext = { ...(context || {}), body };
|
||||
if (pageBodyTiptapDocumentSource(body, fallbackText) === 'local_markdown.content') {
|
||||
return localizeTiptapAssetUrls(toTiptapDocument(body.content, fallbackText), context);
|
||||
return localizeTiptapAssetUrls(toTiptapDocument(body.content, fallbackText), projectionContext);
|
||||
}
|
||||
const blockDocument = body?.blockDocument || body?.block_document || body?.editorDocument || body?.editor_document || null;
|
||||
if (blockDocument) return localizeTiptapAssetUrls(toTiptapDocument(blockDocument, fallbackText), context);
|
||||
return localizeTiptapAssetUrls(toTiptapDocument(body?.content, fallbackText), context);
|
||||
if (blockDocument) return localizeTiptapAssetUrls(toTiptapDocument(blockDocument, fallbackText), projectionContext);
|
||||
return localizeTiptapAssetUrls(toTiptapDocument(body?.content, fallbackText), projectionContext);
|
||||
};
|
||||
|
||||
export const inlineTextNodes = (node) => {
|
||||
@@ -524,7 +575,7 @@ export const tiptapNodeToEditorBlock = (node, index) => {
|
||||
if (node?.type === 'blockquote') return { blockId, blockType: 'quote', props: {}, contentNodes: inlineTextNodes(firstChild(node)), childBlockIds: [] };
|
||||
if (node?.type === 'codeBlock') return { blockId, blockType: 'code_block', props: { language: typeof node?.attrs?.language === 'string' ? node.attrs.language : null }, contentNodes: inlineTextNodes(node), childBlockIds: [] };
|
||||
if (node?.type === 'horizontalRule') return { blockId, blockType: 'divider', props: {}, contentNodes: [], childBlockIds: [] };
|
||||
if (node?.type === 'image') return { blockId, blockType: 'image', props: { src: node?.attrs?.src || '', alt: node?.attrs?.alt || null, title: node?.attrs?.title || null, tiptapImage: node }, contentNodes: [], childBlockIds: [] };
|
||||
if (node?.type === 'image') return { blockId, blockType: 'image', props: { src: node?.attrs?.mnoteMarkdownSrc || node?.attrs?.src || '', alt: node?.attrs?.alt || null, title: node?.attrs?.title || null, tiptapImage: node }, contentNodes: [], childBlockIds: [] };
|
||||
if (node?.type === 'tocNode') return { blockId, blockType: 'toc', props: { tiptapTocNode: node }, contentNodes: [], childBlockIds: [] };
|
||||
if (node?.type === 'table') return { blockId, blockType: 'table', props: { tiptapTable: node }, contentNodes: inlineTextNodes(node), childBlockIds: [] };
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user