| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /**
- * 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();
- });
- }
- });
|