Files
mnote/rust/crates/mnote-web/browser/document-conflict-panel-runtime.js
T

175 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
}
/**
* 在已有 diffPanel 中填充 current/disk/merge DOM 并绑定回调。
* 不处理 fetch、persist、status 等业务逻辑。
* @param {HTMLElement} panel - 已清空的 diffPanel 元素
* @param {Object} context
* @param {string} context.currentText - 当前编辑器的文本(含占位文案)
* @param {string} context.diskText - 磁盘版本的文本(含占位文案)
* @param {string} [context.currentMergeText] - 写入合并区域的当前编辑器原始文本
* @param {string} [context.diskMergeText] - 写入合并区域的磁盘版本原始文本
* @param {string} [context.mergeDefaultText] - 合并区域默认文本
* @param {Object} deps
* @param {Function} [deps.onUseCurrent] - 可选:返回当前版本写入合并区域的文本
* @param {Function} [deps.onUseDisk] - 可选:返回磁盘版本写入合并区域的文本
* @param {Function} deps.onSaveMerge - 保存合并结果回调,接收合并文本字符串
*/
function populateSessionConflictDiffPanel(panel, context, deps) {
context = context || {};
deps = deps || {};
var currentText = context.currentText || '';
var diskText = context.diskText || '';
var currentMergeText = Object.prototype.hasOwnProperty.call(context, 'currentMergeText')
? String(context.currentMergeText || '')
: currentText;
var diskMergeText = Object.prototype.hasOwnProperty.call(context, 'diskMergeText')
? String(context.diskMergeText || '')
: diskText;
var mergeDefaultText = context.mergeDefaultText || currentText || diskText || '';
var current = document.createElement('pre');
current.setAttribute('data-testid', 'mnote-conflict-current-text');
current.textContent = currentText;
var disk = document.createElement('pre');
disk.setAttribute('data-testid', 'mnote-conflict-disk-text');
disk.textContent = diskText;
var currentTitle = document.createElement('h3');
currentTitle.textContent = '当前编辑器版本';
var diskTitle = document.createElement('h3');
diskTitle.textContent = '磁盘版本';
var currentBox = document.createElement('section');
currentBox.append(currentTitle, current);
var diskBox = document.createElement('section');
diskBox.append(diskTitle, disk);
var mergeTitle = document.createElement('h3');
mergeTitle.textContent = '合并结果';
var mergeText = document.createElement('textarea');
mergeText.setAttribute('data-testid', 'mnote-conflict-merge-text');
mergeText.value = mergeDefaultText;
var mergeActions = document.createElement('div');
mergeActions.className = 'mnote-conflict-actions';
var useCurrent = document.createElement('button');
useCurrent.type = 'button';
useCurrent.textContent = '使用当前版本';
useCurrent.setAttribute('data-testid', 'mnote-conflict-merge-use-current');
var useDisk = document.createElement('button');
useDisk.type = 'button';
useDisk.textContent = '使用磁盘版本';
useDisk.setAttribute('data-testid', 'mnote-conflict-merge-use-disk');
var saveMerge = document.createElement('button');
saveMerge.type = 'button';
saveMerge.textContent = '写回合并结果';
saveMerge.setAttribute('data-testid', 'mnote-conflict-merge-save');
mergeActions.append(useCurrent, useDisk, saveMerge);
var mergeBox = document.createElement('section');
mergeBox.className = 'mnote-conflict-merge-box';
mergeBox.append(mergeTitle, mergeText, mergeActions);
panel.append(currentBox, diskBox, mergeBox);
useCurrent.addEventListener('click', function() {
var nextText = typeof deps.onUseCurrent === 'function'
? deps.onUseCurrent(context)
: currentMergeText;
mergeText.value = typeof nextText === 'string' ? nextText : currentMergeText;
});
useDisk.addEventListener('click', function() {
var nextText = typeof deps.onUseDisk === 'function'
? deps.onUseDisk(context)
: diskMergeText;
mergeText.value = typeof nextText === 'string' ? nextText : diskMergeText;
});
saveMerge.addEventListener('click', function() {
if (typeof deps.onSaveMerge === 'function') {
deps.onSaveMerge(mergeText.value);
}
});
}
window.__mnoteDocumentConflictPanelRuntime = {
clearSessionConflictSurface: clearSessionConflictSurface,
createSessionConflictPanel: createSessionConflictPanel,
populateSessionConflictDiffPanel: populateSessionConflictDiffPanel
};