269 lines
13 KiB
JavaScript
269 lines
13 KiB
JavaScript
// MNote 本地上传运行时外置模块。
|
||
// 当前先承接 SIDEBAR_TREE_JS 中的纯辅助函数。
|
||
// SIDEBAR_TREE_JS 会优先委托到 window.__mnoteLocalUploadRuntime;
|
||
// 模块未加载时,inline fallback 保持旧行为。
|
||
|
||
function uploadedAssetTitle(asset) {
|
||
return String(asset && (asset.file_name || asset.title || asset.name) || '未命名附件').trim() || '未命名附件';
|
||
}
|
||
|
||
function uploadedAssetUrl(asset) {
|
||
return String(asset && (asset.sourcePath || asset.file_url || asset.signedUrl || asset.signed_url || asset.thumbnail_url) || '').trim();
|
||
}
|
||
|
||
function currentRootUri() {
|
||
var params = new URLSearchParams(window.location.search);
|
||
var fromUrl = (params.get('rootUri') || '').trim();
|
||
if (fromUrl) return fromUrl;
|
||
return document.body instanceof HTMLElement
|
||
? (document.body.getAttribute('data-mnote-root-uri') || '').trim()
|
||
: '';
|
||
}
|
||
|
||
function editorUploadRootFromElementWithDeps(target, deps) {
|
||
if (deps && typeof deps.editorUploadRootFromElement === 'function') {
|
||
return deps.editorUploadRootFromElement(target);
|
||
}
|
||
if (!(target instanceof Element)) return null;
|
||
var selector = String(deps && deps.rootSelector || '[data-editor-host-kind="leptos_tiptap_island"], [data-editor-host-kind="leptos_tiptap_resource"]');
|
||
var root = target.closest(selector);
|
||
return root instanceof HTMLElement ? root : null;
|
||
}
|
||
|
||
function resolveEditorUploadContext(detail, deps) {
|
||
var root = null;
|
||
var selector = detail && detail.editorRootSelector ? String(detail.editorRootSelector) : '';
|
||
if (selector) {
|
||
try {
|
||
var selected = document.querySelector(selector);
|
||
if (selected instanceof HTMLElement) root = selected;
|
||
} catch (_) {}
|
||
}
|
||
if (!root && window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) {
|
||
root = window.__mnoteIntendedSlashRoot;
|
||
}
|
||
if (!root && window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) {
|
||
root = window.__mnoteLastEditorUploadRoot;
|
||
}
|
||
if (!root && document.activeElement instanceof Element) {
|
||
root = editorUploadRootFromElementWithDeps(document.activeElement, deps);
|
||
}
|
||
if (!root) {
|
||
var rootSelector = String(deps && deps.rootSelector || '[data-editor-host-kind="leptos_tiptap_island"], [data-editor-host-kind="leptos_tiptap_resource"]');
|
||
var focused = document.querySelector(rootSelector + ' .ProseMirror:focus-within');
|
||
root = editorUploadRootFromElementWithDeps(focused, deps);
|
||
}
|
||
if (!root) {
|
||
root = document.querySelector('[data-editor-host-kind="leptos_tiptap_island"][data-pane-role="primary"]');
|
||
}
|
||
var pane = root instanceof Element ? root.closest('.document-pane[data-pane-role]') : null;
|
||
var shell = root instanceof Element ? root.closest('.document-shell[data-document-id]') : null;
|
||
var currentDocumentId = deps && typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
|
||
var resolveWorkspaceId = deps && typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
|
||
return {
|
||
root: root instanceof HTMLElement ? root : null,
|
||
documentId: String(
|
||
detail && detail.documentId
|
||
|| (root instanceof HTMLElement && root.getAttribute('data-document-id'))
|
||
|| (pane instanceof HTMLElement && pane.getAttribute('data-pane-document-id'))
|
||
|| (shell instanceof HTMLElement && shell.getAttribute('data-document-id'))
|
||
|| currentDocumentId()
|
||
|| ''
|
||
).trim(),
|
||
workspaceId: String(
|
||
detail && detail.workspaceId
|
||
|| (root instanceof HTMLElement && root.getAttribute('data-workspace-id'))
|
||
|| (pane instanceof HTMLElement && pane.getAttribute('data-pane-workspace-id'))
|
||
|| (shell instanceof HTMLElement && shell.getAttribute('data-workspace-id'))
|
||
|| resolveWorkspaceId(document.body)
|
||
|| ''
|
||
).trim()
|
||
};
|
||
}
|
||
|
||
function editorRootFromUploadOptions(options, deps) {
|
||
if (options && options.editorRoot instanceof HTMLElement) return options.editorRoot;
|
||
if (window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) {
|
||
return window.__mnoteIntendedSlashRoot;
|
||
}
|
||
if (window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) {
|
||
return window.__mnoteLastEditorUploadRoot;
|
||
}
|
||
var rootSelector = String(deps && deps.rootSelector || '[data-editor-host-kind="leptos_tiptap_island"], [data-editor-host-kind="leptos_tiptap_resource"]');
|
||
var focused = document.querySelector(rootSelector + ' .ProseMirror:focus-within');
|
||
return editorUploadRootFromElementWithDeps(focused, deps);
|
||
}
|
||
|
||
function openEditorUploadFilePicker(detail, deps) {
|
||
var uploadContext = resolveEditorUploadContext(detail || {}, deps || {});
|
||
var input = document.createElement('input');
|
||
input.type = 'file';
|
||
input.multiple = detail && detail.multiple !== false;
|
||
if (detail && detail.accept) input.accept = String(detail.accept);
|
||
input.style.position = 'fixed';
|
||
input.style.left = '-9999px';
|
||
input.style.top = '-9999px';
|
||
document.body.appendChild(input);
|
||
input.addEventListener('change', function() {
|
||
var files = Array.from(input.files || []);
|
||
input.remove();
|
||
var resolveWorkspaceId = deps && typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
|
||
var currentDocumentId = deps && typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
|
||
var uploadFilesWithResolvedTarget = deps && typeof deps.uploadFilesWithResolvedTarget === 'function' ? deps.uploadFilesWithResolvedTarget : null;
|
||
if (!uploadFilesWithResolvedTarget) return;
|
||
void uploadFilesWithResolvedTarget(files, {
|
||
workspaceId: uploadContext.workspaceId || resolveWorkspaceId(document.body),
|
||
documentId: uploadContext.documentId || currentDocumentId(),
|
||
targetRowId: null,
|
||
uploadIntent: 'editor.markdown.attach'
|
||
}, {
|
||
insertIntoEditor: detail && detail.insertIntoEditor !== false,
|
||
editorRoot: uploadContext.root
|
||
});
|
||
}, { once: true });
|
||
input.click();
|
||
}
|
||
|
||
function localAssetOpenUrl(asset, download, context) {
|
||
if (!isLocalUploadedAsset(asset)) return '';
|
||
var rootUri = String(context && context.rootUri || asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
|
||
var rootRelativePath = String(asset && (asset.rootRelativePath || asset.root_relative_path) || '').trim();
|
||
if (!rootUri || !rootRelativePath) return '';
|
||
var url = new URL('/api/local-folder/files/open', window.location.origin);
|
||
url.searchParams.set('rootUri', rootUri);
|
||
url.searchParams.set('path', rootRelativePath);
|
||
if (download) url.searchParams.set('download', 'true');
|
||
return url.toString();
|
||
}
|
||
|
||
function uploadedAssetType(asset) {
|
||
return String(asset && (asset.asset_type || asset.assetType || asset.mime_type || '') || '').trim();
|
||
}
|
||
|
||
function fileTreeIconKindForFileName(fileName) {
|
||
var name = String(fileName || '').trim().toLowerCase();
|
||
var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||
if (['doc', 'docx', 'odt', 'rtf', 'ppt', 'pptx', 'odp', 'xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'office';
|
||
if (ext === 'md' || ext === 'markdown') return 'markdown';
|
||
if (ext === 'pdf') return 'pdf';
|
||
if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp'].indexOf(ext) >= 0) return 'image';
|
||
return '';
|
||
}
|
||
|
||
function isLocalUploadedAsset(asset) {
|
||
var id = String(asset && asset.id || '').trim();
|
||
return String(asset && asset.sourceKind || '').trim() === 'local_folder' || id.indexOf('local:asset:') === 0;
|
||
}
|
||
|
||
function uploadedAssetExtension(asset) {
|
||
var match = uploadedAssetTitle(asset).toLowerCase().match(/\.([a-z0-9]+)$/);
|
||
return match ? match[1] : '';
|
||
}
|
||
|
||
function isNonOfficeAttachmentName(name, ext) {
|
||
var codeFileNames = [
|
||
'.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc',
|
||
'dockerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'
|
||
];
|
||
return [
|
||
'pdf', 'toml', 'json', 'yaml', 'yml', 'md', 'markdown', 'txt', 'ini', 'env', 'xml', 'html', 'htm', 'css', 'scss',
|
||
'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs',
|
||
'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lock', 'log', 'vue', 'svelte', 'astro', 'jsonc', 'json5',
|
||
'mts', 'cts', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj',
|
||
'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd',
|
||
'psm1', 'psd1', 'dockerfile', 'containerfile', 'proto', 'graphql', 'gql', 'prisma', 'tf', 'tfvars',
|
||
'hcl', 'nix', 'cmake', 'bazel', 'bzl', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop',
|
||
'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc'
|
||
].indexOf(ext) >= 0 || codeFileNames.indexOf(name) >= 0;
|
||
}
|
||
|
||
function attachmentExtensionFromFileName(fileName) {
|
||
var name = String(fileName || '').trim().toLowerCase();
|
||
return name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||
}
|
||
|
||
function isPdfAttachmentFileName(fileName) {
|
||
return attachmentExtensionFromFileName(fileName) === 'pdf';
|
||
}
|
||
|
||
function isCodeAttachmentFileName(fileName) {
|
||
var name = String(fileName || '').trim().toLowerCase();
|
||
var ext = attachmentExtensionFromFileName(name);
|
||
return ext !== 'pdf' && isNonOfficeAttachmentName(name, ext);
|
||
}
|
||
|
||
function inferCodeAttachmentLanguage(fileName) {
|
||
var name = String(fileName || '').trim().toLowerCase();
|
||
var ext = attachmentExtensionFromFileName(name);
|
||
var byName = {
|
||
'dockerfile': 'dockerfile',
|
||
'makefile': 'makefile',
|
||
'cmakelists.txt': 'cmake',
|
||
'.gitignore': 'gitignore',
|
||
'.gitattributes': 'gitattributes',
|
||
'.editorconfig': 'ini',
|
||
'.env': 'dotenv'
|
||
};
|
||
if (byName[name]) return byName[name];
|
||
var byExt = {
|
||
bash: 'bash', bat: 'batch', c: 'c', cjs: 'javascript', cmd: 'batch', conf: 'text', cpp: 'cpp',
|
||
cs: 'csharp', css: 'css', cts: 'typescript', dart: 'dart', dockerfile: 'dockerfile', env: 'dotenv',
|
||
go: 'go', gql: 'graphql', gradle: 'groovy', graphql: 'graphql', h: 'c', hcl: 'hcl', hpp: 'cpp',
|
||
htm: 'html', html: 'html', ini: 'ini', java: 'java', js: 'javascript', json: 'json', json5: 'json',
|
||
jsonc: 'jsonc', jsx: 'javascript', kt: 'kotlin', kts: 'kotlin', less: 'less', log: 'text',
|
||
lua: 'lua', m: 'objective-c', markdown: 'markdown', md: 'markdown', mjs: 'javascript',
|
||
mts: 'typescript', nix: 'nix', php: 'php', pl: 'perl', pm: 'perl', prisma: 'prisma',
|
||
proto: 'protobuf', ps1: 'powershell', py: 'python', r: 'r', rb: 'ruby', rs: 'rust',
|
||
scss: 'scss', sh: 'bash', sql: 'sql', svelte: 'svelte', swift: 'swift', tf: 'terraform',
|
||
tfvars: 'terraform', toml: 'toml', ts: 'typescript', tsx: 'typescript', txt: 'text',
|
||
vue: 'vue', xml: 'xml', yaml: 'yaml', yml: 'yaml', zsh: 'bash'
|
||
};
|
||
return byExt[ext] || 'text';
|
||
}
|
||
|
||
function attachmentClassForFileName(fileName) {
|
||
var name = String(fileName || '').trim().toLowerCase();
|
||
var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||
if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-word';
|
||
if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-ppt';
|
||
if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-sheet';
|
||
if (ext === 'pdf') return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-pdf';
|
||
if (isNonOfficeAttachmentName(name, ext)) {
|
||
return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-code';
|
||
}
|
||
return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-file';
|
||
}
|
||
|
||
function uploadedAttachmentClass(asset) {
|
||
return attachmentClassForFileName(uploadedAssetTitle(asset));
|
||
}
|
||
|
||
function uploadedFileSize(asset) {
|
||
var size = Number(asset && (asset.file_size || asset.fileSize) || 0);
|
||
if (!Number.isFinite(size) || size <= 0) return '';
|
||
if (size >= 1024 * 1024) return (size / 1024 / 1024).toFixed(size >= 10 * 1024 * 1024 ? 1 : 2) + ' MB';
|
||
if (size >= 1024) return (size / 1024).toFixed(size >= 100 * 1024 ? 0 : 2) + ' KB';
|
||
return String(Math.round(size)) + ' B';
|
||
}
|
||
|
||
window.__mnoteLocalUploadRuntime = {
|
||
uploadedAssetTitle: uploadedAssetTitle,
|
||
uploadedAssetUrl: uploadedAssetUrl,
|
||
resolveEditorUploadContext: resolveEditorUploadContext,
|
||
editorRootFromUploadOptions: editorRootFromUploadOptions,
|
||
openEditorUploadFilePicker: openEditorUploadFilePicker,
|
||
localAssetOpenUrl: localAssetOpenUrl,
|
||
uploadedAssetType: uploadedAssetType,
|
||
fileTreeIconKindForFileName: fileTreeIconKindForFileName,
|
||
isLocalUploadedAsset: isLocalUploadedAsset,
|
||
uploadedAssetExtension: uploadedAssetExtension,
|
||
isNonOfficeAttachmentName: isNonOfficeAttachmentName,
|
||
attachmentExtensionFromFileName: attachmentExtensionFromFileName,
|
||
isPdfAttachmentFileName: isPdfAttachmentFileName,
|
||
isCodeAttachmentFileName: isCodeAttachmentFileName,
|
||
inferCodeAttachmentLanguage: inferCodeAttachmentLanguage,
|
||
attachmentClassForFileName: attachmentClassForFileName,
|
||
uploadedAttachmentClass: uploadedAttachmentClass,
|
||
uploadedFileSize: uploadedFileSize
|
||
};
|