722 lines
31 KiB
JavaScript
722 lines
31 KiB
JavaScript
/**
|
||
* 可视化编辑器模块
|
||
* @type {module}
|
||
*/
|
||
import { XmlUtils } from './xml-utils.js';
|
||
import { DateTimeDialog } from './date-time-dialog.js';
|
||
import { CommandDialog } from './command-dialog.js';
|
||
|
||
export class VisualEditor {
|
||
/**
|
||
* 渲染可视化编辑器
|
||
* @param {HTMLElement} container - 容器元素
|
||
* @param {Document} xmlDoc - XML文档
|
||
* @param {Function} onEdit - 编辑回调函数
|
||
* @returns {boolean} 是否渲染成功
|
||
*/
|
||
static render(container, xmlDoc, onEdit) {
|
||
if (!xmlDoc || !container) return false;
|
||
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
.section {
|
||
margin-bottom: 20px;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
padding: 10px;
|
||
background-color: white;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
padding-bottom: 5px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.section-title {
|
||
font-weight: bold;
|
||
color: #555;
|
||
}
|
||
|
||
.property-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.property-table th, .property-table td {
|
||
text-align: left;
|
||
padding: 8px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.property-table th {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.form-control {
|
||
width: 100%;
|
||
padding: 8px;
|
||
box-sizing: border-box;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.inline-form {
|
||
display: flex;
|
||
gap: 16px;
|
||
}
|
||
|
||
.inline-form .form-group {
|
||
flex: 1;
|
||
}
|
||
|
||
.two-column-form {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 16px;
|
||
}
|
||
|
||
.input-container {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.input-container .icon-button {
|
||
min-width: 28px;
|
||
height: 28px;
|
||
background-size: 16px;
|
||
background-position: center;
|
||
background-repeat: no-repeat;
|
||
border: none;
|
||
cursor: pointer;
|
||
background-color: transparent;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.input-container .icon-button:hover {
|
||
opacity: 1;
|
||
}
|
||
|
||
.calendar-button {
|
||
background-image: url('assets/icons/png/calendar_b.png');
|
||
}
|
||
|
||
.command-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.command-table th, .command-table td {
|
||
padding: 8px;
|
||
text-align: left;
|
||
border: 1px solid #ddd;
|
||
}
|
||
|
||
.command-table th {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.element-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 10px;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
margin-bottom: 10px;
|
||
background-color: #f9f9f9;
|
||
}
|
||
|
||
.element-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.element-name {
|
||
font-weight: 500;
|
||
color: #444;
|
||
flex: 1;
|
||
}
|
||
|
||
.element-value {
|
||
width: 100%;
|
||
}
|
||
|
||
.element-value input {
|
||
max-width: 100%;
|
||
}
|
||
|
||
.element-input-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
width: 100%;
|
||
}
|
||
|
||
.element-input-row .form-control {
|
||
flex: 1;
|
||
}
|
||
|
||
.nested-elements {
|
||
padding-left: 20px;
|
||
margin-top: 5px;
|
||
border-left: 1px dashed #ccc;
|
||
}
|
||
`;
|
||
|
||
const visualEditor = document.createElement('div');
|
||
visualEditor.className = 'visual-editor';
|
||
|
||
// 获取根元素
|
||
const rootElement = xmlDoc.documentElement;
|
||
|
||
// 只处理Service根元素
|
||
if (rootElement.nodeName === 'Service') {
|
||
// 添加基本信息部分
|
||
visualEditor.appendChild(this.createBasicInfoSection(xmlDoc, onEdit));
|
||
|
||
// 添加命令列表部分
|
||
visualEditor.appendChild(this.createCommandsSection(xmlDoc, onEdit));
|
||
|
||
// 添加其他设置部分
|
||
visualEditor.appendChild(this.createOtherSettingsSection(xmlDoc, onEdit));
|
||
|
||
container.appendChild(style);
|
||
container.appendChild(visualEditor);
|
||
|
||
return true;
|
||
} else {
|
||
// 不是Service根元素,显示错误信息
|
||
visualEditor.innerHTML = `<div class="error-message">
|
||
无法编辑:XML文档的根元素不是Service。
|
||
请确保XML文档的根元素是Service。
|
||
</div>`;
|
||
|
||
container.appendChild(style);
|
||
container.appendChild(visualEditor);
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建基本信息部分
|
||
*/
|
||
static createBasicInfoSection(xmlDoc, onEdit) {
|
||
const rootElement = xmlDoc.documentElement;
|
||
|
||
// 创建基本信息部分
|
||
const basicInfoSection = document.createElement('div');
|
||
basicInfoSection.className = 'section';
|
||
|
||
const basicInfoHeader = document.createElement('div');
|
||
basicInfoHeader.className = 'section-header';
|
||
basicInfoHeader.innerHTML = '<div class="section-title">基本信息</div>';
|
||
basicInfoSection.appendChild(basicInfoHeader);
|
||
|
||
// 获取基本信息数据
|
||
const nameElement = rootElement.querySelector('Name') || xmlDoc.createElement('Name');
|
||
const descElement = rootElement.querySelector('Description') || xmlDoc.createElement('Description');
|
||
const authorElement = rootElement.querySelector('Author') || xmlDoc.createElement('Author');
|
||
const versionElement = rootElement.querySelector('Version') || xmlDoc.createElement('Version');
|
||
const createTimeElement = rootElement.querySelector('CreateTime') || xmlDoc.createElement('CreateTime');
|
||
const changeTimeElement = rootElement.querySelector('ChangeTime') || xmlDoc.createElement('ChangeTime');
|
||
|
||
// 确保元素存在于XML中
|
||
if (!rootElement.querySelector('Name')) rootElement.appendChild(nameElement);
|
||
if (!rootElement.querySelector('Description')) rootElement.appendChild(descElement);
|
||
if (!rootElement.querySelector('Author')) rootElement.appendChild(authorElement);
|
||
if (!rootElement.querySelector('Version')) rootElement.appendChild(versionElement);
|
||
if (!rootElement.querySelector('CreateTime')) {
|
||
createTimeElement.textContent = DateTimeDialog.getCurrentDateTime();
|
||
rootElement.appendChild(createTimeElement);
|
||
}
|
||
if (!rootElement.querySelector('ChangeTime')) {
|
||
changeTimeElement.textContent = DateTimeDialog.getCurrentDateTime();
|
||
rootElement.appendChild(changeTimeElement);
|
||
}
|
||
|
||
// 创建基本信息表单
|
||
const basicInfoForm = document.createElement('div');
|
||
basicInfoForm.className = 'form-container';
|
||
|
||
// 服务名称和描述在同一行
|
||
const nameDescContainer = document.createElement('div');
|
||
nameDescContainer.className = 'inline-form';
|
||
nameDescContainer.innerHTML = `
|
||
<div class="form-group">
|
||
<label for="serviceName">服务名称</label>
|
||
<input type="text" id="serviceName" class="form-control" placeholder="请输入服务名称" value="${XmlUtils.escapeHtml(nameElement.textContent || '')}" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="serviceDesc">服务描述</label>
|
||
<input type="text" id="serviceDesc" class="form-control" placeholder="请输入服务描述" value="${XmlUtils.escapeHtml(descElement.textContent || '')}" />
|
||
</div>
|
||
`;
|
||
basicInfoForm.appendChild(nameDescContainer);
|
||
|
||
// 其他信息以两列布局
|
||
const otherInfoContainer = document.createElement('div');
|
||
otherInfoContainer.className = 'two-column-form';
|
||
otherInfoContainer.style.marginTop = '15px';
|
||
otherInfoContainer.innerHTML = `
|
||
<div class="form-group">
|
||
<label for="serviceAuthor">作者</label>
|
||
<input type="text" id="serviceAuthor" class="form-control" placeholder="请输入作者" value="${XmlUtils.escapeHtml(authorElement.textContent || '')}" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="serviceVersion">版本</label>
|
||
<input type="text" id="serviceVersion" class="form-control" placeholder="请输入版本号" value="${XmlUtils.escapeHtml(versionElement.textContent || '1.0.0')}" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="serviceCreateTime">创建时间</label>
|
||
<div class="input-container">
|
||
<input type="text" id="serviceCreateTime" class="form-control" placeholder="YYYY-MM-DD HH:MM:SS" value="${XmlUtils.escapeHtml(createTimeElement.textContent || '')}" />
|
||
<button class="icon-button calendar-button" title="选择日期和时间" id="createTimeBtn"></button>
|
||
<button class="icon-button refresh-button-sm" title="设置为当前时间" id="refreshCreateTimeBtn" style="background-image: url('assets/icons/png/refresh_b.png'); min-width: 28px; height: 28px; background-size: 16px; background-position: center; background-repeat: no-repeat; border: none; cursor: pointer; background-color: transparent; opacity: 0.7;"></button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="serviceChangeTime">修改时间</label>
|
||
<div class="input-container">
|
||
<input type="text" id="serviceChangeTime" class="form-control" placeholder="YYYY-MM-DD HH:MM:SS" value="${XmlUtils.escapeHtml(changeTimeElement.textContent || '')}" />
|
||
<button class="icon-button calendar-button" title="选择日期和时间" id="changeTimeBtn"></button>
|
||
<button class="icon-button refresh-button-sm" title="设置为当前时间" id="refreshChangeTimeBtn" style="background-image: url('assets/icons/png/refresh_b.png'); min-width: 28px; height: 28px; background-size: 16px; background-position: center; background-repeat: no-repeat; border: none; cursor: pointer; background-color: transparent; opacity: 0.7;"></button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
basicInfoForm.appendChild(otherInfoContainer);
|
||
|
||
basicInfoSection.appendChild(basicInfoForm);
|
||
|
||
// 添加事件监听
|
||
basicInfoSection.addEventListener('change', (e) => {
|
||
if (e.target.id === 'serviceName') {
|
||
nameElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
} else if (e.target.id === 'serviceDesc') {
|
||
descElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
} else if (e.target.id === 'serviceAuthor') {
|
||
authorElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
} else if (e.target.id === 'serviceVersion') {
|
||
versionElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
} else if (e.target.id === 'serviceCreateTime') {
|
||
createTimeElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
} else if (e.target.id === 'serviceChangeTime') {
|
||
changeTimeElement.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
}
|
||
});
|
||
|
||
// 添加日期时间选择器事件
|
||
basicInfoSection.querySelector('#createTimeBtn').addEventListener('click', () => {
|
||
const input = basicInfoSection.querySelector('#serviceCreateTime');
|
||
DateTimeDialog.show(basicInfoSection.ownerDocument.body, input, (newValue) => {
|
||
input.value = newValue;
|
||
createTimeElement.textContent = newValue;
|
||
if (onEdit) onEdit();
|
||
});
|
||
});
|
||
|
||
basicInfoSection.querySelector('#changeTimeBtn').addEventListener('click', () => {
|
||
const input = basicInfoSection.querySelector('#serviceChangeTime');
|
||
DateTimeDialog.show(basicInfoSection.ownerDocument.body, input, (newValue) => {
|
||
input.value = newValue;
|
||
changeTimeElement.textContent = newValue;
|
||
if (onEdit) onEdit();
|
||
});
|
||
});
|
||
|
||
// 添加刷新按钮事件
|
||
basicInfoSection.querySelector('#refreshCreateTimeBtn').addEventListener('click', () => {
|
||
const input = basicInfoSection.querySelector('#serviceCreateTime');
|
||
const datetimeStr = DateTimeDialog.getCurrentDateTime();
|
||
|
||
input.value = datetimeStr;
|
||
createTimeElement.textContent = datetimeStr;
|
||
if (onEdit) onEdit();
|
||
});
|
||
|
||
basicInfoSection.querySelector('#refreshChangeTimeBtn').addEventListener('click', () => {
|
||
const input = basicInfoSection.querySelector('#serviceChangeTime');
|
||
const datetimeStr = DateTimeDialog.getCurrentDateTime();
|
||
|
||
input.value = datetimeStr;
|
||
changeTimeElement.textContent = datetimeStr;
|
||
if (onEdit) onEdit();
|
||
});
|
||
|
||
return basicInfoSection;
|
||
}
|
||
|
||
/**
|
||
* 创建命令列表部分
|
||
*/
|
||
static createCommandsSection(xmlDoc, onEdit) {
|
||
const rootElement = xmlDoc.documentElement;
|
||
|
||
// 创建命令列表部分
|
||
const commandsSection = document.createElement('div');
|
||
commandsSection.className = 'section';
|
||
|
||
const commandsHeader = document.createElement('div');
|
||
commandsHeader.className = 'section-header';
|
||
commandsHeader.innerHTML = `
|
||
<div class="section-title">指令列表</div>
|
||
<button id="addCommandBtn" class="action-button">添加指令</button>
|
||
`;
|
||
commandsSection.appendChild(commandsHeader);
|
||
|
||
// 获取或创建命令列表
|
||
let commandListElement = rootElement.querySelector('CommandList');
|
||
if (!commandListElement) {
|
||
commandListElement = xmlDoc.createElement('CommandList');
|
||
rootElement.appendChild(commandListElement);
|
||
}
|
||
|
||
// 创建命令表格
|
||
const commandsTable = document.createElement('table');
|
||
commandsTable.className = 'command-table';
|
||
commandsTable.innerHTML = `
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 20%;">名称</th>
|
||
<th style="width: 25%;">调用</th>
|
||
<th style="width: 40%;">描述</th>
|
||
<th style="width: 15%;">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="commandsTableBody">
|
||
</tbody>
|
||
`;
|
||
|
||
// 创建表格内容
|
||
const commandsTableBody = commandsTable.querySelector('#commandsTableBody');
|
||
|
||
// 更新命令表格的函数
|
||
const updateCommandTable = () => {
|
||
// 清空表格
|
||
commandsTableBody.innerHTML = '';
|
||
|
||
// 获取所有命令
|
||
const commandElements = commandListElement.querySelectorAll('Command');
|
||
|
||
if (commandElements.length === 0) {
|
||
// 如果没有命令,显示空行
|
||
const emptyRow = document.createElement('tr');
|
||
emptyRow.innerHTML = '<td colspan="4" style="text-align: center;">暂无指令</td>';
|
||
commandsTableBody.appendChild(emptyRow);
|
||
} else {
|
||
// 添加所有命令到表格
|
||
commandElements.forEach((command, index) => {
|
||
const name = command.getAttribute('Name') || '';
|
||
const call = command.getAttribute('Call') || '';
|
||
const description = command.getAttribute('Description') || '';
|
||
|
||
const row = document.createElement('tr');
|
||
row.dataset.index = index;
|
||
row.innerHTML = `
|
||
<td>${XmlUtils.escapeHtml(name)}</td>
|
||
<td>${XmlUtils.escapeHtml(call)}</td>
|
||
<td>${XmlUtils.escapeHtml(description)}</td>
|
||
<td>
|
||
<button class="action-button edit-btn" data-index="${index}">编辑</button>
|
||
<button class="action-button delete-btn" data-index="${index}" style="background-color: #E77979;">删除</button>
|
||
</td>
|
||
`;
|
||
|
||
commandsTableBody.appendChild(row);
|
||
});
|
||
|
||
// 添加编辑和删除事件
|
||
commandsTableBody.querySelectorAll('.edit-btn').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const index = parseInt(btn.dataset.index);
|
||
const command = commandElements[index];
|
||
CommandDialog.showEditDialog(
|
||
commandsSection.ownerDocument.body,
|
||
command,
|
||
index,
|
||
() => {
|
||
updateCommandTable();
|
||
if (onEdit) onEdit();
|
||
}
|
||
);
|
||
});
|
||
});
|
||
|
||
commandsTableBody.querySelectorAll('.delete-btn').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const index = parseInt(btn.dataset.index);
|
||
const command = commandElements[index];
|
||
if (confirm(`确定要删除指令 ${command.getAttribute('Name')} 吗?`)) {
|
||
commandListElement.removeChild(command);
|
||
updateCommandTable();
|
||
if (onEdit) onEdit();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
};
|
||
|
||
// 初始化表格
|
||
updateCommandTable();
|
||
|
||
// 添加"添加指令"按钮事件
|
||
commandsSection.querySelector('#addCommandBtn').addEventListener('click', () => {
|
||
CommandDialog.showAddDialog(
|
||
commandsSection.ownerDocument.body,
|
||
commandListElement,
|
||
xmlDoc,
|
||
() => {
|
||
updateCommandTable();
|
||
if (onEdit) onEdit();
|
||
}
|
||
);
|
||
});
|
||
|
||
// 添加表格
|
||
commandsSection.appendChild(commandsTable);
|
||
|
||
return commandsSection;
|
||
}
|
||
|
||
/**
|
||
* 创建其他设置部分
|
||
*/
|
||
static createOtherSettingsSection(xmlDoc, onEdit) {
|
||
const rootElement = xmlDoc.documentElement;
|
||
|
||
// 创建其他设置部分
|
||
const otherSettingsSection = document.createElement('div');
|
||
otherSettingsSection.className = 'section';
|
||
|
||
const otherSettingsHeader = document.createElement('div');
|
||
otherSettingsHeader.className = 'section-header';
|
||
otherSettingsHeader.innerHTML = `
|
||
<div class="section-title">其他设置</div>
|
||
<span class="settings-hint" style="font-size: 12px; color: #777; font-style: italic;">如需添加参数,请手动编辑配置文件</span>
|
||
`;
|
||
otherSettingsSection.appendChild(otherSettingsHeader);
|
||
|
||
// 创建其他设置内容
|
||
const otherSettingsContent = document.createElement('div');
|
||
otherSettingsContent.className = 'other-settings-container';
|
||
|
||
// 递归处理元素及其子元素
|
||
const processElement = (parentElement, containerElement, level = 0) => {
|
||
// 筛选节点元素,排除文本节点
|
||
const childElements = Array.from(parentElement.childNodes)
|
||
.filter(node => node.nodeType === 1); // 只处理元素节点
|
||
|
||
if (childElements.length === 0) return;
|
||
|
||
childElements.forEach(element => {
|
||
// 排除已处理的基本信息元素和命令列表
|
||
const nodeName = element.nodeName;
|
||
if (['Name', 'Description', 'Author', 'Version', 'CreateTime',
|
||
'ChangeTime', 'CommandList'].includes(nodeName)) {
|
||
return;
|
||
}
|
||
|
||
// 创建元素框
|
||
const elementBox = document.createElement('div');
|
||
elementBox.className = 'element-box';
|
||
elementBox.id = `element-${getElementPath(element).replace(/\./g, '-')}`;
|
||
if (level > 0) {
|
||
elementBox.style.marginLeft = `${level * 10}px`;
|
||
}
|
||
|
||
// 创建元素头部(包含名称)
|
||
const elementHeader = document.createElement('div');
|
||
elementHeader.className = 'element-header';
|
||
|
||
// 创建元素名称
|
||
const elementName = document.createElement('div');
|
||
elementName.className = 'element-name';
|
||
elementName.textContent = nodeName;
|
||
elementHeader.appendChild(elementName);
|
||
|
||
// 将元素头部添加到元素框
|
||
elementBox.appendChild(elementHeader);
|
||
|
||
// 创建元素内容容器
|
||
const elementContent = document.createElement('div');
|
||
elementContent.className = 'element-value';
|
||
|
||
// 处理不同类型的元素内容
|
||
const hasChildElements = Array.from(element.childNodes)
|
||
.some(node => node.nodeType === 1);
|
||
|
||
if (hasChildElements) {
|
||
// 如果有子元素,为它们创建一个嵌套容器
|
||
const childContainer = document.createElement('div');
|
||
childContainer.className = 'nested-elements';
|
||
|
||
// 递归处理子元素
|
||
processElement(element, childContainer, level + 1);
|
||
|
||
elementContent.appendChild(childContainer);
|
||
|
||
// 为父元素添加删除按钮
|
||
const deleteBtn = document.createElement('button');
|
||
deleteBtn.className = 'action-button';
|
||
deleteBtn.textContent = '删除';
|
||
deleteBtn.style.backgroundColor = '#e77979';
|
||
deleteBtn.style.marginTop = '8px';
|
||
deleteBtn.addEventListener('click', () => {
|
||
if (confirm(`确定要删除 ${nodeName} 及其所有子元素吗?`)) {
|
||
try {
|
||
// 从DOM和XML中删除元素
|
||
parentElement.removeChild(element);
|
||
|
||
// 移除元素框
|
||
if (elementBox.parentNode) {
|
||
elementBox.parentNode.removeChild(elementBox);
|
||
}
|
||
|
||
// 触发编辑回调
|
||
if (onEdit) onEdit();
|
||
|
||
// 如果没有其他元素了,显示"没有其他设置项"提示
|
||
const otherSettingsContainer = otherSettingsContent;
|
||
if (otherSettingsContainer && otherSettingsContainer.children.length === 0) {
|
||
const noElementsMsg = document.createElement('div');
|
||
noElementsMsg.style.padding = '10px';
|
||
noElementsMsg.style.color = '#666';
|
||
noElementsMsg.textContent = '没有其他设置项';
|
||
otherSettingsContainer.appendChild(noElementsMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('删除元素时出错:', error);
|
||
alert(`删除元素失败: ${error.message}`);
|
||
}
|
||
}
|
||
});
|
||
|
||
elementContent.appendChild(deleteBtn);
|
||
} else {
|
||
// 如果没有子元素,创建可编辑的文本输入
|
||
const elementValue = element.textContent || '';
|
||
|
||
const inputRow = document.createElement('div');
|
||
inputRow.className = 'element-input-row';
|
||
|
||
const input = document.createElement('input');
|
||
input.type = 'text';
|
||
input.className = 'form-control';
|
||
input.value = elementValue;
|
||
input.dataset.elementPath = getElementPath(element);
|
||
|
||
// 为输入框添加事件监听
|
||
input.addEventListener('change', (e) => {
|
||
element.textContent = e.target.value;
|
||
if (onEdit) onEdit();
|
||
});
|
||
|
||
inputRow.appendChild(input);
|
||
|
||
// 添加删除按钮
|
||
const deleteBtn = document.createElement('button');
|
||
deleteBtn.className = 'action-button';
|
||
deleteBtn.textContent = '删除';
|
||
deleteBtn.style.backgroundColor = '#e77979';
|
||
deleteBtn.addEventListener('click', () => {
|
||
if (confirm(`确定要删除 ${nodeName} 吗?`)) {
|
||
try {
|
||
// 从DOM和XML中删除元素
|
||
parentElement.removeChild(element);
|
||
|
||
// 移除元素框
|
||
if (elementBox.parentNode) {
|
||
elementBox.parentNode.removeChild(elementBox);
|
||
}
|
||
|
||
// 触发编辑回调
|
||
if (onEdit) onEdit();
|
||
|
||
// 如果没有其他元素了,显示"没有其他设置项"提示
|
||
const otherSettingsContainer = otherSettingsContent;
|
||
if (otherSettingsContainer && otherSettingsContainer.querySelectorAll('.element-box').length === 0) {
|
||
const noElementsMsg = document.createElement('div');
|
||
noElementsMsg.style.padding = '10px';
|
||
noElementsMsg.style.color = '#666';
|
||
noElementsMsg.textContent = '没有其他设置项';
|
||
otherSettingsContainer.appendChild(noElementsMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('删除元素时出错:', error);
|
||
alert(`删除元素失败: ${error.message}`);
|
||
}
|
||
}
|
||
});
|
||
|
||
inputRow.appendChild(deleteBtn);
|
||
elementContent.appendChild(inputRow);
|
||
}
|
||
|
||
// 将元素内容添加到元素框
|
||
elementBox.appendChild(elementContent);
|
||
|
||
// 将元素框添加到容器
|
||
containerElement.appendChild(elementBox);
|
||
});
|
||
};
|
||
|
||
// 获取元素的路径,用于唯一标识
|
||
const getElementPath = (element) => {
|
||
const path = [];
|
||
let current = element;
|
||
|
||
while (current && current !== xmlDoc) {
|
||
const nodeName = current.nodeName;
|
||
path.unshift(nodeName);
|
||
current = current.parentNode;
|
||
}
|
||
|
||
return path.join('.');
|
||
};
|
||
|
||
// 处理其他元素(排除标准元素)
|
||
const standardElements = ['Name', 'Description', 'Author', 'Version',
|
||
'CreateTime', 'ChangeTime', 'CommandList'];
|
||
|
||
const otherElements = Array.from(rootElement.childNodes)
|
||
.filter(node => node.nodeType === 1 && !standardElements.includes(node.nodeName));
|
||
|
||
if (otherElements.length > 0) {
|
||
// 处理所有其他元素
|
||
processElement(rootElement, otherSettingsContent);
|
||
} else {
|
||
// 如果没有其他元素,显示提示
|
||
const noElementsMsg = document.createElement('div');
|
||
noElementsMsg.style.padding = '10px';
|
||
noElementsMsg.style.color = '#666';
|
||
noElementsMsg.textContent = '没有其他设置项';
|
||
otherSettingsContent.appendChild(noElementsMsg);
|
||
}
|
||
|
||
otherSettingsSection.appendChild(otherSettingsContent);
|
||
|
||
return otherSettingsSection;
|
||
}
|
||
}
|