Release v2.2.0
This commit is contained in:
@@ -0,0 +1,332 @@
|
||||
export function createSlideFormEditorController(options) {
|
||||
var settings = options || {};
|
||||
var templateFields = settings.templateFields || null;
|
||||
var templateSelectorLock = settings.templateSelectorLock || null;
|
||||
var requestPreviewRender = typeof settings.requestPreviewRender === 'function' ? settings.requestPreviewRender : function () {};
|
||||
var defaultFontSize = Math.max(1, Number(settings.defaultFontSize || 32));
|
||||
var fontFamilyFormats = String(settings.fontFamilyFormats || '').trim();
|
||||
var fontStylesheetHref = String(settings.fontStylesheetHref || '').trim();
|
||||
var defaultEditorFontFamily = 'Arial, Helvetica, sans-serif';
|
||||
var editorInstances = new Map();
|
||||
var getRegionTypeModule = typeof settings.getRegionTypeModule === 'function' ? settings.getRegionTypeModule : function () {
|
||||
return null;
|
||||
};
|
||||
var getEditorBackgroundColor = typeof settings.getEditorBackgroundColor === 'function' ? settings.getEditorBackgroundColor : function () {
|
||||
return '#111111';
|
||||
};
|
||||
|
||||
function normalizeEditorData(value) {
|
||||
return String(value || '');
|
||||
}
|
||||
|
||||
function normalizeEditorMarkup(value) {
|
||||
return String(value === undefined || value === null ? '' : value).trim();
|
||||
}
|
||||
|
||||
function normalizeFontSizeValue(value) {
|
||||
var raw = String(value || '').trim().toLowerCase();
|
||||
if (/^\d+(?:\.\d+)?px$/.test(raw)) {
|
||||
return String(Math.max(1, Math.round(Number(raw.replace(/px$/, '')))));
|
||||
}
|
||||
if (/^\d+(?:\.\d+)?$/.test(raw)) {
|
||||
return String(Math.max(1, Math.round(Number(raw))));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getEditorHiddenInput(regionId) {
|
||||
if (!templateFields) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var card = templateFields.querySelector('[data-region-id="' + regionId + '"]');
|
||||
return card ? card.querySelector('input[type="hidden"][name="region_text_' + regionId + '"]') : null;
|
||||
}
|
||||
|
||||
function getEditorFontSizeHiddenInput(regionId) {
|
||||
if (!templateFields) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var card = templateFields.querySelector('[data-region-id="' + regionId + '"]');
|
||||
return card ? card.querySelector('input[name="region_font_size_' + regionId + '"]') : null;
|
||||
}
|
||||
|
||||
function getEditorRegionType(card) {
|
||||
if (!card) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (card.dataset && String(card.dataset.regionMediaType || '').trim()) {
|
||||
return String(card.dataset.regionMediaType || '').trim();
|
||||
}
|
||||
|
||||
var regionTypeInput = card.querySelector ? card.querySelector('input[type="hidden"][name="region_type[]"]') : null;
|
||||
return String(regionTypeInput && regionTypeInput.value || '').trim();
|
||||
}
|
||||
|
||||
function getEditorContentStyle(regionType) {
|
||||
var module = getRegionTypeModule(regionType);
|
||||
if (module && typeof module.getEditorContentStyle === 'function') {
|
||||
return String(module.getEditorContentStyle() || '').trim();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function syncEditorFontSizeHidden(regionId) {
|
||||
var fontSizeHidden = getEditorFontSizeHiddenInput(regionId);
|
||||
if (!fontSizeHidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
fontSizeHidden.value = normalizeFontSizeValue(fontSizeHidden.value) || String(defaultFontSize);
|
||||
}
|
||||
|
||||
function getTinymce() {
|
||||
return window.tinymce || null;
|
||||
}
|
||||
|
||||
function getThemeName() {
|
||||
var theme = String(document.documentElement && document.documentElement.dataset && document.documentElement.dataset.bsTheme || 'light').trim().toLowerCase();
|
||||
if (theme === 'auto') {
|
||||
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
return theme === 'dark' ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
function getTinyMceThemeAssets() {
|
||||
var themeName = getThemeName();
|
||||
var skinName = themeName === 'dark' ? 'oxide-dark' : 'oxide';
|
||||
var skinBase = '/assets/vendor/tinymce/skins/ui/' + skinName;
|
||||
return {
|
||||
themeName: themeName,
|
||||
skinName: skinName,
|
||||
skinUrl: skinBase,
|
||||
contentCss: skinBase + '/content.css',
|
||||
bodyClass: themeName === 'dark' ? 'tinymce-theme-dark' : 'tinymce-theme-light'
|
||||
};
|
||||
}
|
||||
|
||||
function getEditorBackgroundColorValue() {
|
||||
var value = String(getEditorBackgroundColor() || '').trim();
|
||||
return value || '#111111';
|
||||
}
|
||||
|
||||
function getFontFamilyFormats() {
|
||||
if (fontFamilyFormats) {
|
||||
return fontFamilyFormats;
|
||||
}
|
||||
|
||||
return [
|
||||
'Default=inherit',
|
||||
'Arial=Arial,Helvetica,sans-serif',
|
||||
'Comic Sans MS=Comic Sans MS,cursive,sans-serif',
|
||||
'Courier New=Courier New,Courier,monospace',
|
||||
'Georgia=Georgia,serif',
|
||||
'Helvetica=Helvetica,Arial,sans-serif',
|
||||
'Impact=Impact,Charcoal,sans-serif',
|
||||
'Lucida Sans Unicode=Lucida Sans Unicode,Lucida Grande,sans-serif',
|
||||
'Palatino Linotype=Palatino Linotype,Book Antiqua,Palatino,serif',
|
||||
'Tahoma=Tahoma,Geneva,sans-serif',
|
||||
'Times New Roman=Times New Roman,Times,serif',
|
||||
'Trebuchet MS=Trebuchet MS,Helvetica,sans-serif',
|
||||
'Verdana=Verdana,Geneva,sans-serif'
|
||||
].join(';');
|
||||
}
|
||||
|
||||
function getContentCss() {
|
||||
var themeAssets = getTinyMceThemeAssets();
|
||||
return fontStylesheetHref
|
||||
? [themeAssets.contentCss, fontStylesheetHref]
|
||||
: themeAssets.contentCss;
|
||||
}
|
||||
|
||||
function attachEditorEvents(regionId, editor) {
|
||||
var hidden = getEditorHiddenInput(regionId);
|
||||
var source = editor && editor.targetElm ? editor.targetElm : null;
|
||||
|
||||
function syncState() {
|
||||
var currentEditor = editorInstances.get(regionId);
|
||||
if (currentEditor !== editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof editor.save === 'function') {
|
||||
editor.save();
|
||||
}
|
||||
var content = editor.getContent({ format: 'html' });
|
||||
if (hidden) {
|
||||
hidden.value = content;
|
||||
}
|
||||
if (source) {
|
||||
source.value = content;
|
||||
}
|
||||
if (templateSelectorLock && typeof templateSelectorLock.markEdited === 'function') {
|
||||
templateSelectorLock.markEdited();
|
||||
}
|
||||
requestPreviewRender();
|
||||
}
|
||||
|
||||
editor.on('init', function () {
|
||||
var content = editor.getContent({ format: 'html' });
|
||||
if (hidden) {
|
||||
hidden.value = content;
|
||||
}
|
||||
if (source) {
|
||||
source.value = content;
|
||||
}
|
||||
syncEditorFontSizeHidden(regionId);
|
||||
syncState();
|
||||
});
|
||||
|
||||
['change', 'keyup', 'undo', 'redo', 'SetContent', 'Paste', 'input', 'NodeChange'].forEach(function (eventName) {
|
||||
editor.on(eventName, syncState);
|
||||
});
|
||||
}
|
||||
|
||||
function createEditorForHolder(holder) {
|
||||
if (!holder) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
var regionId = holder.getAttribute('data-region-id');
|
||||
var card = holder.closest ? holder.closest('[data-region-id]') : null;
|
||||
var source = holder.querySelector('.editor-source');
|
||||
var hidden = getEditorHiddenInput(regionId);
|
||||
var tinymce = getTinymce();
|
||||
var themeAssets = getTinyMceThemeAssets();
|
||||
var editorContentStyle = getEditorContentStyle(getEditorRegionType(card));
|
||||
|
||||
if (!source || !tinymce || typeof tinymce.init !== 'function') {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
source.value = normalizeEditorMarkup(normalizeEditorData(source && source.value !== undefined && source.value !== null ? source.value : (hidden ? hidden.value : '')));
|
||||
|
||||
if (!source.id) {
|
||||
source.id = 'slide-editor-region-' + regionId;
|
||||
}
|
||||
|
||||
return tinymce.init({
|
||||
target: source,
|
||||
menubar: false,
|
||||
branding: false,
|
||||
promotion: false,
|
||||
statusbar: true,
|
||||
resize: true,
|
||||
plugins: 'lists link code advlist fullscreen',
|
||||
toolbar: 'undo redo | fontfamily fontsizeinput | forecolor backcolor bold italic underline strikethrough subscript superscript removeformat | align lineheight indent outdent bullist numlist | fullscreen',
|
||||
toolbar_mode: 'sliding',
|
||||
license_key: 'gpl',
|
||||
skin: themeAssets.skinName,
|
||||
skin_url: themeAssets.skinUrl,
|
||||
content_css: getContentCss(),
|
||||
body_class: themeAssets.bodyClass,
|
||||
content_style: 'body { font-family: ' + defaultEditorFontFamily + '; font-size: 32px; line-height: 1.5; background-color: ' + getEditorBackgroundColorValue() + '; } p { margin: 1em 0; } p:first-child { margin-top: 0; } p:last-child { margin-bottom: 1em; }' + (editorContentStyle ? ' ' + editorContentStyle : ''),
|
||||
font_family_formats: getFontFamilyFormats(),
|
||||
font_size_input_default_unit: 'px',
|
||||
forced_root_block: 'p',
|
||||
force_br_newlines: false,
|
||||
newline_behavior: 'default',
|
||||
setup: function (editor) {
|
||||
editorInstances.set(regionId, editor);
|
||||
attachEditorEvents(regionId, editor);
|
||||
}
|
||||
}).then(function (editors) {
|
||||
var editor = Array.isArray(editors) && editors.length ? editors[0] : tinymce.get(source.id);
|
||||
if (!editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
editorInstances.set(regionId, editor);
|
||||
if (editor.targetElm) {
|
||||
editor.targetElm.value = editor.getContent({ format: 'html' });
|
||||
}
|
||||
return editor;
|
||||
}).catch(function (error) {
|
||||
console.error('Failed to initialize TinyMCE.', error);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function renderEditors() {
|
||||
if (!templateFields) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
watchThemeChanges();
|
||||
|
||||
var holders = Array.prototype.slice.call(templateFields.querySelectorAll('.editor-holder'));
|
||||
return Promise.all(holders.map(function (holder) {
|
||||
return createEditorForHolder(holder);
|
||||
}));
|
||||
}
|
||||
|
||||
function syncEditors() {
|
||||
if (!templateFields) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
var saves = Array.prototype.map.call(templateFields.querySelectorAll('.editor-holder'), function (holder) {
|
||||
var regionId = holder.getAttribute('data-region-id');
|
||||
var editor = editorInstances.get(regionId);
|
||||
var hidden = getEditorHiddenInput(regionId);
|
||||
|
||||
if (!editor || !hidden) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
hidden.value = editor.getContent({ format: 'html' });
|
||||
syncEditorFontSizeHidden(regionId);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
return Promise.all(saves);
|
||||
}
|
||||
|
||||
function destroyEditors() {
|
||||
editorInstances.forEach(function (editor) {
|
||||
if (editor && typeof editor.remove === 'function') {
|
||||
editor.remove();
|
||||
}
|
||||
});
|
||||
editorInstances.clear();
|
||||
|
||||
var tinymce = getTinymce();
|
||||
if (tinymce && typeof tinymce.remove === 'function') {
|
||||
tinymce.remove();
|
||||
}
|
||||
}
|
||||
|
||||
var themeObserver = null;
|
||||
|
||||
function watchThemeChanges() {
|
||||
if (themeObserver || !window.MutationObserver || !templateFields) {
|
||||
return;
|
||||
}
|
||||
|
||||
themeObserver = new MutationObserver(function () {
|
||||
destroyEditors();
|
||||
renderEditors();
|
||||
});
|
||||
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-bs-theme']
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
renderEditors: renderEditors,
|
||||
syncEditors: syncEditors,
|
||||
destroyEditors: function () {
|
||||
if (themeObserver) {
|
||||
themeObserver.disconnect();
|
||||
themeObserver = null;
|
||||
}
|
||||
destroyEditors();
|
||||
},
|
||||
watchThemeChanges: watchThemeChanges
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user