refactor: delegate uploaded asset insertion runtime
This commit is contained in:
@@ -83,3 +83,7 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据
|
||||
- `reasonix-2026-05-24T17-07-59-638Z-29274a46` 产生 handoff,但内容串到 Worker B 的 block menu 任务,worktree 无 diff,拒绝采纳。
|
||||
- `reasonix-2026-05-24T17-12-41-044Z-25b9d5d7` 仅产生 `prompt.md` / `memory-recall.json` / `reasonix-transcript.jsonl`,无 `final.md`、`result.json`、`process-handoff.md/json`,worktree 无 diff,拒绝采纳。
|
||||
- 该项保持未完成;下一刀应进一步缩窄为只迁 editor 插入 DOM 拼接中的一个纯 helper,或由 Codex 本地实现后再交 Reasonix 做浏览器 smoke。
|
||||
- 2026-05-25:Codex 主控完成 `insertUploadedAssetIntoEditor` 外置切片:`local-upload-runtime.js` 新增并导出 `insertUploadedAssetIntoEditor(asset, targetRoot, deps)`,`layout.rs` 优先委托 runtime,保留完整 inline fallback。
|
||||
- 修改:`rust/crates/mnote-web/browser/local-upload-runtime.js`、`rust/crates/mnote-web/src/ssr/pages/layout.rs`。
|
||||
- 已验证:`node --check rust/crates/mnote-web/browser/local-upload-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_upload_runtime_contains_editor_upload_context_helpers -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_upload_runtime_routes_local_markdown_assets_to_local_folder -- --test-threads=1`、`node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。
|
||||
- 未完成:`uploadFileToMediaAsset` 编排壳、`uploadFilesWithResolvedTarget`、conflict merge / accept / keep 业务逻辑、secondary pane conflict smoke 仍未迁出。
|
||||
|
||||
@@ -183,6 +183,101 @@ async function uploadLocalFolderAsset(file, plan, context) {
|
||||
};
|
||||
}
|
||||
|
||||
async function insertUploadedAssetIntoEditor(asset, targetRoot, deps) {
|
||||
deps = deps || {};
|
||||
var editorRoot = targetRoot instanceof HTMLElement
|
||||
? targetRoot.querySelector('.editor-surface .ProseMirror')
|
||||
: document.querySelector('.editor-surface .ProseMirror');
|
||||
if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot;
|
||||
var editor = editorRoot && editorRoot.editor;
|
||||
if (!editor || !editor.chain) {
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false');
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'editor_unavailable');
|
||||
return false;
|
||||
}
|
||||
var title = typeof deps.uploadedAssetTitle === 'function' ? deps.uploadedAssetTitle(asset) : uploadedAssetTitle(asset);
|
||||
var localOpenUrl = typeof deps.localAssetOpenUrl === 'function' ? deps.localAssetOpenUrl(asset, false) : localAssetOpenUrl(asset, false);
|
||||
var fallbackUrl = typeof deps.uploadedAssetUrl === 'function' ? deps.uploadedAssetUrl(asset) : uploadedAssetUrl(asset);
|
||||
var url = localOpenUrl || fallbackUrl;
|
||||
var type = typeof deps.uploadedAssetType === 'function' ? deps.uploadedAssetType(asset) : uploadedAssetType(asset);
|
||||
var assetId = String(asset && asset.id || '').trim();
|
||||
var sizeLabel = typeof deps.uploadedFileSize === 'function' ? deps.uploadedFileSize(asset) : uploadedFileSize(asset);
|
||||
try {
|
||||
if (type === 'image' && url) {
|
||||
return editor.chain().focus().setImage({ src: url, alt: title, title: title }).run() === true;
|
||||
}
|
||||
var isLocalAsset = typeof deps.isLocalUploadedAsset === 'function' ? deps.isLocalUploadedAsset(asset) : isLocalUploadedAsset(asset);
|
||||
var userId = '';
|
||||
var buildOnlyOfficeAssetOpenUrl = typeof deps.buildOnlyOfficeAssetOpenUrl === 'function' ? deps.buildOnlyOfficeAssetOpenUrl : function() { return ''; };
|
||||
var onlyOfficeUrl = buildOnlyOfficeAssetOpenUrl(asset, userId);
|
||||
if (onlyOfficeUrl && assetId) {
|
||||
userId = typeof deps.fetchCurrentOnlyOfficeUserId === 'function' ? await deps.fetchCurrentOnlyOfficeUserId() : '';
|
||||
onlyOfficeUrl = buildOnlyOfficeAssetOpenUrl(asset, userId);
|
||||
}
|
||||
var href = onlyOfficeUrl || url;
|
||||
if (href) {
|
||||
var storedHref = onlyOfficeUrl
|
||||
? (isLocalAsset ? onlyOfficeUrl : deps.buildOnlyOfficeOpenPath({
|
||||
fileUrl: '',
|
||||
fileName: title,
|
||||
fileType: deps.inferOnlyOfficeFileType(title, asset && asset.mime_type) || 'docx',
|
||||
assetId: assetId,
|
||||
documentId: String(asset && (asset.document_id || asset.documentId) || deps.currentDocumentId() || '').trim(),
|
||||
userId: userId || '',
|
||||
mode: 'view'
|
||||
}))
|
||||
: href;
|
||||
var inserted = editor.chain().focus().insertContent([
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: title,
|
||||
marks: [{
|
||||
type: 'link',
|
||||
attrs: {
|
||||
href: storedHref,
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer nofollow',
|
||||
class: typeof deps.uploadedAttachmentClass === 'function' ? deps.uploadedAttachmentClass(asset) : uploadedAttachmentClass(asset)
|
||||
}
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{ type: 'paragraph' }
|
||||
]).focus('end').run() === true;
|
||||
if (inserted) {
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'true');
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId || '');
|
||||
document.documentElement.removeAttribute('data-mnote-last-upload-insert-error');
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false');
|
||||
document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'insert_content_failed');
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot;
|
||||
if (typeof deps.enhanceEditorAttachmentLinks === 'function') deps.enhanceEditorAttachmentLinks();
|
||||
var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value || '').replace(/"/g, '\\"'); };
|
||||
var selector = assetId
|
||||
? '.editor-surface .ProseMirror a[href*="' + cssEscape(assetId) + '"]'
|
||||
: '.editor-surface .ProseMirror a';
|
||||
var link = targetRoot instanceof HTMLElement
|
||||
? targetRoot.querySelector(selector)
|
||||
: document.querySelector(selector);
|
||||
if (link instanceof HTMLElement) {
|
||||
link.setAttribute('data-mnote-attachment-link', 'true');
|
||||
if (assetId) link.setAttribute('data-asset-id', assetId);
|
||||
if (sizeLabel) link.setAttribute('data-file-size', sizeLabel);
|
||||
}
|
||||
}, 0);
|
||||
return inserted;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[mnote upload] insert uploaded asset failed', error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function localAssetOpenUrl(asset, download, context) {
|
||||
if (!isLocalUploadedAsset(asset)) return '';
|
||||
var rootUri = String(context && context.rootUri || asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
|
||||
@@ -313,6 +408,7 @@ window.__mnoteLocalUploadRuntime = {
|
||||
openEditorUploadFilePicker: openEditorUploadFilePicker,
|
||||
fetchWithTimeout: fetchWithTimeout,
|
||||
uploadLocalFolderAsset: uploadLocalFolderAsset,
|
||||
insertUploadedAssetIntoEditor: insertUploadedAssetIntoEditor,
|
||||
localAssetOpenUrl: localAssetOpenUrl,
|
||||
uploadedAssetType: uploadedAssetType,
|
||||
fileTreeIconKindForFileName: fileTreeIconKindForFileName,
|
||||
|
||||
@@ -3905,6 +3905,25 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
async function insertUploadedAssetIntoEditor(asset, targetRoot) {
|
||||
var runtimeFn = localUploadRuntimeFunction('insertUploadedAssetIntoEditor');
|
||||
if (runtimeFn) {
|
||||
return await runtimeFn(asset, targetRoot, {
|
||||
uploadedAssetTitle: uploadedAssetTitle,
|
||||
localAssetOpenUrl: localAssetOpenUrl,
|
||||
uploadedAssetUrl: uploadedAssetUrl,
|
||||
uploadedAssetType: uploadedAssetType,
|
||||
isLocalUploadedAsset: isLocalUploadedAsset,
|
||||
buildOnlyOfficeAssetOpenUrl: buildOnlyOfficeAssetOpenUrl,
|
||||
fetchCurrentOnlyOfficeUserId: fetchCurrentOnlyOfficeUserId,
|
||||
buildOnlyOfficeOpenPath: buildOnlyOfficeOpenPath,
|
||||
inferOnlyOfficeFileType: inferOnlyOfficeFileType,
|
||||
currentDocumentId: currentDocumentId,
|
||||
uploadedAttachmentClass: uploadedAttachmentClass,
|
||||
uploadedFileSize: uploadedFileSize,
|
||||
cssEscape: cssEscape,
|
||||
enhanceEditorAttachmentLinks: enhanceEditorAttachmentLinks
|
||||
});
|
||||
}
|
||||
var editorRoot = targetRoot instanceof HTMLElement
|
||||
? targetRoot.querySelector('.editor-surface .ProseMirror')
|
||||
: document.querySelector('.editor-surface .ProseMirror');
|
||||
@@ -10932,6 +10951,9 @@ mod tests {
|
||||
assert!(
|
||||
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('openEditorUploadFilePicker')")
|
||||
);
|
||||
assert!(
|
||||
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('insertUploadedAssetIntoEditor')")
|
||||
);
|
||||
assert!(SIDEBAR_TREE_JS.contains("__mnoteLastEditorUploadRoot"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-pane-role=\"primary\""));
|
||||
assert!(SIDEBAR_TREE_JS.contains("insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options))"));
|
||||
@@ -10947,6 +10969,8 @@ mod tests {
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function openEditorUploadFilePicker"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function fetchWithTimeout"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadLocalFolderAsset"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function insertUploadedAssetIntoEditor"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("data-mnote-last-upload-inserted"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("uploadFilesWithResolvedTarget"));
|
||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("__mnoteLastEditorUploadRoot"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user