// MNote document conflict panel 运行时外置模块。 // 第一刀:纯 DOM 清理 helper clearSessionConflictSurface。 // 本文件以 type="module" 加载,执行时机可能晚于 inline script。 // web_shell.rs 的 inline clearSessionConflictSurface 会优先委托到 // window.__mnoteDocumentConflictPanelRuntime; // 模块尚未加载或加载失败时,inline script 保留原地实现兜底。 /** * 清除指定 session 所有视图中冲突面板 DOM。 * 只做 DOM 清理,不处理冲突 merge/accept/keep 业务逻辑。 * @param {Object} session - document session 对象 * @param {Object} deps - 依赖注入,从 inline 上下文传入 * @param {Function} deps.sessionViews - session.views 迭代器 */ function clearSessionConflictSurface(session, deps) { var views = deps && typeof deps.sessionViews === 'function' ? deps.sessionViews(session) : []; views.forEach(function(view) { var host = view.runtimeDescriptor.root.closest('.document-pane') || view.runtimeDescriptor.root; if (!(host instanceof HTMLElement)) return; host.querySelectorAll('[data-testid="mnote-editor-conflict-panel"]').forEach(function(node) { node.remove(); }); }); } function createSessionConflictPanel(session, message, deps) { deps = deps || {}; var externalConflictMessage = String(deps.externalConflictMessage || '').trim() || '文件已在外部修改'; var panel = document.createElement('section'); panel.className = 'mnote-editor-conflict-panel'; panel.setAttribute('data-testid', 'mnote-editor-conflict-panel'); panel.setAttribute('role', 'status'); panel.setAttribute('aria-live', 'polite'); var heading = document.createElement('h2'); heading.textContent = '文件冲突'; var text = document.createElement('p'); text.textContent = message || externalConflictMessage; var meta = document.createElement('div'); meta.className = 'mnote-conflict-meta'; var fileLabel = session && session.sessionKind === 'resource' ? String(session.rootUri || '') + '/' + String(session.resourcePath || session.documentId || '') : String(session && (session.rootUri || session.documentId) || ''); var sourceLabel = typeof deps.conflictSourceLabel === 'function' ? deps.conflictSourceLabel(session) : ''; meta.textContent = '文件:' + fileLabel + ' · 来源:' + (sourceLabel || '本地文件变更'); var actions = document.createElement('div'); actions.className = 'mnote-conflict-actions'; var acceptDisk = document.createElement('button'); acceptDisk.type = 'button'; acceptDisk.textContent = '接受磁盘版本'; acceptDisk.setAttribute('data-testid', 'mnote-conflict-accept-disk'); var keepCurrent = document.createElement('button'); keepCurrent.type = 'button'; keepCurrent.textContent = '保留当前编辑器版本'; keepCurrent.setAttribute('data-testid', 'mnote-conflict-keep-current'); var openDiff = document.createElement('button'); openDiff.type = 'button'; openDiff.textContent = '打开 diff'; openDiff.setAttribute('data-testid', 'mnote-conflict-open-diff'); actions.append(acceptDisk, keepCurrent, openDiff); var diffPanel = document.createElement('div'); diffPanel.className = 'mnote-conflict-diff-panel'; diffPanel.setAttribute('data-testid', 'mnote-conflict-diff-panel'); diffPanel.hidden = true; panel.append(heading, text, meta, actions, diffPanel); acceptDisk.addEventListener('click', function() { if (typeof deps.onAcceptDisk === 'function') deps.onAcceptDisk(session, panel); }); keepCurrent.addEventListener('click', function() { if (typeof deps.onKeepCurrent === 'function') deps.onKeepCurrent(session, panel); }); openDiff.addEventListener('click', function() { if (typeof deps.onOpenDiff === 'function') deps.onOpenDiff(session, panel); }); return panel; } window.__mnoteDocumentConflictPanelRuntime = { clearSessionConflictSurface: clearSessionConflictSurface, createSessionConflictPanel: createSessionConflictPanel };