130 lines
5.5 KiB
JavaScript
130 lines
5.5 KiB
JavaScript
|
/**
|
|||
|
* XML编辑模块
|
|||
|
* @type {module}
|
|||
|
*/
|
|||
|
import { markEdited } from './utils.js';
|
|||
|
|
|||
|
/**
|
|||
|
* 更新XML内容从可视化编辑器
|
|||
|
* @param {HTMLElement} component - 组件实例
|
|||
|
* @param {boolean} silent - 是否静默执行(不显示提示)
|
|||
|
* @returns {string} 更新后的XML内容
|
|||
|
*/
|
|||
|
export function updateXmlFromVisualEditor(component, silent = true) {
|
|||
|
if (!component.xmlDoc) {
|
|||
|
return component.xmlContent;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
// 获取所有输入元素
|
|||
|
const inputs = component.shadowRoot.querySelectorAll('[data-path]');
|
|||
|
|
|||
|
// 遍历输入元素,更新XML
|
|||
|
inputs.forEach(input => {
|
|||
|
const path = input.dataset.path;
|
|||
|
const value = input.type === 'checkbox' ? (input.checked ? '1' : '0') : input.value;
|
|||
|
|
|||
|
if (!path) return;
|
|||
|
|
|||
|
// 解析路径
|
|||
|
if (path.includes('@')) {
|
|||
|
// 属性路径
|
|||
|
const [elementPath, attrName] = path.split('@');
|
|||
|
|
|||
|
if (elementPath) {
|
|||
|
// 包含元素路径和属性名
|
|||
|
let element;
|
|||
|
|
|||
|
if (elementPath.includes('/')) {
|
|||
|
// 使用/分隔的路径
|
|||
|
const pathParts = elementPath.split('/');
|
|||
|
let currentElement = component.xmlDoc.documentElement;
|
|||
|
|
|||
|
for (let i = 0; i < pathParts.length; i++) {
|
|||
|
const part = pathParts[i];
|
|||
|
|
|||
|
if (part === '') continue;
|
|||
|
|
|||
|
if (part.includes('[') && part.includes(']')) {
|
|||
|
// 带索引的元素
|
|||
|
const tagName = part.substring(0, part.indexOf('['));
|
|||
|
const index = parseInt(part.substring(part.indexOf('[') + 1, part.indexOf(']')));
|
|||
|
|
|||
|
const elements = currentElement.getElementsByTagName(tagName);
|
|||
|
if (elements.length > index) {
|
|||
|
currentElement = elements[index];
|
|||
|
} else {
|
|||
|
console.warn(`无法找到元素: ${part}`);
|
|||
|
return;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// 不带索引的元素
|
|||
|
const elements = currentElement.getElementsByTagName(part);
|
|||
|
if (elements.length > 0) {
|
|||
|
currentElement = elements[0];
|
|||
|
} else {
|
|||
|
console.warn(`无法找到元素: ${part}`);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
element = currentElement;
|
|||
|
} else if (elementPath.includes('[') && elementPath.includes(']')) {
|
|||
|
// 带索引的元素 e.g. ModelGroup[0]
|
|||
|
const tagName = elementPath.substring(0, elementPath.indexOf('['));
|
|||
|
const index = parseInt(elementPath.substring(elementPath.indexOf('[') + 1, elementPath.indexOf(']')));
|
|||
|
|
|||
|
const elements = component.xmlDoc.getElementsByTagName(tagName);
|
|||
|
if (elements.length > index) {
|
|||
|
element = elements[index];
|
|||
|
} else {
|
|||
|
console.warn(`无法找到元素: ${elementPath}`);
|
|||
|
return;
|
|||
|
}
|
|||
|
} else {
|
|||
|
// 简单元素 e.g. Environment
|
|||
|
element = component.xmlDoc.getElementsByTagName(elementPath)[0];
|
|||
|
}
|
|||
|
|
|||
|
if (element) {
|
|||
|
if (input.dataset.isNew === 'true') {
|
|||
|
// 新属性
|
|||
|
element.setAttribute(attrName, value);
|
|||
|
} else {
|
|||
|
// 已有属性,检查是否修改
|
|||
|
const oldValue = element.getAttribute(attrName);
|
|||
|
if (oldValue !== value) {
|
|||
|
element.setAttribute(attrName, value);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// 直接在根元素上的属性
|
|||
|
component.xmlDoc.documentElement.setAttribute(attrName, value);
|
|||
|
}
|
|||
|
} else {
|
|||
|
// 元素内容路径 (暂未使用)
|
|||
|
console.warn('不支持的路径格式:', path);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// 生成更新后的XML
|
|||
|
const serializer = new XMLSerializer();
|
|||
|
const xmlString = serializer.serializeToString(component.xmlDoc);
|
|||
|
|
|||
|
// 更新组件的xmlContent
|
|||
|
component.xmlContent = xmlString;
|
|||
|
|
|||
|
// 标记为已编辑
|
|||
|
component.isEdited = markEdited(component.shadowRoot, component.isEdited);
|
|||
|
|
|||
|
return xmlString;
|
|||
|
} catch (error) {
|
|||
|
if (!silent) {
|
|||
|
console.error('更新XML失败:', error);
|
|||
|
alert(`更新XML失败: ${error.message}`);
|
|||
|
}
|
|||
|
return component.xmlContent;
|
|||
|
}
|
|||
|
}
|