208 lines
11 KiB
JavaScript
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 = {}));
|