/** * 工具函数模块 * @type {module} */ import { saveFileContent } from './file-operations.js'; /** * 格式化XML字符串 * @param {string} xml - XML字符串 * @returns {string} 格式化后的XML字符串 */ export function formatXml(xml) { if (!xml || !xml.trim()) return ''; try { let formatted = ''; const parser = new DOMParser(); const doc = parser.parseFromString(xml, 'text/xml'); // 检查是否解析错误 const parseError = doc.querySelector('parsererror'); if (parseError) { console.warn('XML解析错误,返回原始文本'); return xml; // 如果解析错误,返回原始文本 } // 使用XMLSerializer序列化为字符串 const serializer = new XMLSerializer(); formatted = serializer.serializeToString(doc); // 简单格式化:替换'><'为'>\n<'添加换行 formatted = formatted.replace(/><(?!\/)/g, '>\n<'); // 添加缩进 const lines = formatted.split('\n'); let indent = 0; formatted = lines.map(line => { if (line.match(/<\/[^>]+>/)) { // 关闭标签,减少缩进 indent--; } const result = ' '.repeat(Math.max(0, indent * 2)) + line; if (line.match(/<[^\/][^>]*[^\/]>/) && !line.match(/<.*\/>/) && !line.match(/<[^>]+><\/[^>]+>/)) { // 开放标签,增加缩进 indent++; } return result; }).join('\n'); return formatted; } catch (e) { console.error('XML格式化失败:', e); return xml; } } /** * 转义HTML字符 * @param {string} unsafe - 不安全的HTML字符串 * @returns {string} 转义后的HTML字符串 */ export function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** * 创建模态对话框 * @param {HTMLElement} shadowRoot - Shadow DOM根元素 * @param {string} title - 对话框标题 * @param {HTMLElement|string} content - 对话框内容 * @param {Function} confirmCallback - 确认按钮回调函数 * @returns {Object} 对话框引用 */ export function createModal(shadowRoot, title, content, confirmCallback) { // 创建模态框容器 const modalOverlay = document.createElement('div'); modalOverlay.className = 'modal-overlay active'; modalOverlay.style.position = 'fixed'; modalOverlay.style.top = '0'; modalOverlay.style.left = '0'; modalOverlay.style.right = '0'; modalOverlay.style.bottom = '0'; modalOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; modalOverlay.style.display = 'flex'; modalOverlay.style.alignItems = 'center'; modalOverlay.style.justifyContent = 'center'; modalOverlay.style.zIndex = '1000'; // 创建模态框 const modal = document.createElement('div'); modal.className = 'modal-content'; modal.style.backgroundColor = 'white'; modal.style.borderRadius = '12px'; modal.style.padding = '24px'; modal.style.width = '500px'; modal.style.maxWidth = '90%'; modal.style.maxHeight = '90vh'; modal.style.overflowY = 'auto'; modal.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)'; // 创建模态框头部 const modalHeader = document.createElement('div'); modalHeader.className = 'modal-header'; modalHeader.style.display = 'flex'; modalHeader.style.justifyContent = 'space-between'; modalHeader.style.alignItems = 'center'; modalHeader.style.marginBottom = '16px'; // 创建标题 const modalTitle = document.createElement('h2'); modalTitle.className = 'modal-title'; modalTitle.textContent = title; modalTitle.style.fontSize = '20px'; modalTitle.style.fontWeight = 'bold'; modalTitle.style.color = '#2c3e50'; modalTitle.style.margin = '0'; // 关闭按钮 const closeBtn = document.createElement('button'); closeBtn.className = 'close-btn'; closeBtn.innerHTML = '×'; closeBtn.style.background = 'none'; closeBtn.style.border = 'none'; closeBtn.style.fontSize = '24px'; closeBtn.style.cursor = 'pointer'; closeBtn.style.color = '#718096'; closeBtn.style.lineHeight = '1'; closeBtn.style.padding = '0'; // 添加关闭按钮事件 closeBtn.onclick = () => { modalOverlay.remove(); }; // 组装头部 modalHeader.appendChild(modalTitle); modalHeader.appendChild(closeBtn); // 创建表单容器 const formContainer = document.createElement('form'); formContainer.style.marginBottom = '0'; // 添加内容 if (content) { // 如果内容已经是DOM元素,直接使用 if (content instanceof HTMLElement) { // 为内容添加样式 content.style.margin = '0 0 20px 0'; formContainer.appendChild(content); } else { // 否则创建新的内容容器 const contentDiv = document.createElement('div'); contentDiv.innerHTML = content; contentDiv.style.margin = '0 0 20px 0'; formContainer.appendChild(contentDiv); } } // 创建按钮容器 const modalFooter = document.createElement('div'); modalFooter.className = 'modal-footer'; modalFooter.style.display = 'flex'; modalFooter.style.justifyContent = 'flex-end'; modalFooter.style.gap = '12px'; modalFooter.style.marginTop = '24px'; // 取消按钮 const cancelButton = document.createElement('button'); cancelButton.className = 'btn btn-secondary'; cancelButton.type = 'button'; cancelButton.textContent = '取消'; cancelButton.style.padding = '10px 16px'; cancelButton.style.borderRadius = '6px'; cancelButton.style.fontSize = '15px'; cancelButton.style.cursor = 'pointer'; cancelButton.style.transition = 'all 0.3s'; cancelButton.style.backgroundColor = '#f8f9fa'; cancelButton.style.border = '1px solid #ddd'; cancelButton.style.color = '#718096'; // 添加取消按钮事件 cancelButton.onclick = () => { modalOverlay.remove(); }; // 确定按钮 const confirmButton = document.createElement('button'); confirmButton.className = 'btn btn-primary'; confirmButton.type = 'button'; confirmButton.textContent = '确定'; confirmButton.style.padding = '10px 16px'; confirmButton.style.borderRadius = '6px'; confirmButton.style.fontSize = '15px'; confirmButton.style.cursor = 'pointer'; confirmButton.style.transition = 'all 0.3s'; confirmButton.style.background = 'linear-gradient(135deg, #667eea, #764ba2)'; confirmButton.style.border = 'none'; confirmButton.style.color = 'white'; // 添加确定按钮事件 confirmButton.onclick = () => { if (confirmCallback) { confirmCallback(); modalOverlay.remove(); // 确保回调执行后关闭对话框 } }; // 点击背景关闭 modalOverlay.onclick = (e) => { if (e.target === modalOverlay) { modalOverlay.remove(); } }; // 组装底部按钮 modalFooter.appendChild(cancelButton); modalFooter.appendChild(confirmButton); // 组装表单 formContainer.appendChild(modalFooter); // 阻止表单提交默认行为 formContainer.onsubmit = (e) => { e.preventDefault(); if (confirmCallback) { confirmCallback(); modalOverlay.remove(); // 确保回调执行后关闭对话框 } return false; }; // 组装整个模态框 modal.appendChild(modalHeader); modal.appendChild(formContainer); modalOverlay.appendChild(modal); // 添加到DOM shadowRoot.appendChild(modalOverlay); // 返回引用 return { modal: modalOverlay, confirmButton: confirmButton }; } /** * 标记编辑状态 * @param {HTMLElement} shadowRoot - Shadow DOM根元素 * @param {boolean} isEdited - 是否已编辑 * @returns {boolean} 新的编辑状态 */ export function markEdited(shadowRoot, isEdited) { if (!isEdited) { // 更新保存按钮样式 const saveButton = shadowRoot.getElementById('saveConfig'); if (saveButton) { saveButton.classList.add('modified'); saveButton.title = '文件已修改,请保存'; } return true; } return isEdited; } /** * 重置编辑状态 * @param {HTMLElement} shadowRoot - Shadow DOM根元素 * @returns {boolean} 重置后的编辑状态(false) */ export function resetEditState(shadowRoot) { // 更新保存按钮样式 const saveButton = shadowRoot.getElementById('saveConfig'); if (saveButton) { saveButton.classList.remove('modified'); saveButton.title = ''; } return false; } /** * 检查是否需要保存当前更改 * @param {HTMLElement} component - 组件实例 * @returns {Promise} 如果可以继续操作返回true,否则返回false */ export async function checkSaveNeeded(component) { // 检查是否有未保存的修改 const saveButton = component.shadowRoot.getElementById('saveConfig'); const hasUnsavedChanges = saveButton && saveButton.classList.contains('modified'); if (hasUnsavedChanges) { // 使用自定义对话框替代简单的confirm const dialogResult = await new Promise(resolve => { // 创建模态框 const modal = document.createElement('div'); modal.className = 'modal'; modal.id = 'saveConfirmModal'; modal.innerHTML = ` `; document.body.appendChild(modal); // 添加事件监听 const saveBtn = modal.querySelector('#saveBtn'); const dontSaveBtn = modal.querySelector('#dontSaveBtn'); const cancelBtn = modal.querySelector('#cancelBtn'); const closeModal = () => { document.body.removeChild(modal); }; saveBtn.addEventListener('click', () => { closeModal(); resolve('save'); }); dontSaveBtn.addEventListener('click', () => { closeModal(); resolve('dont-save'); }); cancelBtn.addEventListener('click', () => { closeModal(); resolve('cancel'); }); // 点击模态窗口外部也取消 modal.addEventListener('click', (event) => { if (event.target === modal) { closeModal(); resolve('cancel'); } }); }); // 根据对话框结果执行相应操作 if (dialogResult === 'save') { try { // 保存文件 if (component.currentFile && component.xmlContent) { await saveFileContent(component, component.currentFile, component.xmlContent); resetEditState(component.shadowRoot); return true; // 继续执行后续操作 } else { return false; // 无法保存,不继续执行 } } catch (error) { console.error('保存出错:', error); return false; // 保存失败,不继续执行 } } else if (dialogResult === 'dont-save') { // 不保存,但继续执行后续操作 return true; } else { // 用户取消,不执行后续操作 return false; } } // 没有编辑状态,直接返回true允许继续操作 return true; }