/* /assets/js/bridge/blocks-custom.js (FINAL & LOG-KONTROLLIERT) */ (function () { const PluginName = 'blocks-custom'; const B = window.BridgeParts || (window.BridgeParts = {}); // ---------------------------------------------------------------------- // 🎯 NEU: LOKALE LOG-KONFIGURATION UND WRAPPER // ---------------------------------------------------------------------- // Setzen Sie dies auf 'false' in der config.js oder hier, um alle Logs NUR für dieses Plugin zu deaktivieren. if (B.LOG_CONFIG && B.LOG_CONFIG.PLUGINS) { B.LOG_CONFIG.PLUGINS[PluginName] = false; // <-- HIER IST IHR SCHALTER } // NEUER LOKALER WRAPPER, der die zentrale B.log Funktion verwendet: const log = (type, message, color = '#FFD700', logType = 'info', force = false) => { if (typeof B.log === 'function') { B.log(PluginName, `[${type}] ${message}`, color, logType, force); } else if (logType === 'error') { // Fallback für kritische Fehler, wenn B.log fehlt console.error(`%c[${PluginName} - ${type}] %c${message}`, `color:red; font-weight:bold;`, 'color:inherit;'); } }; // ---------------------------------------------------------------------- log('FILE CHECK', 'Datei-IIFE startet.'); // NEU: Kontrollierbarer Start-Log if (window.__CUSTOM_BLOCKS_LOADED) return; window.__CUSTOM_BLOCKS_LOADED = true; const TARGET_CAT_ID = 'bausteine'; const ALL_CUSTOM_BLOCK_IDS = []; function addOnce(bm, id, def) { // Hinzufügen des Blocks und Sicherstellen der Kategorie-Zuweisung try { bm.add(id, { ...def, category: TARGET_CAT_ID }); ALL_CUSTOM_BLOCK_IDS.push(id); log('BLOCK ADD', `Block '${id}' erfolgreich hinzugefügt.`, '#B8860B'); } catch (e) { log('BLOCK ERROR', `Fehler beim Hinzufügen von Block '${id}': ${e.message}`, 'red', 'error'); } } const css = o => Object.entries(o).map(([k,v]) => `${k}:${v}`).join(';'); const PLACEHOLDER_COMPONENT = 'placeholder-block'; const placeholderSchemaStore = { promise: null, tables: [], }; const fetchPlaceholderSchema = () => { if (placeholderSchemaStore.promise) return placeholderSchemaStore.promise; const base = B.API_KERNEL_URL || '/api.php'; const sep = base.includes('?') ? '&' : '?'; const url = `${base}${sep}action=placeholders.schema`; placeholderSchemaStore.promise = fetch(url, { credentials: 'include' }) .then(res => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }) .then(data => { placeholderSchemaStore.tables = Array.isArray(data?.tables) ? data.tables : []; return placeholderSchemaStore.tables; }) .catch(err => { placeholderSchemaStore.tables = []; placeholderSchemaStore.promise = null; log('PLACEHOLDER ERROR', `Schema konnte nicht geladen werden: ${err.message || err}`, 'red', 'error'); throw err; }); return placeholderSchemaStore.promise; }; const getTraitByName = (model, name) => { if (typeof model.getTrait === 'function') return model.getTrait(name); const traits = model.get('traits'); if (!traits) return null; if (typeof traits.where === 'function') { const found = traits.where({ name }); return found && found[0]; } if (Array.isArray(traits.models)) { return traits.models.find(t => t.get && t.get('name') === name) || null; } return null; }; const ensurePlaceholderComponent = (editor) => { const domc = editor.DomComponents; if (domc.getType(PLACEHOLDER_COMPONENT)) return; const baseType = domc.getType('text') ? 'text' : 'default'; domc.addType(PLACEHOLDER_COMPONENT, { extend: baseType, isComponent(el) { if (el && el.hasAttribute && el.hasAttribute('data-placeholder-type')) { return { type: PLACEHOLDER_COMPONENT }; } return false; }, model: { defaults: { name: 'Placeholder', tagName: 'span', droppable: false, attributes: { 'data-placeholder-type': 'custom', 'data-placeholder-key': 'UEBERSCHRIFT', }, traits: [ { type: 'select', name: 'data-placeholder-type', label: 'Typ', options: [ { id: 'custom', label: 'Allgemein' }, { id: 'database', label: 'Datenbank' }, ], changeProp: true, }, { type: 'text', name: 'data-placeholder-key', label: 'Bezeichner', placeholder: 'UEBERSCHRIFT', changeProp: true, }, { type: 'select', name: 'data-placeholder-table', label: 'Tabelle', options: [], changeProp: true, }, { type: 'select', name: 'data-placeholder-column', label: 'Feld', options: [], changeProp: true, }, ], }, init() { this.listenTo(this, 'change:attributes', this.updatePlaceholderState); this.updatePlaceholderState(); fetchPlaceholderSchema() .then(() => this.updateSchemaTraits()) .catch(() => this.updateSchemaTraits([])); }, updatePlaceholderState() { const attrs = this.getAttributes(); const type = attrs['data-placeholder-type'] || 'custom'; if (type === 'database' && placeholderSchemaStore.tables.length === 0) { this.addAttributes({ 'data-placeholder-type': 'custom' }); } this.updateTraitVisibility(); this.updateSchemaTraits(); this.updateLabel(); }, updateTraitVisibility() { const attrs = this.getAttributes(); const type = attrs['data-placeholder-type'] || 'custom'; const isDb = type === 'database'; const tableTrait = getTraitByName(this, 'data-placeholder-table'); const columnTrait = getTraitByName(this, 'data-placeholder-column'); const keyTrait = getTraitByName(this, 'data-placeholder-key'); if (tableTrait?.view?.el) { tableTrait.view.el.style.display = isDb ? '' : 'none'; } if (columnTrait?.view?.el) { columnTrait.view.el.style.display = isDb ? '' : 'none'; } if (keyTrait?.view?.el) { keyTrait.view.el.style.display = isDb ? 'none' : ''; } }, updateSchemaTraits(tablesOverride) { const tables = Array.isArray(tablesOverride) ? tablesOverride : placeholderSchemaStore.tables; const tableTrait = getTraitByName(this, 'data-placeholder-table'); const columnTrait = getTraitByName(this, 'data-placeholder-column'); const loading = !tablesOverride && placeholderSchemaStore.promise && !tables.length; if (tableTrait) { let opts; if (tables.length) { opts = tables.map(tbl => ({ id: tbl.name, label: tbl.name })); } else if (loading) { opts = [{ id: '', label: 'Tabellen werden geladen…', disabled: true }]; } else { opts = [{ id: '', label: 'Keine Tabellen verfügbar', disabled: true }]; } setTraitOptions(tableTrait, opts); } if (columnTrait) { const attrs = this.getAttributes(); const tableName = (attrs['data-placeholder-table'] || '').toLowerCase(); const table = tables.find(tbl => tbl.name.toLowerCase() === tableName); const colOpts = table ? table.columns.map(col => ({ id: col.name, label: `${col.name} (${col.type})` })) : [{ id: '', label: table ? 'Keine Felder' : 'Feld wählen', disabled: !table }]; setTraitOptions(columnTrait, colOpts); } }, updateLabel() { const attrs = this.getAttributes(); const type = attrs['data-placeholder-type'] || 'custom'; let label; if (type === 'database') { const table = attrs['data-placeholder-table'] || 'TABELLE'; const column = attrs['data-placeholder-column'] || 'FELD'; label = `${table}.${column}`.toUpperCase(); } else { label = (attrs['data-placeholder-key'] || 'PLATZHALTER').toUpperCase(); } const text = `{{${label}}}`; const comps = this.components(); if (comps.length === 1 && comps.at(0).is('textnode')) { comps.at(0).set('content', text); } else { comps.reset([{ type: 'textnode', content: text }]); } }, }, view: editor.DomComponents.View.extend({ render() { editor.DomComponents.View.prototype.render.apply(this, arguments); this.el.classList.add('placeholder-block'); this.el.style.display = 'inline-block'; this.el.style.padding = '2px 8px'; this.el.style.border = '1px dashed #94a3b8'; this.el.style.borderRadius = '6px'; this.el.style.background = '#f1f5f9'; this.el.style.fontFamily = 'monospace'; this.el.style.fontSize = '12px'; return this; }, }), }); }; function setTraitOptions(trait, options) { if (!trait) return; trait.set('options', options); if (trait.view && typeof trait.view.render === 'function') { trait.view.render(); } } function register(editor) { log('EXECUTION', `Starte Block-Registrierung für ${TARGET_CAT_ID}.`, '#DAA520'); const bm = editor.BlockManager; ensurePlaceholderComponent(editor); // --- Custom-Blöcke DEFINIEREN --- // PLACEHOLDER addOnce(bm, 'cust-placeholder', { id: 'cust-placeholder', label: '🔖 Placeholder', content: `{{UEBERSCHRIFT}}` }); // TEXT addOnce(bm, 'cust-text', { id:'cust-text', label:'📝 Text', content:`
Dies ist ein Absatz. Doppelklick zum Bearbeiten.
|
Linke Spalte – Inhalt hier. |
Rechte Spalte – Inhalt hier. |
|
|
ÜberschriftBeschreibungstext … Mehr erfahren |
Kurzer Untertitel oder Einleitung.
Dein Unternehmen GmbH • Musterstraße 1 • 12345 Berlin