export const createSidebarFileTreeUploadRuntime = (dependencies = {}) => { const { cssEscape, currentDocumentId, fileTreeRuntimeDeps, fileTreeRuntimeFunction, recordFileTreeAction, recordFileTreeActionStatus, resolveWorkspaceId, rowTitle, selectedSidebarFileTreeSelection, } = dependencies; const sidebarFileTreeSelection = selectedSidebarFileTreeSelection; function fileTreeRowsForUploadPreflight() { var runtimeFn = fileTreeRuntimeFunction('fileTreeRowsForUploadPreflight'); if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps()); return Array.from(document.querySelectorAll('.tree-row[data-shell-mode="filetree"]')).map(function(row) { return { rowId: row.getAttribute('data-row-id') || '', rowKind: row.getAttribute('data-row-kind') || '', documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null, assetId: row.getAttribute('data-asset-id') || null, assetDocumentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null, assetType: row.querySelector('.tree-kind-badge') ? row.querySelector('.tree-kind-badge').getAttribute('data-kind') : null, storagePath: null }; }).filter(function(row) { return row.rowId || row.documentId || row.assetId; }); } function fileTreeRowCapabilities(row) { if (!(row instanceof HTMLElement)) return []; try { var parsed = JSON.parse(row.getAttribute('data-capabilities') || '[]'); return Array.isArray(parsed) ? parsed.map(function(item) { return String(item || '').trim(); }).filter(Boolean) : []; } catch (_) { return []; } } function fileTreeRowIsReadonly(row) { return fileTreeRowCapabilities(row).some(function(capability) { return ['readonly', 'readOnly', 'permissionDenied'].indexOf(capability) >= 0; }); } async function blockReadonlyFileTreeAction(action, detail, message) { var normalizedAction = String(action || 'drop').trim() || 'drop'; var text = String(message || '目标位置是只读,不能拖放到这里').trim(); var targetRowId = String(detail && (detail.targetRowId || detail.rowId) || '').trim(); var documentId = String(detail && detail.documentId || '').trim(); var assetId = String(detail && detail.assetId || '').trim(); recordFileTreeAction(normalizedAction, { rowId: targetRowId, documentId: documentId, assetId: assetId, readonly: true }); recordFileTreeActionStatus('blocked', { rowId: targetRowId, documentId: documentId, assetId: assetId, readonly: true, fallback: 'alert' }); document.documentElement.setAttribute('data-mnote-filetree-readonly-blocked', normalizedAction); document.documentElement.setAttribute('data-mnote-filetree-readonly-message', text); if (targetRowId) { document.documentElement.setAttribute('data-mnote-filetree-readonly-target-row-id', targetRowId); var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(targetRowId) + '"]'); if (row instanceof HTMLElement) { row.setAttribute('data-readonly-blocked', normalizedAction); row.setAttribute('data-readonly-message', text); } } await window.mnote.alert(text); return false; } function fileTreeDocumentParentsForPreflight() { var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentParentsForPreflight'); if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps()); return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]')).map(function(row) { var documentId = row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || ''; if (!documentId) return null; var parentRowId = row.getAttribute('data-parent-id') || ''; var parentDocumentId = parentRowId.indexOf('doc:') === 0 ? parentRowId.slice(4) : parentRowId || null; return { documentId: documentId, parentId: parentDocumentId }; }).filter(Boolean); } function fileTreeTargetChildrenForPreflight(targetRow) { var runtimeFn = fileTreeRuntimeFunction('fileTreeTargetChildrenForPreflight'); if (runtimeFn) return runtimeFn(targetRow, fileTreeRuntimeDeps()); var node = targetRow instanceof HTMLElement ? targetRow.closest('.tree-node') : null; if (!node) return []; return Array.from(node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"]')).map(function(row) { return { rowKind: row.getAttribute('data-row-kind') || '', documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null, assetId: row.getAttribute('data-asset-id') || null, title: rowTitle(row) }; }); } function fileTreeDropPreflightRows() { var runtimeFn = fileTreeRuntimeFunction('fileTreeDropPreflightRows'); if (runtimeFn) return runtimeFn(Object.assign({}, fileTreeRuntimeDeps(), { fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight })); return fileTreeRowsForUploadPreflight().map(function(row) { var domRow = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(row.rowId) + '"]'); row.title = rowTitle(domRow); return row; }); } async function ensureFileTreeWritableTarget(action, targetRow, rowIds, copy) { var normalizedAction = String(action || 'drop').trim() || 'drop'; if (!(targetRow instanceof HTMLElement)) return true; var detail = { targetRowId: targetRow.getAttribute('data-row-id') || '', rowId: targetRow.getAttribute('data-row-id') || '', documentId: targetRow.getAttribute('data-document-id') || targetRow.getAttribute('data-doc-id') || '', assetId: targetRow.getAttribute('data-asset-id') || '' }; if (fileTreeRowIsReadonly(targetRow)) { return blockReadonlyFileTreeAction(normalizedAction, detail, '目标位置是只读,不能拖放到这里'); } try { var response = await fetch('/api/tree/filetree/drop-preflight', { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ workspaceId: resolveWorkspaceId(targetRow), copy: Boolean(copy), sourceCapabilities: ['read', 'write', 'move'], targetCapabilities: fileTreeRowCapabilities(targetRow), targetDocumentId: detail.documentId || null, targetRowId: detail.targetRowId || null, focusedRowId: sidebarFileTreeSelection.focusedRowId || null, activeDocumentId: currentDocumentId() || null, rowIds: Array.isArray(rowIds) ? rowIds : [], rows: fileTreeDropPreflightRows(), targetChildren: fileTreeTargetChildrenForPreflight(targetRow), documentParents: fileTreeDocumentParentsForPreflight() }) }); if (response.ok) return true; var payload = await response.json().catch(function() { return null; }); var message = payload && (payload.error || payload.message) ? String(payload.error || payload.message) : '目标位置是只读,不能拖放到这里'; if (message.indexOf('只读') >= 0 || message.toLowerCase().indexOf('readonly') >= 0) { return blockReadonlyFileTreeAction(normalizedAction, detail, message); } return true; } catch (_) { return true; } } function fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) { var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight'); if (runtimeFn) { return runtimeFn(workspaceId, Object.assign({}, fileTreeRuntimeDeps(), { fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight })); } var seen = new Set(); return fileTreeRowsForUploadPreflight().filter(function(row) { if (!row.documentId || seen.has(row.documentId)) return false; seen.add(row.documentId); return true; }).map(function(row) { return { documentId: row.documentId, workspaceId: workspaceId || null }; }); } async function preflightFileTreeUploadTarget(detail) { var bodyRuntime = fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody'); var body = bodyRuntime ? bodyRuntime(detail || {}, Object.assign({}, fileTreeRuntimeDeps(), { focusedRowId: sidebarFileTreeSelection.focusedRowId || null, fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight, currentDocumentId: currentDocumentId, resolveWorkspaceId: resolveWorkspaceId })) : (function() { var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim(); return { workspaceId: workspaceId || null, targetDocumentId: detail && detail.documentId ? String(detail.documentId) : null, targetRowId: detail && detail.targetRowId ? String(detail.targetRowId) : null, focusedRowId: sidebarFileTreeSelection.focusedRowId || null, activeDocumentId: currentDocumentId() || null, rows: fileTreeRowsForUploadPreflight(), documentWorkspaces: fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) }; })(); var response = await fetch('/api/tree/filetree/upload-target-preflight', { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) }); var payload = await response.json().catch(function() { return null; }); if (!response.ok || !payload || !payload.plan) { throw new Error(payload && payload.error ? payload.error : '文件树上传目标预检失败'); } return payload.plan; } function fallbackFileTreeUploadTarget(detail) { var runtimeFn = fileTreeRuntimeFunction('fileTreeUploadTargetFallback'); if (runtimeFn) { return runtimeFn(detail || {}, { resolveWorkspaceId: resolveWorkspaceId, currentDocumentId: currentDocumentId }); } var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim(); var documentId = String(detail && detail.documentId || currentDocumentId() || '').trim(); if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) { return { workspaceId: workspaceId, targetDocumentId: documentId, targetMindmapId: null, targetSubPath: null, targetRelativePath: String(detail.targetRelativePath || ''), uploadIntent: String(detail.uploadIntent || 'filetree.folder.drop') }; } if (!workspaceId || !documentId) { throw new Error('请选择一个目标页面后再拖入文件'); } return { workspaceId: workspaceId, targetDocumentId: documentId, targetMindmapId: null, targetSubPath: null, uploadIntent: String(detail && detail.uploadIntent || 'editor.markdown.attach') }; } async function resolveFileTreeUploadTarget(detail) { if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) { return fallbackFileTreeUploadTarget(detail || {}); } try { var plan = await preflightFileTreeUploadTarget(detail || {}); var normalizePlanRuntime = fileTreeRuntimeFunction('normalizeFileTreeUploadTargetPlan'); if (normalizePlanRuntime) { return normalizePlanRuntime(detail || {}, plan); } if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) { plan.targetRelativePath = String(detail.targetRelativePath || ''); } if (detail && detail.uploadIntent) { plan.uploadIntent = String(detail.uploadIntent); } else if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) { plan.uploadIntent = 'filetree.folder.drop'; } else if (!plan.uploadIntent) { plan.uploadIntent = 'editor.markdown.attach'; } return plan; } catch (error) { console.warn('[mnote upload] upload target preflight fallback', error); return fallbackFileTreeUploadTarget(detail || {}); } } return { fileTreeRowsForUploadPreflight, fileTreeRowCapabilities, fileTreeRowIsReadonly, blockReadonlyFileTreeAction, fileTreeDocumentParentsForPreflight, fileTreeTargetChildrenForPreflight, fileTreeDropPreflightRows, ensureFileTreeWritableTarget, fileTreeDocumentWorkspacesForUploadPreflight, preflightFileTreeUploadTarget, fallbackFileTreeUploadTarget, resolveFileTreeUploadTarget, }; };