function generateNewsletter() {
const idOrder = storyOrder.map(s => parseInt(s.split(':')[0], 10));
- let html = '';
+ let headerHtml = '';
// Table of contents
if (entries.length) {
@@ -911,9 +935,9 @@
Links sent in previous newsletters
return indexA - indexB;
});
- html += '
In this newsletter:
';
- html += sortedEntries.map(e => `
${e.title}
`).join('\n');
- html += '
';
+ headerHtml += '
In this newsletter:
';
+ headerHtml += sortedEntries.map(e => `
${e.title}
`).join('\n');
+ headerHtml += '
';
}
// Summary of extras
@@ -931,11 +955,11 @@
Links sent in previous newsletters
extras.push(`${notes.length} note${notes.length > 1 ? 's' : ''}`);
}
if (extras.length) {
- html += `
Plus ${extras.join(' and ')}
`;
+ headerHtml += `
Plus ${extras.join(' and ')}
`;
}
// Sponsor message
- html += `
If you find this newsletter useful, please consider sponsoring me via GitHub. $10/month and higher sponsors get a monthly newsletter with my summary of the most important trends of the past 30 days - here are previews from October and November.
`;
+ headerHtml += `
If you find this newsletter useful, please consider sponsoring me via GitHub. $10/month and higher sponsors get a monthly newsletter with my summary of the most important trends of the past 30 days - here are previews from October and November.
`;
// Content sorted by story order
const sortedContent = [...content].sort((a, b) => {
@@ -945,21 +969,53 @@
Links sent in previous newsletters
return indexA - indexB;
});
- html += sortedContent.map(c => c.html + '').join('\n');
-
- // Apply URL replacements
- for (const [oldUrl, newUrl] of urlReplacements) {
- html = html.split(oldUrl).join(newUrl);
+ // Apply URL replacements helper
+ function applyReplacements(html) {
+ for (const [oldUrl, newUrl] of urlReplacements) {
+ html = html.split(oldUrl).join(newUrl);
+ }
+ return html;
}
- newsletterHTML = html;
+ // Clean newsletter HTML (for copying)
+ let html = headerHtml + sortedContent.map(c => c.html + '').join('\n');
+ newsletterHTML = applyReplacements(html);
htmlLengthEl.textContent = `Length of HTML: ${newsletterHTML.length.toLocaleString()} characters`;
- previewEl.innerHTML = html;
+
+ // Preview HTML with delete buttons for non-entry items
+ const previewContentHtml = sortedContent.map(c => {
+ const itemHtml = applyReplacements(c.html);
+ if (c.type !== 'entry') {
+ return `