131 lines
4.6 KiB
Plaintext
131 lines
4.6 KiB
Plaintext
(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
|
|
};
|
|
})();
|