Files
emailtemplate.it/public/assets/js/bridge/blocks-api (Kopie).js
2025-12-04 22:33:05 +01:00

208 lines
11 KiB
JavaScript

/* /assets/js/bridge/blocks-api.js (SCHRITT 16: Finaler Stabilitäts-Fix) */
(function (B) {
// 🛑 KRITISCHER FIX: Nur minimale Prüfung, um synchrone Initialisierung zu garantieren
if (!B || typeof grapesjs === 'undefined') {
console.warn("[BRIDGE-API] blocks-api.js: BridgeParts (B) oder GrapesJS fehlt. Exit.");
return;
}
const PluginName = 'bridge-blocks-api';
const qs = new URLSearchParams(location.search);
B.EDITOR_MODE = (qs.get('mode') || 'templates').toUpperCase();
console.log(`%c[${PluginName} - INIT] Editor Modus: ${B.EDITOR_MODE} (SCHRITT 16 - FINAL STABLE)`, 'color: #1E90FF; font-weight: bold;');
const TARGET_CAT_ID = 'custom';
const PLACEHOLDER_ID = 'api-placeholder-loading';
const REFERENCE_COMPONENT_TYPE = 'library-reference';
// --------------------------------------------------------
// (1) Kern-Logik: Platzhalter und Kategorien registrieren (SYNCHRON)
// --------------------------------------------------------
const preRegisterCategoriesAndPlaceholders = (editor) => {
const bm = editor.BlockManager;
bm.add(PLACEHOLDER_ID, {
label: 'Lade Custom-Blöcke...',
category: TARGET_CAT_ID,
content: '<div style="padding: 10px; color: #1e3a8a; background-color: #eef2ff; border: 1px solid #c7d2fe; text-align: center;">⚙️ Custom-Blöcke werden geladen...</div>',
attributes: { class: 'gjs-block__api-placeholder' },
});
const cat = bm.getCategories().get(TARGET_CAT_ID);
if (!cat) {
bm.addCategory(TARGET_CAT_ID, { label: 'Custom', open: true, order: 1 });
}
console.log(`%c[${PluginName}] Platzhalter und Kategorie registriert.`, 'color: #008000;');
};
// --------------------------------------------------------
// (2) Komponenten-Logik (ASYNCHRONER WORKAROUND & FIX)
// --------------------------------------------------------
const registerReferenceComponent = (editor) => {
const domc = editor.DomComponents;
const defaultType = domc.getType('default');
if (!defaultType) return;
// KRITISCHER WORKAROUND: Registrierung wird minimal verzögert
setTimeout(() => {
domc.addType(REFERENCE_COMPONENT_TYPE, {
model: defaultType.model.extend({
init() {
// Setze die Attribute sicher im init() (Fix für "defaults" TypeError)
if (this.get('type') !== REFERENCE_COMPONENT_TYPE) {
this.set('type', REFERENCE_COMPONENT_TYPE);
this.set('tagName', 'div');
this.set('lib-kind', '');
this.set('lib-id', '');
}
this.on('change:lib-kind change:lib-id', this.reloadComponentContent);
const editorInstance = this.em.get('Editor');
if (editorInstance && this.get('lib-id')) {
// Prüft hier nur auf getApiItem, da es für die Referenz-Komponente essenziell ist
if(B.getApiItem) {
editorInstance.on('load', this.reloadComponentContent.bind(this), { once: true });
} else {
console.warn(`[${PluginName}] B.getApiItem fehlt. Inhalte für 'library-reference' können nicht geladen werden.`);
}
}
},
reloadComponentContent(opts = {}) {
const kind = this.get('lib-kind');
const id = this.get('lib-id');
if (!kind || !id) {
this.set('content', '<div style="padding: 10px; color: #dc3545; background-color: #fce7f3; border: 1px solid #fbcfe8; text-align: center;">🛑 Fehler: API-Referenz unvollständig.</div>');
return;
}
if (!B.getApiItem) {
this.set('content', '<div style="padding: 10px; color: #dc3545; background-color: #fce7f3; border: 1px solid #fbcfe8; text-align: center;">🛑 Fehler: API-Kernfunktion getApiItem fehlt.</div>');
return;
}
B.getApiItem(kind, id)
.then(item => {
if (item && item.html) {
this.set('content', item.html);
console.log(`[${PluginName}] Geladenen Inhalt für ${kind}/${id} gesetzt.`);
} else {
this.set('content', `<div style="padding: 10px; color: #dc3545; background-color: #fce7f3; border: 1px solid #fbcfe8; text-align: center;">🛑 Fehler: Inhalt für ${kind}/${id} nicht gefunden.</div>`);
}
})
.catch(error => {
console.error(`[${PluginName}] Fehler beim Abruf von ${kind}/${id}:`, error);
this.set('content', `<div style="padding: 10px; color: #dc3545; background-color: #fce7f3; border: 1px solid #fbcfe8; text-align: center;">🛑 Fehler beim Laden von ${kind}/${id}.</div>`);
});
},
}, {}),
view: defaultType.view,
});
console.log(`%c[${PluginName}] Komponententyp '${REFERENCE_COMPONENT_TYPE}' ASYNCHRON registriert.`, 'color: #008000;');
}, 0);
};
// --------------------------------------------------------
// (3) Asynchrone Logik: API-Blöcke registrieren (FINAL CLEAN)
// --------------------------------------------------------
const loadAndRegisterApiBlocks = (editor) => {
const bm = editor.BlockManager;
const targetCatId = TARGET_CAT_ID;
// KRITISCHER FIX: Stelle sicher, dass der Platzhalter existiert.
if (!bm.get(PLACEHOLDER_ID)) {
bm.add(PLACEHOLDER_ID, {
label: 'Lade Custom-Blöcke...',
category: targetCatId,
content: '<div style="padding: 10px; color: #1e3a8a; background-color: #eef2ff; border: 1px solid #c7d2fe; text-align: center;">⚙️ Custom-Blöcke werden geladen...</div>',
attributes: { class: 'gjs-block__api-placeholder' },
});
console.log(`%c[${PluginName}] Platzhalter erneut hinzugefügt (Überlebens-Check).`, 'color: orange;');
}
// 🛑 NEUER CHECK: Prüfe die fetch*-Funktionen erst HIER.
if (!B.fetchSections || !B.fetchBlocks || !B.fetchSnippets) {
console.error(`%c[${PluginName}] FEHLER: Eine der API-Ladefunktionen (fetchSections/Blocks/Snippets) fehlt.`, 'color: #dc3545; font-weight: bold;');
// Platzhalter bleibt, da die Kategorie sonst verschwindet.
return;
}
// Explizite Promise.all mit allen fetch*-Funktionen
Promise.all([
B.fetchSections().then(items => items.map(i => ({ ...i, kind: 'sections' }))),
B.fetchBlocks().then(items => items.map(i => ({ ...i, kind: 'blocks' }))),
B.fetchSnippets().then(items => items.map(i => ({ ...i, kind: 'snippets' })))
])
.then(results => {
// Führe alle Ergebnisse zu einem flachen Array zusammen
const apiItems = results.flat().filter(item => item && item.id);
// Array-Ausgabe zur Bestätigung der Daten
console.log(`%c[${PluginName}] API-Daten Array:`, 'color: #9400D3; font-weight: bold;', apiItems);
console.log(`%c[${PluginName}] API-Daten geladen: ${apiItems.length} Blöcke/Sektionen gefunden.`, 'color: #1E90FF; font-weight: bold;');
if (apiItems.length === 0) {
// Platzhalter bleibt, um die leere Kategorie sichtbar zu halten.
console.warn(`[${PluginName}] Keine API-Daten gefunden, Platzhalter bleibt (leer) erhalten.`);
} else {
apiItems.forEach(item => {
const blockId = `lib-${item.kind}-${item.id}`;
const label = item.name || item.label || 'Unbenannter Block';
const itemKindUpper = item.kind.toUpperCase();
const blockDefinition = {
label: label,
category: targetCatId,
content: {
type: REFERENCE_COMPONENT_TYPE,
attributes: { 'lib-kind': item.kind, 'lib-id': item.id },
},
attributes: { 'title': itemKindUpper },
media: item.preview_url ? `<img src="${item.preview_url}">` : '',
};
bm.add(blockId, blockDefinition);
});
// Platzhalter entfernen, da Blöcke erfolgreich geladen wurden
bm.remove(PLACEHOLDER_ID);
console.log(`%c[${PluginName}] ${apiItems.length} API-Blöcke registriert. Platzhalter entfernt.`, 'color: #008000; font-weight: bold;');
}
})
.catch(error => {
console.error(`%c[${PluginName}] FEHLER beim Laden der API-Blöcke:`, 'color: #dc3545; font-weight: bold;', error);
// Platzhalter entfernen, um nicht im ewigen Ladezustand zu bleiben.
bm.remove(PLACEHOLDER_ID);
});
};
// --------------------------------------------------------
// (4) Plugin-Funktion
// --------------------------------------------------------
const plugin = (editor) => {
preRegisterCategoriesAndPlaceholders(editor);
registerReferenceComponent(editor);
editor.on('load', () => {
console.log(`%c[${PluginName}] GrapesJS 'load' Event: Starte asynchrones Laden der API-Blöcke.`, 'color: #1E90FF; font-weight: bold;');
loadAndRegisterApiBlocks(editor);
});
};
// --------------------------------------------------------
// (5) Export an Bridge Core
// --------------------------------------------------------
if (B.registerGrapesJSPlugin) {
B.registerGrapesJSPlugin(PluginName, plugin);
}
})(window.BridgeParts || (window.BridgeParts = {}));