Add visual button presets, jump targets and menu controls
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

This commit is contained in:
kantarci committed 2026-09-14 13:47:49 +02:00
1 parent bb4e422af8
commit 3391fea58b
41 files changed
+723 -57

No files matched your search

+16 -1
View File
@@ -1,6 +1,7 @@
import { EditorHistory, labels, blockLabel, blockIcon, isPluginBlock, setStyle, effectiveStyle, locate, clone, isContainer, canContain, insertBlock, insertBlockAt, insertionTarget, moveBlockTo, duplicateBlock, moveBlock, devices, effectiveDesign, setDesign, blockPath, insertPreset, insertRow, insertRowAt, setEffect, insertMedia, upgradeDocument, CATEGORIES, ROW_COLUMNS, whyNot, dropList } from './editor-model.js';
import { openMedia, createMediaPreview } from './media.js';
import { createDesignPanel } from './design-panel.js';
import { renderButtonControls, setButtonDesign } from './button-design.js';
import { createRichText } from './rich-text.js';
import { createCanvasOverlay } from './canvas-overlay.js';
import { preview, rowPreview } from './library-previews.js';
@@ -202,7 +203,11 @@ function renderProperties() {
history.change(doc => {
const current = selected ? locate(doc.blocks, selected)?.block : doc;
if (!current) return;
if (options.layout) (current.layout ??= {})[key] = next;
if (options.anchor) {
const anchor = String(next).trim().replace(/^#/, '');
if (anchor) { current.anchor = anchor; upgradeDocument(doc, 21); } else delete current.anchor;
}
else if (options.layout) (current.layout ??= {})[key] = next;
else if (selected) {
(current.props ??= {})[key] = next;
// Decorative means "no text": an image loses its alternative text, an icon its label.
@@ -248,6 +253,7 @@ function renderProperties() {
panel.append(label, rich.element, help);
}
if (['heading', 'button'].includes(block.type)) field(block.type === 'button' ? 'Beschriftung' : 'Text', 'text', block.props.text, { multiline: block.type !== 'button' });
if (block.type === 'button' && designSchema) buttonControls(block, panel);
if (INLINE_TEXT[block.type]) {
const inline = document.createElement('button');
inline.className = 'secondary full-width';
@@ -339,6 +345,7 @@ function renderProperties() {
add.textContent = '+ Eintrag hinzufügen'; add.addEventListener('click', () => addAccordionEntry(block.id));
panel.append(hint, entries, add);
}
if (['section', 'row', 'column'].includes(block.type)) field('Sprungziel', 'anchor', block.anchor, { anchor: true, maxLength: 64, help: 'Zum Beispiel kontakt eingeben. Buttons und Menülinks mit #kontakt springen dann hierher; von anderen Seiten mit /seitenadresse#kontakt.' });
if (block.type === 'accordionitem') {
field('Titel', 'title', block.props.title, { maxLength: 160 });
field('Beim Laden geöffnet', 'open', block.props.open, { checkbox: true, help: 'Gilt für die veröffentlichte Seite. Im Editor bleiben alle Einträge zum Bearbeiten geöffnet.' });
@@ -499,6 +506,7 @@ function renderImageWidth(block, panel) {
}
function renderDesign(block, panel) {
if (block.type === 'button' && designSchema) buttonControls(block, panel);
if (designSchema && designPanel) {
designPanel(panel);
} else {
@@ -884,6 +892,13 @@ function addElement(type) {
changed();
}
function buttonControls(block, panel) {
renderButtonControls(panel, { block, device, schema: designSchema, apply: (values, focusId) => {
history.change(doc => setButtonDesign(doc, block.id, device, values)); changed();
document.getElementById(focusId)?.focus({ preventScroll: true });
} });
}
function beginContainerInsert(id) {
const block = locate(history.document.blocks, id)?.block;
if (!block || busy) return;