asdasd
This commit is contained in:
@@ -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: `<span data-gjs-type="${PLACEHOLDER_COMPONENT}" data-placeholder-type="custom" data-placeholder-key="UEBERSCHRIFT">{{UEBERSCHRIFT}}</span>`
|
||||
};
|
||||
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: `<span data-gjs-type="${PLACEHOLDER_COMPONENT}" data-placeholder-type="database" data-placeholder-table="${tableName}" data-placeholder-column="${firstColumn}">{{${placeholderLabel}}}</span>`
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
log('PLACEHOLDER WARN', 'DB Placeholder Block ausgeblendet (Schemafehler).', '#b45309');
|
||||
});
|
||||
|
||||
// TEXT
|
||||
addOnce(bm, 'cust-text', { id:'cust-text', label:'📝 Text',
|
||||
|
||||
Reference in New Issue
Block a user