Re: 來做一個html生成器
发表于 : 2025年 11月 30日 11:27
當前代碼:
代码: 全选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ejwoom HTML Editor</title>
<style>
body {font-family:system-ui,sans-serif;margin:0;padding:0;background:#f5f5f5;}
.ejwoomtab {display:flex;background:#333;color:white;}
.ejwoomtab span {padding:12px 20px;cursor:pointer;}
.ejwoomtab span.active {background:#007bff;}
.ejwoomedit, .ejwoomresult {
padding:20px;background:white;min-height:100vh;display:none;
}
.ejwoomedit.active, .ejwoomresult.active {display:block;}
.ejwoomcontrol {
margin-bottom:15px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;
}
.ejwoomcontrol span {
padding:6px 12px;background:#eee;border-radius:4px;cursor:pointer;
}
.ejwoomcontrol span:hover {background:#ddd;}
.ejwoomtitle {
width:100%;padding:10px;font-size:18px;border:1px solid #ccc;
border-radius:4px;box-sizing:border-box;margin-bottom:15px;
}
.ejwoombuttons {
display:flex;gap:8px;flex-wrap:wrap;margin-bottom:15px;
}
.ejwoombuttons span {
padding:3px 7px;background:#007bff;color:white;border:none;
border-radius:4px;cursor:pointer;font-size:14px;
}
.ejwoombuttons span:hover {background:#0056b3;}
.ejwoomcontent {
width:100%;height:70vh;padding:12px;font-size:16px;
font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;
border:1px solid #ccc;border-radius:4px;box-sizing:border-box;
resize:vertical;
}
.ejwoomattach {
width:36px;height:36px;background:#28a745;color:white;border:none;
border-radius:8px;font-size:20px;cursor:pointer;
display:flex;align-items:center;justify-content:center;margin-top:10px;
}
.ejwoomattached {
display:flex;align-items:center;gap:8px;
background:#f8f9fa;border:1px solid #dee2e6;border-radius:6px;
padding:8px;margin:8px 0;font-size:14px;cursor:pointer;
}
.wmattachtype {
background:#e3f2fd;line-height:24px;border-radius:4px;
font-weight:bold;color:#1976d2;padding:0 7px;text-align:center;
}
.wmattachname {
flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
white-space:nowrap;background:#f5f5f5;padding:0 8px;
border-radius:4px;color:#333;margin-right:8px;
}
.wmattachsize {
background:#e8f5e8;color:#2e7d32;font-weight:500;
padding:2px 6px;border-radius:4px;margin-right:8px;font-size:12px;
}
.wmattachdelete {
background:#ffebee;color:#d32f2f;width:24px;height:24px;
border-radius:50%;line-height:22px!important;font-size:18px;
text-align:center;cursor:pointer;
}
.ejwoomdownload {margin-bottom:20px;}
.ejwoomdownload a {
padding:10px 16px;background:#28a745;color:white;
text-decoration:none;border-radius:6px;display:inline-block;
}
.ejwoomdownloadsize {
margin-left:15px;color:#666;font-size:14px;
}
.ejwoompreview {
border:1px solid #ddd;padding:20px;background:white;
border-radius:6px;min-height:70vh;overflow:auto;
}
/* Custom Button Styles */
.ejwoomaddbutton {
padding:3px 7px;background:#6c757d;color:white;border-radius:4px;
cursor:pointer;font-size:14px;font-weight:bold;
}
.ejwoomaddbutton:hover {background:#5a6268;}
.ejwoomcustombutton {
padding:3px 7px;background:#17a2b8;color:white;border-radius:4px;
cursor:pointer;font-size:14px;
}
.ejwoomcustombutton:hover {background:#138496;}
/* Modal Window */
.ejwoomwindow {
position:fixed;inset:0;background:rgba(0,0,0,0.7);
display:none;align-items:center;justify-content:center;z-index:999;
}
.ejwoomwindow.active {display:flex;}
.ejwoomwindow-content {
background:white;padding:28px 32px;border-radius:12px;
width:90%;max-width:540px;max-height:90vh;overflow-y:auto;
box-shadow:0 20px 40px rgba(0,0,0,0.22);
display:flex;flex-direction:column;gap:18px;
font-family:system-ui,sans-serif;
}
.ejwoom-btn-selector {
display:flex;flex-wrap:wrap;gap:10px;
border-bottom:1px solid #eee;padding-bottom:15px;
}
.ejwoomselbutton {
padding:6px 14px;background:#e9ecef;border-radius:6px;
cursor:pointer;user-select:none;transition:all 0.2s;font-weight:500;
}
.ejwoomselbutton:hover {background:#dee2e6;}
.ejwoomselbutton.selected {
background:#007bff;color:white;
}
.ejwoomselbutton.selected:hover {background:#0056b3;}
.ejwoom-input-row {
display:flex;align-items:center;gap:10px;
}
.ejwoom-input-row label {flex-basis:100px;flex-shrink:0;}
.ejwoom-input-row input[type="text"] {
flex-grow:1;padding:8px;border:1px solid #ccc;border-radius:4px;
}
.ejwoom-modal-controls {
display:flex;gap:10px;justify-content:flex-end;
padding-top:10px;border-top:1px solid #eee;
}
.ejwoom-modal-controls button {
border:none;padding:8px 16px;border-radius:4px;
cursor:pointer;color:white;font-weight:500;
}
.wmconfirm {background:#007bff;}
.wmconfirm:hover {background:#0056b3;}
.wmdelete {background:#dc3545;}
.wmdelete:hover {background:#c82333;}
.wmcancel {background:#6c757d;}
.wmcancel:hover {background:#5a6268;}
.wmdelete:disabled {opacity:0.5;cursor:not-allowed;background:#ccc;}
/* Read File Tab */
.ejwoomreadfile {
padding: 20px;
background: white;
min-height: 100vh;
}
.ejwoomreadarea {
border: 3px dashed #28a745;
border-radius: 8px;
padding: 20px;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 1.2em;
color: #555;
cursor: pointer;
transition: all 0.3s;
}
.ejwoomreadarea.selected {
border-color: #fd7e14; /* Orange */
color: #333;
font-weight: bold;
}
.ejwoomreadreset {
margin: -10px 0 15px 0;
color: #007bff;
cursor: pointer;
text-decoration: underline;
font-size: 14px;
}
.ejwoomreadoptions {
display: none; /* Hidden by default */
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #eee;
gap: 10px;
flex-wrap: wrap;
}
.ejwoomreadoptions a {
padding: 10px 16px;
background: #007bff; /* Blue */
color: white;
text-decoration: none;
border-radius: 6px;
display: inline-block;
cursor: pointer;
}
.ejwoomreadoptions a:hover {
background: #0056b3;
}
</style>
</head>
<body>
<div class="ejwoomtab">
<span class="ejwoomedittab active">Edit</span>
<span class="ejwoomresulttab">Preview & Download</span>
<span class="ejwoomreadfiletab">Read File</span>
</div>
<div class="ejwoomedit active">
<div class="ejwoomcontrol">
<span class="ejwoomundo">Undo</span>
<span class="ejwoomredo">Redo</span>
</div>
<input type="text" class="ejwoomtitle" placeholder="Enter title...">
<div class="ejwoombuttons">
<span>p</span>
<span>b</span><span>u</span><span>s</span><span>i</span>
<span>ul</span><span>ol</span><span>li</span>
<span>h1</span><span>h2</span><span>h3</span><span>h4</span><span>h5</span><span>h6</span>
<span class="ejwoomaddbutton">+</span>
</div>
<textarea class="ejwoomcontent" placeholder="Enter HTML content..."></textarea>
<div id="attachments"></div>
<button class="ejwoomattach" title="Attach file">+</button>
</div>
<div class="ejwoomresult"></div>
<input type="file" id="attachfile" style="display:none;">
<input type="file" id="readhtmlfile" style="display:none;" accept=".html,.htm">
<script>
document.addEventListener('DOMContentLoaded', function () {
const editTab = document.querySelector('.ejwoomedittab');
const resultTab = document.querySelector('.ejwoomresulttab');
const readfileTab = document.querySelector('.ejwoomreadfiletab'); // New
const editDiv = document.querySelector('.ejwoomedit');
const resultDiv = document.querySelector('.ejwoomresult');
// .ejwoomreadfile is created dynamically
const titleInput = document.querySelector('.ejwoomtitle');
const textarea = document.querySelector('.ejwoomcontent');
const attachBtn = document.querySelector('.ejwoomattach');
const attachInput = document.getElementById('attachfile');
const readHtmlInput = document.getElementById('readhtmlfile'); // New
const attachmentsContainer = document.getElementById('attachments');
const buttonsContainer = document.querySelector('.ejwoombuttons');
const addButton = document.querySelector('.ejwoomaddbutton');
const attachedFiles = new Map();
const imageExts = new Set(['png','jpg','jpeg','gif','svg','webp','bmp','ico']);
let loadedHtmlContent = null; // New: To store read file content
// === Helpers ===
function getExt(name) {
const i = name.lastIndexOf('.');
return i === -1 ? '' : name.slice(i + 1).toLowerCase();
}
function formatBytes(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// New: Convert Data URL back to File object
function dataURLtoFile(dataurl, filename) {
try {
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
} catch (e) {
console.error("Error converting data URL to file:", e);
return null;
}
}
// === Attachment System ===
function createAttachmentRow(file) {
const row = document.createElement('div');
row.className = 'ejwoomattached';
const ext = getExt(file.name);
const typeSpan = document.createElement('span');
typeSpan.className = 'wmattachtype';
typeSpan.textContent = (imageExts.has(ext) ? 'img' : 'file') + '/' + ext;
const nameSpan = document.createElement('span');
nameSpan.className = 'wmattachname';
nameSpan.textContent = file.name;
nameSpan.title = file.name;
const sizeSpan = document.createElement('span');
sizeSpan.className = 'wmattachsize';
sizeSpan.textContent = formatBytes(file.size);
const deleteSpan = document.createElement('span');
deleteSpan.className = 'wmattachdelete';
deleteSpan.textContent = '×';
deleteSpan.onclick = (e) => {
e.stopPropagation();
// Remove all references of this file from the editor content
const fileName = file.name;
const esc = fileName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`\\[img:${esc}\\]|\\[file:${esc}\\]`, 'g');
textarea.value = textarea.value.replace(regex, '');
row.remove();
attachedFiles.delete(file.name);
};
const insertRef = () => {
const start = textarea.selectionStart;
const ref = imageExts.has(ext) ? `[img:${file.name}]` : `[file:${file.name}]`;
textarea.value = textarea.value.slice(0, start) + ref + textarea.value.slice(start);
textarea.focus();
textarea.setSelectionRange(start + ref.length, start + ref.length);
};
row.onclick = (e) => {
if (e.target === deleteSpan) return;
insertRef();
};
row.append(typeSpan, nameSpan, sizeSpan, deleteSpan);
return row;
}
attachBtn.onclick = () => attachInput.click();
attachInput.onchange = e => {
for (let file of e.target.files) {
if (attachedFiles.has(file.name)) {
alert(`File "${file.name}" is already attached.`);
continue;
}
attachmentsContainer.appendChild(createAttachmentRow(file));
attachedFiles.set(file.name, file);
}
attachInput.value = '';
};
// === Button Wrapping ===
function wrapSelection(before, after = '') {
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const selected = textarea.value.substring(start, end);
textarea.value = textarea.value.substring(0, start) + before + selected + after + textarea.value.substring(end);
textarea.focus();
textarea.setSelectionRange(start + before.length, start + before.length + selected.length);
}
// Default buttons
document.querySelectorAll('.ejwoombuttons span:not(.ejwoomaddbutton):not(.ejwoomcustombutton)').forEach(span => {
span.onclick = () => wrapSelection(`<${span.textContent}>`, `</${span.textContent}>`);
});
// New: Refactored function to apply click logic to custom buttons
function applyCustomButtonLogic(targetSpan) {
targetSpan.onclick = () => {
const beforeRaw = targetSpan.dataset.before ? atob(targetSpan.dataset.before) : '';
const afterRaw = targetSpan.dataset.after ? atob(targetSpan.dataset.after) : '';
if (beforeRaw === '' && afterRaw === '') {
// If both before and after are empty, use <name>selected text</name>
const name = targetSpan.textContent.trim();
wrapSelection(`<${name}>`, `</${name}>`);
} else {
// Otherwise use custom before/after (even if one is empty)
wrapSelection(beforeRaw, afterRaw);
}
};
}
// === Custom Button Editor (Fixed!) ===
addButton.onclick = function () {
const modal = document.createElement('div');
modal.className = 'ejwoomwindow active';
modal.innerHTML = `
<div class="ejwoomwindow-content">
<div class="ejwoom-btn-selector">
<span class="ejwoomselbutton selected" data-value="new">new</span>
</div>
<div class="ejwoom-input-row"><label>Name</label><input type="text" placeholder="e.g. blockquote"></div>
<div class="ejwoom-input-row"><label>Before HTML</label><input type="text" placeholder="<div class="tip">"></div>
<div class="ejwoom-input-row"><label>After HTML</label><input type="text" placeholder="</div>"></div>
<div class="ejwoom-modal-controls">
<button class="wmconfirm">Confirm</button>
<button class="wmdelete" disabled>Delete</button>
<button class="wmcancel">Cancel</button>
</div>
</div>`;
document.body.appendChild(modal);
const selector = modal.querySelector('.ejwoom-btn-selector');
const nameInp = modal.querySelectorAll('input')[0];
const beforeInp = modal.querySelectorAll('input')[1];
const afterInp = modal.querySelectorAll('input')[2];
const confirmBtn = modal.querySelector('.wmconfirm');
const deleteBtn = modal.querySelector('.wmdelete');
const cancelBtn = modal.querySelector('.wmcancel');
// Load existing custom buttons into selector
buttonsContainer.querySelectorAll('.ejwoomcustombutton').forEach(btn => {
const sel = document.createElement('span');
sel.className = 'ejwoomselbutton';
sel.textContent = btn.textContent;
sel.dataset.value = btn.textContent;
sel._target = btn;
selector.appendChild(sel);
});
function updateForm() {
const selected = selector.querySelector('.selected');
if (!selected || selected.dataset.value === 'new') {
nameInp.value = beforeInp.value = afterInp.value = '';
deleteBtn.disabled = true;
} else {
const target = selected._target;
nameInp.value = target.textContent;
beforeInp.value = target.dataset.before ? atob(target.dataset.before) : '';
afterInp.value = target.dataset.after ? atob(target.dataset.after) : '';
deleteBtn.disabled = false;
}
}
selector.onclick = e => {
const btn = e.target.closest('.ejwoomselbutton');
if (!btn) return;
selector.querySelectorAll('.ejwoomselbutton').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
updateForm();
};
deleteBtn.onclick = () => {
const selected = selector.querySelector('.selected');
if (selected && selected.dataset.value !== 'new') {
selected._target.remove();
selected.remove();
selector.querySelector('[data-value="new"]').classList.add('selected');
updateForm();
}
};
confirmBtn.onclick = () => {
const name = nameInp.value.trim();
if (!name) return alert('Button name is required');
const selected = selector.querySelector('.selected');
let targetSpan;
if (selected.dataset.value === 'new') {
targetSpan = document.createElement('span');
targetSpan.className = 'ejwoomcustombutton';
buttonsContainer.insertBefore(targetSpan, addButton);
const newSel = document.createElement('span');
newSel.className = 'ejwoomselbutton';
newSel.textContent = name;
newSel.dataset.value = name;
newSel._target = targetSpan;
selector.appendChild(newSel);
} else {
targetSpan = selected._target;
}
targetSpan.textContent = name;
if (beforeInp.value) targetSpan.dataset.before = btoa(beforeInp.value);
else delete targetSpan.dataset.before;
if (afterInp.value) targetSpan.dataset.after = btoa(afterInp.value);
else delete targetSpan.dataset.after;
// Apply click behavior
applyCustomButtonLogic(targetSpan);
modal.remove();
};
cancelBtn.onclick = () => modal.remove();
updateForm();
};
// === Preview & Download (Fixed filename + [img:] [file:]) ===
async function buildResult() {
// Requirement 2: Collect all custom buttons to inject as <meta> in the final HTML
const customButtons = Array.from(buttonsContainer.querySelectorAll('.ejwoomcustombutton'));
let metaTagHTML = '';
if (customButtons.length > 0) {
const allButtonsHTML = customButtons.map(btn => btn.outerHTML.trim()).join('\n');
try {
const buttonsBase64 = btoa(allButtonsHTML);
metaTagHTML = `<meta name="ejwoombuttons" content="${buttonsBase64}">`;
} catch (e) {
console.error("Error encoding buttons:", e);
}
}
resultDiv.innerHTML = `
<div class="ejwoomdownload">
<a id="downloadlink" download="">Download HTML</a>
<span class="ejwoomdownloadsize"></span>
</div>
<div class="ejwoompreview"></div>
`;
const downloadLink = resultDiv.querySelector('#downloadlink');
const sizeSpan = resultDiv.querySelector('.ejwoomdownloadsize');
const previewDiv = resultDiv.querySelector('.ejwoompreview');
let title = (titleInput.value || 'Untitled').trim();
let processedContent = textarea.value.trim();
const replacements = new Map();
for (const [name, file] of attachedFiles) {
const base64 = await fileToBase64(file);
const ext = getExt(name);
const isImage = imageExts.has(ext);
let html = '';
if (isImage) {
let dims = '';
if (ext === 'svg') {
try {
const svg = atob(base64.split(',')[1]);
const w = svg.match(/width=["'](\d+)["']/i);
const h = svg.match(/height=["'](\d+)["']/i);
if (w) dims += ` width="${w[1]}"`;
if (h) dims += ` height="${h[1]}"`;
} catch (e) {}
}
html = `<img src="${base64}" alt="${name}" style="max-width:100%;height:auto;"${dims}>`;
} else {
html = `<a href="${base64}" download="${name}">Download ${name}</a>`;
}
replacements.set(`[img:${name}]`, html);
replacements.set(`[file:${name}]`, html);
}
for (const [key, val] of replacements) {
processedContent = processedContent.replace(
new RegExp(key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), val
);
}
previewDiv.innerHTML = processedContent;
const fullHTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width:device-width, initial-scale=1.0">
<title>${title}</title>
${metaTagHTML}
</head>
<body>
${processedContent}
</body>
</html>`;
const blob = new Blob([fullHTML], { type: 'text/html' });
const url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = title + '.html';
downloadLink.textContent = 'Download ' + title + '.html';
sizeSpan.textContent = formatBytes(blob.size);
}
// === NEW: Read File Functions ===
// 6.6: Parse HTML, extract attachments, and replace with placeholders
function rebuildAttachmentsFromHTML(htmlString) {
const tempDiv = document.createElement('div');
tempDiv.innerHTML = htmlString;
// Clear existing attachments
attachmentsContainer.innerHTML = '';
attachedFiles.clear();
// Find all data-based images and links
tempDiv.querySelectorAll('img[src^="data:"], a[href^="data:"][download]').forEach(el => {
const dataUrl = el.tagName === 'IMG' ? el.getAttribute('src') : el.getAttribute('href');
const filename = el.tagName === 'IMG' ? el.getAttribute('alt') : el.getAttribute('download');
if (!filename) {
console.warn('Found data URL element without alt/download name. Skipping.', el);
return;
}
if (attachedFiles.has(filename)) {
// Already processed a file with this name, just replace
const placeholder = el.tagName === 'IMG' ? `[img:${filename}]` : `[file:${filename}]`;
el.parentNode.replaceChild(document.createTextNode(placeholder), el);
return;
}
const file = dataURLtoFile(dataUrl, filename);
if (file) {
// Add to attachment systems
attachedFiles.set(file.name, file);
attachmentsContainer.appendChild(createAttachmentRow(file));
// Replace element with placeholder
const placeholder = el.tagName === 'IMG' ? `[img:${filename}]` : `[file:${filename}]`;
el.parentNode.replaceChild(document.createTextNode(placeholder), el);
}
});
// Return the HTML string with placeholders
return tempDiv.innerHTML;
}
// 6.5: Load buttons from a parsed HTML document
function parseAndLoadButtons(htmlDoc) {
// Clear existing custom buttons
buttonsContainer.querySelectorAll('.ejwoomcustombutton').forEach(btn => btn.remove());
// Requirement 2: Read from meta tag
const meta = htmlDoc.head.querySelector('meta[name="ejwoombuttons"]');
if (meta && meta.content) {
try {
const buttonsHTML = atob(meta.content);
const tempDiv = document.createElement('div');
tempDiv.innerHTML = buttonsHTML;
Array.from(tempDiv.children).forEach(node => {
if (node.tagName === 'SPAN' && node.classList.contains('ejwoomcustombutton')) {
// node is newly created by innerHTML, just append it
buttonsContainer.insertBefore(node, addButton);
applyCustomButtonLogic(node); // Re-apply click logic
}
});
} catch (e) {
console.error("Error parsing custom buttons from meta tag:", e);
}
}
}
// 6.4: Get body HTML
function parseAndLoadHTML(htmlDoc) {
const body = htmlDoc.body;
if (!body) return '';
// Template removal is no longer needed as it's in the head.
// Also try to find title
const titleTag = htmlDoc.head.querySelector('title');
if (titleTag && titleTag.textContent) {
titleInput.value = titleTag.textContent;
}
return body.innerHTML.trim(); // Use innerHTML to skip the <body> tag itself
}
// Switch to Edit Tab helper
function switchToEditTab() {
document.querySelectorAll('.ejwoomtab span').forEach(s => s.classList.remove('active'));
editTab.classList.add('active');
editDiv.classList.add('active');
resultDiv.classList.remove('active');
resultDiv.innerHTML = '';
const readDiv = document.querySelector('.ejwoomreadfile');
if (readDiv) readDiv.remove();
}
// === Tab Switching ===
resultTab.onclick = () => {
document.querySelectorAll('.ejwoomtab span').forEach(s => s.classList.remove('active'));
resultTab.classList.add('active');
editDiv.classList.remove('active');
resultDiv.classList.add('active');
const readDiv = document.querySelector('.ejwoomreadfile'); // New
if (readDiv) readDiv.remove(); // New
buildResult();
};
editTab.onclick = () => {
switchToEditTab(); // Use helper
};
// New: Read File Tab click
readfileTab.onclick = () => {
// Set active tab
document.querySelectorAll('.ejwoomtab span').forEach(s => s.classList.remove('active'));
readfileTab.classList.add('active');
// Hide other main divs
editDiv.classList.remove('active');
resultDiv.classList.remove('active');
// Clean up old read div if it exists
let readDiv = document.querySelector('.ejwoomreadfile');
if (readDiv) readDiv.remove();
// Create new read file UI
readDiv = document.createElement('div');
readDiv.className = 'ejwoomreadfile';
readDiv.innerHTML = `
<div class="ejwoomreadarea">Open the HTML file that you saved before.</div>
<div class="ejwoomreadoptions">
<a class="ejwoomreadall">Read All0</a>
<a class="ejwoomreadhtml">Read HTML Only</a>
<a class="ejwoomreadbutton">Read Buttons Only</a>
</div>
`;
document.body.appendChild(readDiv);
const readArea = readDiv.querySelector('.ejwoomreadarea');
const readOptions = readDiv.querySelector('.ejwoomreadoptions');
// Reset function
function resetReadFileUI() {
readArea.innerHTML = 'Open the HTML file that you saved before.';
readArea.classList.remove('selected');
readOptions.style.display = 'none';
const resetBtn = readDiv.querySelector('.ejwoomreadreset');
if (resetBtn) resetBtn.remove();
readHtmlInput.value = ''; // Clear file input
loadedHtmlContent = null;
}
// Read area click
readArea.onclick = () => readHtmlInput.click();
// Read file input change
readHtmlInput.onchange = e => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
loadedHtmlContent = ev.target.result;
// Update UI
readArea.textContent = file.name;
readArea.classList.add('selected');
readOptions.style.display = 'flex';
// Add reset button if it doesn't exist
if (!readDiv.querySelector('.ejwoomreadreset')) {
const resetBtn = document.createElement('div');
resetBtn.className = 'ejwoomreadreset';
resetBtn.textContent = 'Reset file selection.';
resetBtn.onclick = resetReadFileUI;
readDiv.insertBefore(resetBtn, readArea);
}
};
reader.onerror = () => {
alert('Error reading file.');
resetReadFileUI();
};
reader.readAsText(file);
};
// Option button clicks
readDiv.querySelector('.ejwoomreadall').onclick = () => {
if (!loadedHtmlContent) return alert('No file loaded.');
const parser = new DOMParser();
const doc = parser.parseFromString(loadedHtmlContent, 'text/html');
parseAndLoadButtons(doc);
let bodyHtml = parseAndLoadHTML(doc);
textarea.value = rebuildAttachmentsFromHTML(bodyHtml).trim();
switchToEditTab();
};
readDiv.querySelector('.ejwoomreadhtml').onclick = () => {
if (!loadedHtmlContent) return alert('No file loaded.');
const parser = new DOMParser();
const doc = parser.parseFromString(loadedHtmlContent, 'text/html');
let bodyHtml = parseAndLoadHTML(doc);
textarea.value = rebuildAttachmentsFromHTML(bodyHtml).trim();
switchToEditTab();
};
readDiv.querySelector('.ejwoomreadbutton').onclick = () => {
if (!loadedHtmlContent) return alert('No file loaded.');
const parser = new DOMParser();
const doc = parser.parseFromString(loadedHtmlContent, 'text/html');
parseAndLoadButtons(doc);
switchToEditTab();
};
};
});
</script>
</body>
</html>