feat: enhance page block system with custom styling support and add TinyMCE rich editor integration
This commit is contained in:
+130
@@ -0,0 +1,130 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
class SISTinyMceTool {
|
||||
static get toolbox() {
|
||||
return {
|
||||
title: 'TinyMCE Editor',
|
||||
icon: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16v16H4z"></path><path d="M8 8h8"></path><path d="M12 8v8"></path><path d="M10 16h4"></path></svg>'
|
||||
};
|
||||
}
|
||||
|
||||
constructor({ data, api, readOnly }) {
|
||||
this.api = api;
|
||||
this.readOnly = readOnly;
|
||||
this.data = {
|
||||
html: data.html || ''
|
||||
};
|
||||
this.editorId = 'tinymce-editor-' + Math.random().toString(36).substring(7);
|
||||
this.editorInstance = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'sis-tinymce-block-wrapper border rounded p-2 bg-white';
|
||||
wrapper.style.minHeight = '280px';
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.id = this.editorId;
|
||||
textarea.value = this.data.html;
|
||||
textarea.style.width = '100%';
|
||||
textarea.style.minHeight = '250px';
|
||||
wrapper.appendChild(textarea);
|
||||
this.textareaElement = textarea;
|
||||
|
||||
this._initTinyMCE();
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
_initTinyMCE() {
|
||||
const self = this;
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
self._createEditor();
|
||||
return;
|
||||
}
|
||||
|
||||
// Global loading queue to prevent duplicate script tags
|
||||
window.SISTinyMceLoading = window.SISTinyMceLoading || {
|
||||
loaded: false,
|
||||
callbacks: []
|
||||
};
|
||||
|
||||
if (window.SISTinyMceLoading.loaded) {
|
||||
self._createEditor();
|
||||
return;
|
||||
}
|
||||
|
||||
window.SISTinyMceLoading.callbacks.push(() => {
|
||||
self._createEditor();
|
||||
});
|
||||
|
||||
if (window.SISTinyMceLoading.callbacks.length === 1) {
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/tinymce@6/tinymce.min.js';
|
||||
script.referrerPolicy = 'origin';
|
||||
script.onload = () => {
|
||||
window.SISTinyMceLoading.loaded = true;
|
||||
while (window.SISTinyMceLoading.callbacks.length > 0) {
|
||||
const cb = window.SISTinyMceLoading.callbacks.shift();
|
||||
try { cb(); } catch (e) { console.error(e); }
|
||||
}
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
}
|
||||
|
||||
_createEditor() {
|
||||
const self = this;
|
||||
const textarea = this.textareaElement || document.getElementById(this.editorId);
|
||||
if (!textarea) return;
|
||||
|
||||
// Wait until the element is actually attached to the document DOM
|
||||
const checkAndInit = () => {
|
||||
if (!document.body.contains(textarea)) {
|
||||
requestAnimationFrame(checkAndInit);
|
||||
return;
|
||||
}
|
||||
|
||||
tinymce.init({
|
||||
target: textarea,
|
||||
height: 250,
|
||||
menubar: false,
|
||||
readonly: !!self.readOnly,
|
||||
plugins: 'advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table code help wordcount',
|
||||
toolbar: 'undo redo | blocks | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table link image | code removeformat',
|
||||
setup: function(editor) {
|
||||
self.editorInstance = editor;
|
||||
editor.on('change keyup undo redo', function() {
|
||||
self.data.html = editor.getContent();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
checkAndInit();
|
||||
}
|
||||
|
||||
save(blockContent) {
|
||||
if (this.editorInstance) {
|
||||
this.data.html = this.editorInstance.getContent();
|
||||
}
|
||||
return {
|
||||
html: this.data.html
|
||||
};
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.editorInstance) {
|
||||
tinymce.remove(this.editorInstance);
|
||||
this.editorInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register globally
|
||||
window.SISEditorPlugins = window.SISEditorPlugins || {};
|
||||
window.SISEditorPlugins['tinymce'] = {
|
||||
class: SISTinyMceTool
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user