/* /assets/js/bridge/table-builder.js */ (function () { const PluginName = 'bridge-table-builder'; const B = window.BridgeParts || (window.BridgeParts = {}); if (B.DISABLE_TABLE_BUILDER) return; if (B.__tableBuilderLoaded) return; B.__tableBuilderLoaded = true; const log = (type, message, color = '#94a3b8', logType = 'info', force = false) => { if (typeof B.log === 'function') { B.log(PluginName, `[${type}] ${message}`, color, logType, force); } }; B.setupTableBuilder = (editor) => { const domc = editor && editor.DomComponents; if (!domc) return; const icon = (path) => ``; const tableIcon = icon('M3 4h18v16H3V4zm2 2v3h6V6H5zm8 0v3h6V6h-6zM5 11v3h6v-3H5zm8 0v3h6v-3h-6zM5 16v2h6v-2H5zm8 0v2h6v-2h-6z'); const collectTableCells = (component) => { const el = component?.view?.el; if (!el) return []; return Array.from(el.querySelectorAll('tr')).map(row => Array.from(row.children || []).map(cell => cell.innerHTML || '') ); }; const buildTableHtml = (rows, cols, existing) => { const safeRows = Math.max(1, Math.min(20, Number(rows) || 1)); const safeCols = Math.max(2, Math.min(2, Number(cols) || 2)); const cellStyle = "padding:8px;border:1px solid #e2e8f0;font-size:13px"; const headStyle = "text-align:left;padding:8px;border:1px solid #e2e8f0;background-color:#f8fafc;font-size:13px"; let html = ''; for (let r = 0; r < safeRows; r++) { html += ''; for (let c = 0; c < safeCols; c++) { const existingVal = existing?.[r]?.[c] || ''; const label = existingVal || (r === 0 ? `Spalte ${String.fromCharCode(65 + c)}` : `Zeile ${r} / ${c + 1}`); if (r === 0) { html += `${label}`; } else { html += `${label}`; } } html += ''; } return html; }; const openTableModal = (component) => { if (!component) return; const modal = editor.Modal; if (!modal) return; const attrs = component.getAttributes ? component.getAttributes() : {}; const rows = Number(attrs['data-bridge-rows'] || 3) || 3; const container = document.createElement('div'); container.style.display = 'flex'; container.style.flexDirection = 'column'; container.style.gap = '12px'; container.style.minWidth = '280px'; const label = document.createElement('label'); label.textContent = 'Anzahl Zeilen'; label.style.fontSize = '13px'; label.style.fontWeight = '600'; const input = document.createElement('input'); input.type = 'number'; input.min = '1'; input.max = '20'; input.value = String(rows); input.style.width = '100%'; input.style.padding = '6px 8px'; input.style.border = '1px solid #cbd5f5'; input.style.borderRadius = '4px'; label.appendChild(input); container.appendChild(label); const actions = document.createElement('div'); actions.style.display = 'flex'; actions.style.justifyContent = 'flex-end'; actions.style.gap = '8px'; const cancelBtn = document.createElement('button'); cancelBtn.type = 'button'; cancelBtn.textContent = 'Abbrechen'; cancelBtn.className = 'btn'; cancelBtn.addEventListener('click', () => modal.close()); const saveBtn = document.createElement('button'); saveBtn.type = 'button'; saveBtn.textContent = 'Uebernehmen'; saveBtn.className = 'btn'; saveBtn.addEventListener('click', () => { const nextRows = Math.max(1, Math.min(20, Number(input.value) || 1)); const existing = collectTableCells(component); const html = buildTableHtml(nextRows, 2, existing); component.addAttributes && component.addAttributes({ 'data-bridge-rows': String(nextRows), 'data-bridge-cols': '2', }); if (component.components) { component.components(html); } if (component.view && component.view.render) { component.view.render(); } modal.close(); }); actions.appendChild(cancelBtn); actions.appendChild(saveBtn); container.appendChild(actions); modal.setTitle('Tabelle konfigurieren'); modal.setContent(container); const mdl = modal.getModel && modal.getModel(); if (mdl && typeof mdl.set === 'function') { mdl.set('closeOnEsc', false); mdl.set('closeOnClick', false); } modal.open(); }; if (editor.Commands && editor.Commands.add) { editor.Commands.add('bridge-table:edit', { run(ed, sender, opts = {}) { if (sender && sender.set) sender.set('active', 0); const component = opts.component || ed.getSelected(); if (component && component.is && component.is('bridge-table')) { openTableModal(component); } }, }); } if (!domc.getType('bridge-table')) { const baseType = domc.getType('table') || domc.getType('default'); const BaseModel = baseType.model; const BaseView = baseType.view; domc.addType('bridge-table', { model: BaseModel.extend({ initialize(props = {}, opts = {}) { if (BaseModel.prototype.initialize) { BaseModel.prototype.initialize.apply(this, [props, opts]); } const attrs = this.getAttributes ? this.getAttributes() : {}; const nextAttrs = Object.assign({ 'data-bridge-table': '1', 'data-bridge-rows': '3', 'data-bridge-cols': '2', role: 'presentation', }, attrs || {}); if (this.addAttributes) { this.addAttributes(nextAttrs); } else if (this.set) { this.set('attributes', nextAttrs, { silent: true }); } const toolbar = this.get && this.get('toolbar'); if (!Array.isArray(toolbar) || !toolbar.some(btn => btn && btn.command === 'bridge-table:edit')) { this.set && this.set('toolbar', [ ...(Array.isArray(toolbar) ? toolbar : []), { label: tableIcon, command: 'bridge-table:edit', attributes: { title: 'Tabelle bearbeiten' }, }, ]); } }, }), view: BaseView, isComponent(el) { if (!el || !el.hasAttribute) return false; if (el.tagName && el.tagName.toLowerCase() === 'table' && el.getAttribute('data-bridge-table') === '1') { return { type: 'bridge-table' }; } return false; }, }); } editor.on('component:selected', (model) => { if (model && model.is && model.is('bridge-table')) { const toolbar = model.get('toolbar') || []; const exists = toolbar.some(btn => btn && btn.command === 'bridge-table:edit'); if (!exists) { toolbar.push({ label: tableIcon, command: 'bridge-table:edit', attributes: { title: 'Tabelle bearbeiten' }, }); model.set('toolbar', toolbar); } } }); editor.on('component:dblclick', (model) => { if (model && model.is && model.is('bridge-table')) { openTableModal(model); } }); log('INIT', 'Table-Builder geladen.', '#10b981'); }; })();