2025-04-28 12:25:20 +08:00

445 lines
15 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.

/**
* 工具函数模块
* @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, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
/**
* 创建模态对话框
* @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 = '&times;';
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<boolean>} 如果可以继续操作返回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 = `
<style>
.modal {
display: block;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 400px;
border-radius: 5px;
position: relative;
text-align: center;
}
.modal-title {
margin-top: 0;
color: #333;
font-size: 18px;
margin-bottom: 20px;
}
.modal-buttons {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 20px;
}
.btn {
padding: 8px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
min-width: 80px;
}
.btn-save {
background-color: #7986E7;
color: white;
}
.btn-save:hover {
background-color: #6875D6;
}
.btn-dont-save {
background-color: #E77979;
color: white;
}
.btn-dont-save:hover {
background-color: #D66868;
}
.btn-cancel {
background-color: #f5f5f5;
color: #333;
}
.btn-cancel:hover {
background-color: #e0e0e0;
}
</style>
<div class="modal-content">
<h3 class="modal-title">当前文件有未保存的更改</h3>
<p>您想要保存这些更改吗?</p>
<div class="modal-buttons">
<button class="btn btn-save" id="saveBtn">保存</button>
<button class="btn btn-dont-save" id="dontSaveBtn">不保存</button>
<button class="btn btn-cancel" id="cancelBtn">取消</button>
</div>
</div>
`;
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;
}