diff --git a/public/assets/js/bridge/blocks-placeholder.js b/public/assets/js/bridge/blocks-placeholder.js index 04faa33..e50809b 100644 --- a/public/assets/js/bridge/blocks-placeholder.js +++ b/public/assets/js/bridge/blocks-placeholder.js @@ -568,28 +568,29 @@ return null; }; - const ensurePlaceholderComponent = (editor) => { - const domc = editor.DomComponents; - if (domc.getType(PLACEHOLDER_COMPONENT)) return; - - const baseType = domc.getType('text') || domc.getType('default') || {}; - const BaseModel = baseType.model || editor.DomComponents.Component; - const BaseView = baseType.view || editor.DomComponents.View; - - const placeholderDefaults = {}; - if (BaseModel.prototype && BaseModel.prototype.defaults) { - for (const key in BaseModel.prototype.defaults) { - placeholderDefaults[key] = BaseModel.prototype.defaults[key]; - } + const cloneValue = (value) => { + if (Array.isArray(value)) { + return value.map(cloneValue); } - placeholderDefaults.name = 'Placeholder'; - placeholderDefaults.tagName = 'span'; - placeholderDefaults.droppable = false; - placeholderDefaults.attributes = { + if (value && typeof value === 'object') { + const copy = {}; + Object.keys(value).forEach(key => { + copy[key] = cloneValue(value[key]); + }); + return copy; + } + return value; + }; + + const defaultPlaceholderProps = { + name: 'Placeholder', + tagName: 'span', + droppable: false, + attributes: { 'data-placeholder-type': 'custom', 'data-placeholder-key': 'UEBERSCHRIFT', - }; - placeholderDefaults.traits = [ + }, + traits: [ { type: 'select', name: 'data-placeholder-type', @@ -621,17 +622,37 @@ options: [], changeProp: true, }, - ]; - const baseToolbar = Array.isArray(placeholderDefaults.toolbar) ? placeholderDefaults.toolbar.slice() : []; - baseToolbar.push({ - attributes: { class: 'fa fa-edit', title: 'Placeholder bearbeiten' }, - command: 'bridge-placeholder:edit', + ], + toolbar: [ + { + attributes: { class: 'fa fa-edit', title: 'Placeholder bearbeiten' }, + command: 'bridge-placeholder:edit', + }, + ], + }; + + const applyPlaceholderDefaults = (model) => { + if (!model || typeof model.get !== 'function' || typeof model.set !== 'function') { + return; + } + Object.entries(defaultPlaceholderProps).forEach(([key, value]) => { + if (typeof model.get(key) === 'undefined') { + model.set(key, cloneValue(value)); + } }); - placeholderDefaults.toolbar = baseToolbar; + }; + + const ensurePlaceholderComponent = (editor) => { + const domc = editor.DomComponents; + if (domc.getType(PLACEHOLDER_COMPONENT)) return; + + const baseType = domc.getType('text') || domc.getType('default') || {}; + const BaseModel = baseType.model || editor.DomComponents.Component; + const BaseView = baseType.view || editor.DomComponents.View; const PlaceholderModel = BaseModel.extend({ - defaults: placeholderDefaults, init() { + applyPlaceholderDefaults(this); this.listenTo(this, 'change:attributes', this.updatePlaceholderState); this.updatePlaceholderState(); fetchPlaceholderSchema() @@ -720,13 +741,6 @@ } }); - PlaceholderModel.isComponent = function (el) { - if (el && el.hasAttribute && el.hasAttribute('data-placeholder-type')) { - return { type: PLACEHOLDER_COMPONENT }; - } - return false; - }; - const PlaceholderView = BaseView.extend({ render() { BaseView.prototype.render.apply(this, arguments); @@ -745,44 +759,49 @@ domc.addType(PLACEHOLDER_COMPONENT, { model: PlaceholderModel, view: PlaceholderView, + isComponent(el) { + if (el && el.hasAttribute && el.hasAttribute('data-placeholder-type')) { + return { type: PLACEHOLDER_COMPONENT }; + } + return false; + }, }); }; + const patchTextComponentDroppable = (component) => { + if (!component || !component.is || !component.is('text')) { + return; + } + if (component.__bridgePlaceholderDroppable) { + return; + } + component.__bridgePlaceholderDroppable = true; + const originalDroppable = component.get('droppable'); + const allowFn = function (source, cmp) { + if (cmp && cmp.get && cmp.get('type') === PLACEHOLDER_COMPONENT) { + return true; + } + if (typeof originalDroppable === 'function') { + return originalDroppable.call(this, source, cmp); + } + if (typeof originalDroppable === 'undefined') { + return true; + } + return originalDroppable; + }; + component.set('droppable', allowFn); + }; + const ensureTextSupportsPlaceholders = (editor) => { - if (editor.__bridgeTextPlaceholderExtended) return; - const domc = editor.DomComponents; - const textType = domc.getType('text'); - if (!textType || !textType.model) return; - - const BaseModel = textType.model; - const BaseView = textType.view; - const baseDefaults = (BaseModel.prototype && BaseModel.prototype.defaults) ? BaseModel.prototype.defaults : {}; - const originalDroppable = baseDefaults.droppable; - const baseIsComponent = typeof textType.isComponent === 'function' ? textType.isComponent : null; - - const TextModel = BaseModel.extend({ - defaults: { - ...baseDefaults, - droppable(source, component) { - if (component && component.get && component.get('type') === PLACEHOLDER_COMPONENT) { - return true; - } - if (typeof originalDroppable === 'function') { - return originalDroppable.call(this, source, component); - } - return typeof originalDroppable === 'undefined' ? false : originalDroppable; - }, - }, - }, {}); - - domc.addType('text', { - model: TextModel, - isComponent: baseIsComponent || textType.isComponent, - view: BaseView, - }); - - editor.__bridgeTextPlaceholderExtended = true; - log('TEXT EXTEND', 'Text-Komponenten erlauben jetzt Placeholder als Inline-Drop.', '#DAA520'); + const wrapper = editor.getWrapper && editor.getWrapper(); + if (wrapper) { + if (typeof wrapper.findType === 'function') { + wrapper.findType('text').forEach(patchTextComponentDroppable); + } else if (typeof wrapper.find === 'function') { + wrapper.find('[data-gjs-type="text"]').forEach(patchTextComponentDroppable); + } + } + editor.on('component:add', (cmp) => patchTextComponentDroppable(cmp)); }; function setTraitOptions(trait, options) {