/** * Simple WYSIWYG Editor * Lightweight rich text editor for publication content */ class WYSIWYGEditor { constructor(textareaId, options = {}) { this.textarea = document.getElementById(textareaId); this.options = { toolbar: ['bold', 'italic', 'underline', '|', 'link', 'image', '|', 'ul', 'ol', '|', 'h1', 'h2', 'h3'], ...options }; this.createEditor(); this.bindEvents(); } createEditor() { // Create editor container this.container = document.createElement('div'); this.container.className = 'wysiwyg-container'; // Create toolbar this.toolbar = document.createElement('div'); this.toolbar.className = 'wysiwyg-toolbar'; this.createToolbarButtons(); // Create content area this.content = document.createElement('div'); this.content.className = 'wysiwyg-content'; this.content.contentEditable = true; // Create character count this.charCount = document.createElement('div'); this.charCount.className = 'wysiwyg-char-count'; // Assemble editor this.container.appendChild(this.toolbar); this.container.appendChild(this.content); this.container.appendChild(this.charCount); // Replace textarea this.textarea.parentNode.insertBefore(this.container, this.textarea); this.textarea.style.display = 'none'; // Initialize content this.content.innerHTML = this.textarea.value; this.updateCharCount(); } createToolbarButtons() { this.options.toolbar.forEach(item => { if (item === '|') { const separator = document.createElement('div'); separator.className = 'wysiwyg-separator'; this.toolbar.appendChild(separator); } else { const button = document.createElement('button'); button.className = 'wysiwyg-btn'; button.type = 'button'; button.innerHTML = this.getButtonLabel(item); button.dataset.command = item; button.addEventListener('click', () => this.execCommand(item)); this.toolbar.appendChild(button); } }); } getButtonLabel(command) { const labels = { 'bold': 'B', 'italic': 'I', 'underline': 'U', 'link': '🔗', 'image': '🖼️', 'ul': '• List', 'ol': '1. List', 'h1': 'H1', 'h2': 'H2', 'h3': 'H3' }; return labels[command] || command; } execCommand(command) { switch (command) { case 'bold': document.execCommand('bold', false, null); break; case 'italic': document.execCommand('italic', false, null); break; case 'underline': document.execCommand('underline', false, null); break; case 'link': this.insertLink(); break; case 'image': this.insertImage(); break; case 'ul': document.execCommand('insertUnorderedList', false, null); break; case 'ol': document.execCommand('insertOrderedList', false, null); break; case 'h1': this.formatHeading('h1'); break; case 'h2': this.formatHeading('h2'); break; case 'h3': this.formatHeading('h3'); break; } this.content.focus(); } insertLink() { const selection = window.getSelection(); const url = prompt('Enter URL:'); if (url) { document.execCommand('createLink', false, url); } } insertImage() { const url = prompt('Enter image URL:'); if (url) { document.execCommand('insertImage', false, url); } } formatHeading(tag) { const selection = window.getSelection(); const range = selection.getRangeAt(0); const heading = document.createElement(tag); heading.textContent = range.toString(); range.deleteContents(); range.insertNode(heading); } bindEvents() { // Update textarea when content changes this.content.addEventListener('input', () => { this.textarea.value = this.content.innerHTML; this.updateCharCount(); }); // Update content when textarea changes (for form submission) this.textarea.addEventListener('input', () => { this.content.innerHTML = this.textarea.value; this.updateCharCount(); }); // Handle paste events this.content.addEventListener('paste', (e) => { e.preventDefault(); const text = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain'); document.execCommand('insertHTML', false, text); }); // Keyboard shortcuts this.content.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { switch (e.key) { case 'b': e.preventDefault(); this.execCommand('bold'); break; case 'i': e.preventDefault(); this.execCommand('italic'); break; case 'u': e.preventDefault(); this.execCommand('underline'); break; } } }); } updateCharCount() { const text = this.content.innerText || this.content.textContent || ''; const count = text.length; this.charCount.textContent = `Characters: ${count}`; } getContent() { return this.content.innerHTML; } setContent(html) { this.content.innerHTML = html; this.textarea.value = html; this.updateCharCount(); } destroy() { this.textarea.style.display = 'block'; this.textarea.value = this.content.innerHTML; this.container.remove(); } } // Initialize editor when DOM is ready document.addEventListener('DOMContentLoaded', () => { const editor = new WYSIWYGEditor('content'); // Make editor globally accessible window.wysiwygEditor = editor; // Handle form submission const form = document.querySelector('.publication-form'); if (form) { form.addEventListener('submit', () => { // Ensure textarea has latest content document.getElementById('content').value = editor.getContent(); }); } });