/** * TextStylingTune — Block Tune for Editor.js * Adds alignment, custom CSS class, custom CSS style, and HTML ID settings to blocks. */ class TextStylingTune { constructor({ api, block, data }) { this.api = api; this.block = block; this.data = data || { alignment: '', cssClass: '', customStyle: '', elementId: '', customAttrs: '' }; } static get isTune() { return true; } render() { const wrapper = document.createElement('div'); wrapper.className = 'cdx-settings-text-styling p-2 border-top'; wrapper.style.fontFamily = 'inherit'; const title = document.createElement('div'); title.className = 'small font-weight-bold text-primary mb-2'; title.innerHTML = ' Style & Alignment'; wrapper.appendChild(title); // Alignment row const alignWrapper = document.createElement('div'); alignWrapper.className = 'd-flex mb-2 align-items-center justify-content-start'; const alignments = [ { name: 'left', icon: '', title: 'Align Left' }, { name: 'center', icon: '', title: 'Align Center' }, { name: 'right', icon: '', title: 'Align Right' }, { name: 'justify', icon: '', title: 'Align Justify' } ]; alignments.forEach(align => { const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn btn-xs btn-light mr-1 border'; btn.style.width = '30px'; btn.style.height = '30px'; btn.style.padding = '0'; btn.title = align.title; if (this.data.alignment === align.name) { btn.className = 'btn btn-xs btn-info mr-1 border'; } btn.innerHTML = align.icon; btn.addEventListener('click', () => { this.data.alignment = this.data.alignment === align.name ? '' : align.name; alignWrapper.querySelectorAll('button').forEach((b, idx) => { b.className = (this.data.alignment === alignments[idx].name) ? 'btn btn-xs btn-info mr-1 border' : 'btn btn-xs btn-light mr-1 border'; }); this.applyTuneToBlock(); }); alignWrapper.appendChild(btn); }); wrapper.appendChild(alignWrapper); // CSS Class Group const classGroup = document.createElement('div'); classGroup.className = 'form-group mb-1'; const classLabel = document.createElement('label'); classLabel.className = 'small font-weight-bold text-secondary mb-0 d-block'; classLabel.innerText = 'CSS Class'; const classInput = document.createElement('input'); classInput.type = 'text'; classInput.className = 'form-control form-control-sm py-0'; classInput.style.height = '24px'; classInput.placeholder = 'e.g. lead text-primary font-weight-bold'; classInput.value = this.data.cssClass || ''; classInput.addEventListener('input', (e) => { this.data.cssClass = e.target.value.trim(); this.applyTuneToBlock(); }); classGroup.appendChild(classLabel); classGroup.appendChild(classInput); wrapper.appendChild(classGroup); // Custom CSS Style Group const styleGroup = document.createElement('div'); styleGroup.className = 'form-group mb-1'; const styleLabel = document.createElement('label'); styleLabel.className = 'small font-weight-bold text-secondary mb-0 d-block'; styleLabel.innerText = 'CSS Style'; const styleInput = document.createElement('input'); styleInput.type = 'text'; styleInput.className = 'form-control form-control-sm py-0'; styleInput.style.height = '24px'; styleInput.placeholder = 'e.g. color: #dc3545; font-size: 1.5rem;'; styleInput.value = this.data.customStyle || ''; styleInput.addEventListener('input', (e) => { this.data.customStyle = e.target.value.trim(); this.applyTuneToBlock(); }); styleGroup.appendChild(styleLabel); styleGroup.appendChild(styleInput); wrapper.appendChild(styleGroup); // HTML ID Group const idGroup = document.createElement('div'); idGroup.className = 'form-group mb-1'; const idLabel = document.createElement('label'); idLabel.className = 'small font-weight-bold text-secondary mb-0 d-block'; idLabel.innerText = 'Element ID'; const idInput = document.createElement('input'); idInput.type = 'text'; idInput.className = 'form-control form-control-sm py-0'; idInput.style.height = '24px'; idInput.placeholder = 'e.g. section-main-title'; idInput.value = this.data.elementId || ''; idInput.addEventListener('input', (e) => { this.data.elementId = e.target.value.trim(); this.applyTuneToBlock(); }); idGroup.appendChild(idLabel); idGroup.appendChild(idInput); wrapper.appendChild(idGroup); // Custom HTML Attributes Group const attrsGroup = document.createElement('div'); attrsGroup.className = 'form-group mb-0'; const attrsLabel = document.createElement('label'); attrsLabel.className = 'small font-weight-bold text-secondary mb-0 d-block'; attrsLabel.innerText = 'Custom Attributes'; const attrsInput = document.createElement('input'); attrsInput.type = 'text'; attrsInput.className = 'form-control form-control-sm py-0'; attrsInput.style.height = '24px'; attrsInput.placeholder = 'e.g. data-aos="fade-up" target="_blank"'; attrsInput.value = this.data.customAttrs || ''; attrsInput.addEventListener('input', (e) => { this.data.customAttrs = e.target.value.trim(); }); attrsGroup.appendChild(attrsLabel); attrsGroup.appendChild(attrsInput); wrapper.appendChild(attrsGroup); return wrapper; } applyTuneToBlock() { if (!this.block || !this.block.holder) return; const blockContent = this.block.holder.querySelector('.ce-block__content'); if (blockContent) { // Live alignment preview blockContent.style.textAlign = this.data.alignment || ''; // Live styling preview const currentElement = blockContent.firstElementChild; if (currentElement) { // Apply custom inline styles on top of defaults currentElement.style.cssText = this.data.customStyle || ''; } } } save() { return this.data; } wrap(blockContent) { // Applies styling during initial render / loading if (this.data.alignment) { blockContent.style.textAlign = this.data.alignment; } const currentElement = blockContent.firstElementChild; if (currentElement && this.data.customStyle) { currentElement.style.cssText = this.data.customStyle; } return blockContent; } } // Register globally window.SISEditorPlugins = window.SISEditorPlugins || {}; window.SISEditorPlugins['textStyling'] = { class: TextStylingTune };