From 534f79b6176ed1130d05a60f2108747a1384f981 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Tue, 9 Dec 2025 01:27:20 +0100 Subject: [PATCH] asdasd --- public/assets/js/bridge/blocks-custom.js | 306 +-------------- public/assets/js/bridge/blocks-placeholder.js | 352 ++++++++++++++++++ public/assets/js/bridge/category-config.js | 7 + 3 files changed, 361 insertions(+), 304 deletions(-) create mode 100644 public/assets/js/bridge/blocks-placeholder.js diff --git a/public/assets/js/bridge/blocks-custom.js b/public/assets/js/bridge/blocks-custom.js index 14b2355..7bae7b8 100644 --- a/public/assets/js/bridge/blocks-custom.js +++ b/public/assets/js/bridge/blocks-custom.js @@ -31,10 +31,10 @@ const TARGET_CAT_ID = 'bausteine'; const ALL_CUSTOM_BLOCK_IDS = []; - function addOnce(bm, id, def) { + function addOnce(bm, id, def, category = TARGET_CAT_ID) { // Hinzufügen des Blocks und Sicherstellen der Kategorie-Zuweisung try { - bm.add(id, { ...def, category: TARGET_CAT_ID }); + bm.add(id, { ...def, category }); ALL_CUSTOM_BLOCK_IDS.push(id); log('BLOCK ADD', `Block '${id}' erfolgreich hinzugefügt.`, '#B8860B'); } catch (e) { @@ -44,312 +44,10 @@ const css = o => Object.entries(o).map(([k,v]) => `${k}:${v}`).join(';'); - const PLACEHOLDER_COMPONENT = 'placeholder-block'; - const placeholderSchemaStore = { - promise: null, - tables: [], - status: null, - statusPromise: null, - }; - - const ensureBridgeAvailability = () => { - if (placeholderSchemaStore.status !== null) { - return Promise.resolve(placeholderSchemaStore.status); - } - if (placeholderSchemaStore.statusPromise) { - return placeholderSchemaStore.statusPromise; - } - const base = B.API_KERNEL_URL || '/api.php'; - const sep = base.includes('?') ? '&' : '?'; - const url = `${base}${sep}action=placeholders.status`; - placeholderSchemaStore.statusPromise = fetch(url, { credentials: 'include' }) - .then(res => { - if (!res.ok) throw new Error(`HTTP ${res.status}`); - return res.json(); - }) - .then(data => { - const available = !!(data && (data.available || (data.settings && data.settings.available))); - placeholderSchemaStore.status = available; - placeholderSchemaStore.statusPromise = null; - if (!available) { - log('PLACEHOLDER INFO', 'Bridge-Placeholders nicht konfiguriert – DB-Funktionen deaktiviert.', '#64748b'); - } - return available; - }) - .catch(err => { - placeholderSchemaStore.status = false; - placeholderSchemaStore.statusPromise = null; - log('PLACEHOLDER WARN', `Bridge-Status konnte nicht geprüft werden: ${err && err.message ? err.message : err}`, '#b45309'); - return false; - }); - return placeholderSchemaStore.statusPromise; - }; - - const fetchPlaceholderSchema = () => { - if (placeholderSchemaStore.promise) return placeholderSchemaStore.promise; - placeholderSchemaStore.promise = ensureBridgeAvailability().then(isAvailable => { - if (!isAvailable) throw new Error('Bridge not available'); - const base = B.API_KERNEL_URL || '/api.php'; - const sep = base.includes('?') ? '&' : '?'; - const url = `${base}${sep}action=placeholders.schema`; - return fetch(url, { credentials: 'include' }) - .then(res => { - if (!res.ok) throw new Error(`HTTP ${res.status}`); - return res.json(); - }) - .then(data => { - const tbls = data && Array.isArray(data.tables) ? data.tables : []; - placeholderSchemaStore.tables = tbls; - return placeholderSchemaStore.tables; - }); - }).catch(err => { - placeholderSchemaStore.tables = []; - placeholderSchemaStore.promise = null; - const msg = err && err.message ? err.message : err; - if (msg === 'Bridge not available') { - log('PLACEHOLDER INFO', 'Schema-Abfrage übersprungen (keine Bridge verfügbar).', '#64748b'); - } else { - log('PLACEHOLDER ERROR', `Schema konnte nicht geladen werden: ${msg}`, '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') || 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]; - } - } - placeholderDefaults.name = 'Placeholder'; - placeholderDefaults.tagName = 'span'; - placeholderDefaults.droppable = false; - placeholderDefaults.attributes = { - 'data-placeholder-type': 'custom', - 'data-placeholder-key': 'UEBERSCHRIFT', - }; - placeholderDefaults.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, - }, - ]; - - const PlaceholderModel = BaseModel.extend({ - 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 && tableTrait.view && tableTrait.view.el) { - tableTrait.view.el.style.display = isDb ? '' : 'none'; - } - if (columnTrait && columnTrait.view && columnTrait.view.el) { - columnTrait.view.el.style.display = isDb ? '' : 'none'; - } - if (keyTrait && keyTrait.view && 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(function (tbl) { return { 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(function (tbl) { return tbl.name.toLowerCase() === tableName; }); - const colOpts = table - ? table.columns.map(function (col) { return { 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(); - const onlyText = comps.length === 1 && comps.at(0).is('textnode'); - if (onlyText) { - comps.at(0).set('content', text); - } else { - comps.reset([{ type: 'textnode', content: text }]); - } - } - }); - - PlaceholderModel.prototype.defaults = placeholderDefaults; - - 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); - 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; - }, - }); - - domc.addType(PLACEHOLDER_COMPONENT, { - model: PlaceholderModel, - view: PlaceholderView, - }); - }; - - 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 (Custom) - const customPlaceholderBlock = { - id: 'cust-placeholder-custom', - label: '🔖 Placeholder (Text)', - content: `{{UEBERSCHRIFT}}` - }; - addOnce(bm, customPlaceholderBlock.id, customPlaceholderBlock); - - // Datenbank Placeholder – erst registrieren, wenn Tabellen verfügbar - fetchPlaceholderSchema() - .then(tables => { - if (!tables || !tables.length) { - log('PLACEHOLDER INFO', 'Keine Tabellen – DB Placeholder Block wird nicht angezeigt.', '#888'); - return; - } - const firstTable = tables[0] || {}; - const tableName = firstTable.name || 'tabelle'; - const columns = Array.isArray(firstTable.columns) ? firstTable.columns : []; - const firstColumn = columns.length ? columns[0].name : 'feld'; - const placeholderLabel = (tableName + '.' + firstColumn).toUpperCase(); - addOnce(bm, 'cust-placeholder-db', { - id: 'cust-placeholder-db', - label: '🗄️ Placeholder (DB)', - content: `{{${placeholderLabel}}}` - }); - }) - .catch(() => { - log('PLACEHOLDER WARN', 'DB Placeholder Block ausgeblendet (Schemafehler).', '#b45309'); - }); // TEXT addOnce(bm, 'cust-text', { id:'cust-text', label:'📝 Text', diff --git a/public/assets/js/bridge/blocks-placeholder.js b/public/assets/js/bridge/blocks-placeholder.js new file mode 100644 index 0000000..e195e9b --- /dev/null +++ b/public/assets/js/bridge/blocks-placeholder.js @@ -0,0 +1,352 @@ +/* /assets/js/bridge/blocks-placeholder.js (LOG-KONTROLLIERT) */ +(function () { + const PluginName = 'blocks-placeholder'; + const B = window.BridgeParts || (window.BridgeParts = {}); + + if (B.LOG_CONFIG && B.LOG_CONFIG.PLUGINS) { + B.LOG_CONFIG.PLUGINS[PluginName] = false; // Lokaler Schalter für dieses Plugin + } + + 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') { + console.error(`%c[${PluginName} - ${type}] %c${message}`, `color:red; font-weight:bold;`, 'color:inherit;'); + } + }; + + log('FILE CHECK', 'Placeholder-Datei-IIFE startet.'); + + if (window.__PLACEHOLDER_BLOCKS_LOADED) return; + window.__PLACEHOLDER_BLOCKS_LOADED = true; + + const TARGET_CAT_ID = 'placeholders'; + const PLACEHOLDER_COMPONENT = 'placeholder-block'; + const ALL_PLACEHOLDER_BLOCK_IDS = []; + + const placeholderSchemaStore = { + promise: null, + tables: [], + status: null, + statusPromise: null, + }; + + function addOnce(bm, id, def, category = TARGET_CAT_ID) { + try { + bm.add(id, { ...def, category }); + ALL_PLACEHOLDER_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 ensureBridgeAvailability = () => { + if (placeholderSchemaStore.status !== null) { + return Promise.resolve(placeholderSchemaStore.status); + } + if (placeholderSchemaStore.statusPromise) { + return placeholderSchemaStore.statusPromise; + } + const base = B.API_KERNEL_URL || '/api.php'; + const sep = base.includes('?') ? '&' : '?'; + const url = `${base}${sep}action=placeholders.status`; + placeholderSchemaStore.statusPromise = fetch(url, { credentials: 'include' }) + .then(res => { + if (!res.ok) throw new Error(`HTTP ${res.status}`); + return res.json(); + }) + .then(data => { + const available = !!(data && (data.available || (data.settings && data.settings.available))); + placeholderSchemaStore.status = available; + placeholderSchemaStore.statusPromise = null; + if (!available) { + log('PLACEHOLDER INFO', 'Bridge-Placeholders nicht konfiguriert – DB-Funktionen deaktiviert.', '#64748b'); + } + return available; + }) + .catch(err => { + placeholderSchemaStore.status = false; + placeholderSchemaStore.statusPromise = null; + log('PLACEHOLDER WARN', `Bridge-Status konnte nicht geprüft werden: ${err && err.message ? err.message : err}`, '#b45309'); + return false; + }); + return placeholderSchemaStore.statusPromise; + }; + + const fetchPlaceholderSchema = () => { + if (placeholderSchemaStore.promise) return placeholderSchemaStore.promise; + placeholderSchemaStore.promise = ensureBridgeAvailability().then(isAvailable => { + if (!isAvailable) throw new Error('Bridge not available'); + const base = B.API_KERNEL_URL || '/api.php'; + const sep = base.includes('?') ? '&' : '?'; + const url = `${base}${sep}action=placeholders.schema`; + return fetch(url, { credentials: 'include' }) + .then(res => { + if (!res.ok) throw new Error(`HTTP ${res.status}`); + return res.json(); + }) + .then(data => { + const tbls = data && Array.isArray(data.tables) ? data.tables : []; + placeholderSchemaStore.tables = tbls; + return placeholderSchemaStore.tables; + }); + }).catch(err => { + placeholderSchemaStore.tables = []; + placeholderSchemaStore.promise = null; + const msg = err && err.message ? err.message : err; + if (msg === 'Bridge not available') { + log('PLACEHOLDER INFO', 'Schema-Abfrage übersprungen (keine Bridge verfügbar).', '#64748b'); + } else { + log('PLACEHOLDER ERROR', `Schema konnte nicht geladen werden: ${msg}`, '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') || 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]; + } + } + placeholderDefaults.name = 'Placeholder'; + placeholderDefaults.tagName = 'span'; + placeholderDefaults.droppable = false; + placeholderDefaults.attributes = { + 'data-placeholder-type': 'custom', + 'data-placeholder-key': 'UEBERSCHRIFT', + }; + placeholderDefaults.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, + }, + ]; + + const PlaceholderModel = BaseModel.extend({ + 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 && tableTrait.view && tableTrait.view.el) { + tableTrait.view.el.style.display = isDb ? '' : 'none'; + } + if (columnTrait && columnTrait.view && columnTrait.view.el) { + columnTrait.view.el.style.display = isDb ? '' : 'none'; + } + if (keyTrait && keyTrait.view && 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(function (tbl) { return { 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(function (tbl) { return tbl.name.toLowerCase() === tableName; }); + const colOpts = table + ? table.columns.map(function (col) { return { 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(); + const onlyText = comps.length === 1 && comps.at(0).is('textnode'); + if (onlyText) { + comps.at(0).set('content', text); + } else { + comps.reset([{ type: 'textnode', content: text }]); + } + } + }); + + PlaceholderModel.prototype.defaults = placeholderDefaults; + + 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); + 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; + }, + }); + + domc.addType(PLACEHOLDER_COMPONENT, { + model: PlaceholderModel, + view: PlaceholderView, + }); + }; + + 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 Placeholder-Registrierung für ${TARGET_CAT_ID}.`, '#DAA520'); + + const bm = editor.BlockManager; + ensurePlaceholderComponent(editor); + + addOnce(bm, 'cust-placeholder-custom', { + id: 'cust-placeholder-custom', + label: '🔖 Placeholder (Text)', + content: `{{UEBERSCHRIFT}}` + }); + + fetchPlaceholderSchema() + .then(tables => { + if (!tables || !tables.length) { + log('PLACEHOLDER INFO', 'Keine Tabellen – DB Placeholder Block wird nicht angezeigt.', '#888'); + return; + } + const firstTable = tables[0] || {}; + const tableName = firstTable.name || 'tabelle'; + const columns = Array.isArray(firstTable.columns) ? firstTable.columns : []; + const firstColumn = columns.length ? columns[0].name : 'feld'; + const placeholderLabel = (tableName + '.' + firstColumn).toUpperCase(); + addOnce(bm, 'cust-placeholder-db', { + id: 'cust-placeholder-db', + label: '🗄️ Placeholder (DB)', + content: `{{${placeholderLabel}}}` + }); + }) + .catch(() => { + log('PLACEHOLDER WARN', 'DB Placeholder Block ausgeblendet (Schemafehler).', '#b45309'); + }); + + log('SUCCESS', `Placeholder-Registrierung abgeschlossen. ${ALL_PLACEHOLDER_BLOCK_IDS.length} Blöcke erstellt.`, '#008000', 'info', true); + } + + window.BridgeBlocksPlaceholder = { + IDS: ALL_PLACEHOLDER_BLOCK_IDS, + register + }; + + if (B && B.registerGrapesJSPlugin && typeof register === 'function') { + B.registerGrapesJSPlugin('bridge-blocks-placeholder', register); + log('PLUGIN REGISTER', `'bridge-blocks-placeholder' erfolgreich registriert.`, '#008000'); + } else { + log('CRITICAL ERROR', `BridgeParts oder registerGrapesJSPlugin fehlt! Placeholder Plugin-Registrierung gescheitert.`, 'red', 'error'); + } +})(); diff --git a/public/assets/js/bridge/category-config.js b/public/assets/js/bridge/category-config.js index 25f596c..0a2cfaf 100644 --- a/public/assets/js/bridge/category-config.js +++ b/public/assets/js/bridge/category-config.js @@ -17,6 +17,13 @@             files: ['blocks-standard.js'], registration_mode: 'sync',         }, + placeholders: { + ord: 5, + open: true, + label: '🔖 Placeholder', + files: ['blocks-placeholder.js'], + registration_mode: 'sync', + },         // --- 2. BAUSTEINE (bausteine) ---         bausteine: {             // ... (Bleibt unverändert, da es kein API-Async-Laden nutzt)