Files
TK-Wiki-Newsletter/app/static/js/newsletter.js
smueller 90cdb7e922 Enhance newsletter functionality and UI improvements
- Introduce `create_outlook_html` function for generating Outlook-compatible newsletter HTML.
- Update dashboard to include `outlook_html` in the response.
- Modify newsletter generation logic to support separate handling of Outlook HTML.
- Improve CSS styles for newsletter preview and layout adjustments.
- Add new button for downloading HTML directly from the dashboard.
2026-07-03 13:07:33 +02:00

286 lines
9.4 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.
function setCopyStatus(message, isError) {
const status = document.getElementById("copy-status");
if (!status) return;
status.textContent = message;
status.className = isError ? "copy-status error" : "copy-status success";
}
function getNewsletterHtml() {
const htmlSource = document.getElementById("newsletter-html-source");
const htmlDisplay = document.getElementById("newsletter-html-display");
const value = htmlSource?.value.trim() || htmlDisplay?.value.trim() || "";
return value;
}
function getNewsletterOutlookHtml() {
const outlookSource = document.getElementById("newsletter-outlook-source");
const outlook = outlookSource ? outlookSource.value.trim() : "";
if (outlook) return outlook;
return getNewsletterHtml();
}
function getNewsletterPlain() {
const plainSource = document.getElementById("newsletter-plain-source");
return plainSource ? plainSource.value : "";
}
function wrapCfHtml(html) {
const fragmentStart = "<!--StartFragment-->";
const fragmentEnd = "<!--EndFragment-->";
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
const inner = bodyMatch ? bodyMatch[1].trim() : html;
const documentHtml = `<html><body>${fragmentStart}${inner}${fragmentEnd}</body></html>`;
const pad = (value) => String(value).padStart(10, "0");
const headerPlaceholder = "StartHTML:0000000000\r\nEndHTML:0000000000\r\nStartFragment:0000000000\r\nEndFragment:0000000000\r\n";
const prefix = `Version:0.9\r\n${headerPlaceholder}`;
const startHtml = prefix.length;
const endHtml = startHtml + documentHtml.length;
const startFragment = startHtml + documentHtml.indexOf(fragmentStart) + fragmentStart.length;
const endFragment = startHtml + documentHtml.indexOf(fragmentEnd);
return (
`Version:0.9\r\n` +
`StartHTML:${pad(startHtml)}\r\n` +
`EndHTML:${pad(endHtml)}\r\n` +
`StartFragment:${pad(startFragment)}\r\n` +
`EndFragment:${pad(endFragment)}\r\n` +
documentHtml
);
}
function copyFromTextarea(textarea) {
if (!textarea || !textarea.value) return false;
const previousActive = document.activeElement;
textarea.removeAttribute("readonly");
textarea.focus({ preventScroll: true });
textarea.select();
textarea.setSelectionRange(0, textarea.value.length);
let ok = false;
try {
ok = document.execCommand("copy");
} catch (err) {
console.warn("execCommand copy from textarea failed.", err);
ok = false;
} finally {
textarea.setAttribute("readonly", "");
if (previousActive && typeof previousActive.focus === "function") {
previousActive.focus({ preventScroll: true });
}
}
return ok;
}
function copyTextWithFallback(text) {
if (!text) return false;
const pageTextareas = [
document.getElementById("newsletter-html-display"),
document.getElementById("newsletter-html-source"),
document.getElementById("newsletter-outlook-source"),
document.getElementById("newsletter-plain-source"),
];
for (const textarea of pageTextareas) {
if (textarea && textarea.value === text && copyFromTextarea(textarea)) {
return true;
}
}
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.setAttribute("aria-hidden", "true");
textarea.style.position = "fixed";
textarea.style.top = "0";
textarea.style.left = "0";
textarea.style.width = "2px";
textarea.style.height = "2px";
textarea.style.padding = "0";
textarea.style.border = "none";
textarea.style.outline = "none";
textarea.style.boxShadow = "none";
textarea.style.background = "transparent";
document.body.appendChild(textarea);
let ok = false;
try {
textarea.focus({ preventScroll: true });
textarea.select();
textarea.setSelectionRange(0, text.length);
ok = document.execCommand("copy");
} catch (err) {
console.warn("execCommand copy from temporary textarea failed.", err);
ok = false;
} finally {
document.body.removeChild(textarea);
}
return ok;
}
function copyHtmlWithFallback(html) {
const container = document.createElement("div");
container.innerHTML = html;
container.contentEditable = "true";
container.setAttribute("aria-hidden", "true");
container.style.position = "fixed";
container.style.left = "0";
container.style.top = "0";
container.style.width = "600px";
container.style.height = "1px";
container.style.overflow = "hidden";
container.style.opacity = "0";
container.style.pointerEvents = "none";
container.style.background = "#FFFFFF";
document.body.appendChild(container);
const range = document.createRange();
range.selectNodeContents(container);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
let ok = false;
try {
ok = document.execCommand("copy");
} catch (err) {
console.warn("execCommand HTML copy failed.", err);
ok = false;
} finally {
selection.removeAllRanges();
document.body.removeChild(container);
}
if (!ok) {
ok = copyTextWithFallback(wrapCfHtml(html));
}
return ok;
}
async function copyText(text) {
if (!text) return false;
if (copyTextWithFallback(text)) {
return true;
}
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (err) {
console.warn("Clipboard API text copy failed.", err);
}
}
return false;
}
async function copyForOutlook() {
const html = getNewsletterOutlookHtml();
const plain = getNewsletterPlain();
if (!html) {
setCopyStatus("Bitte zuerst einen Newsletter generieren.", true);
return;
}
if (copyHtmlWithFallback(html)) {
setCopyStatus("Newsletter für Outlook kopiert. Mit Strg+V einfügen (ggf. „Format beibehalten“).");
return;
}
const cfHtml = wrapCfHtml(html);
if (navigator.clipboard && window.ClipboardItem && window.isSecureContext) {
try {
await navigator.clipboard.write([
new ClipboardItem({
"text/html": new Blob([cfHtml], { type: "text/html" }),
"text/plain": new Blob([plain], { type: "text/plain" }),
}),
]);
setCopyStatus("Newsletter für Outlook kopiert. Mit Strg+V einfügen (ggf. „Format beibehalten“).");
return;
} catch (err) {
console.warn("Clipboard API HTML copy failed.", err);
}
}
setCopyStatus("Kopieren fehlgeschlagen. Bitte „HTML herunterladen“ verwenden.", true);
}
async function copyHtmlSource() {
const html = getNewsletterHtml();
if (!html) {
setCopyStatus("Bitte zuerst einen Newsletter generieren.", true);
return;
}
const displayArea = document.getElementById("newsletter-html-display");
const sourceArea = document.getElementById("newsletter-html-source");
const textarea = displayArea?.value ? displayArea : sourceArea;
if (textarea && copyFromTextarea(textarea)) {
setCopyStatus("HTML-Quelltext kopiert.");
return;
}
if (copyTextWithFallback(html)) {
setCopyStatus("HTML-Quelltext kopiert.");
return;
}
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(html);
setCopyStatus("HTML-Quelltext kopiert.");
return;
} catch (err) {
console.warn("Clipboard API HTML source copy failed.", err);
}
}
if (textarea) {
textarea.focus({ preventScroll: true });
textarea.select();
}
setCopyStatus(
"Automatisches Kopieren nicht möglich. HTML-Feld unten ist markiert bitte Strg+C drücken.",
true
);
}
function downloadHtml() {
const html = getNewsletterOutlookHtml();
if (!html) {
setCopyStatus("Bitte zuerst einen Newsletter generieren.", true);
return;
}
const stamp = new Date().toISOString().slice(0, 10);
const filename = `wiki-newsletter-${stamp}.html`;
const blob = new Blob([html], { type: "text/html;charset=utf-8" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
setCopyStatus(`HTML gespeichert als ${filename}. Datei in Outlook öffnen oder Inhalt kopieren.`);
}
document.addEventListener("DOMContentLoaded", () => {
const outlookSource = document.getElementById("newsletter-outlook-source");
const htmlSource = document.getElementById("newsletter-html-source");
const frame = document.getElementById("newsletter-preview-frame");
const previewHtml = outlookSource?.value.trim() || htmlSource?.value.trim() || "";
if (frame && previewHtml) {
frame.srcdoc = previewHtml;
}
document.getElementById("copy-outlook-btn")?.addEventListener("click", copyForOutlook);
document.getElementById("copy-html-source-btn")?.addEventListener("click", copyHtmlSource);
document.getElementById("download-html-btn")?.addEventListener("click", downloadHtml);
});