This commit is contained in:
2026-01-18 22:48:02 +01:00
parent 8ff3e7a64d
commit 8a23398853

View File

@@ -206,6 +206,15 @@
|| (component.view && component.view.el && component.view.el.innerHTML) || (component.view && component.view.el && component.view.el.innerHTML)
|| ''; || '';
content.innerHTML = initialHtml; content.innerHTML = initialHtml;
const existingStyle = component && component.get && component.get('style') ? component.get('style') : null;
if (existingStyle && typeof existingStyle === 'object') {
if (existingStyle.fontFamily) {
content.style.fontFamily = existingStyle.fontFamily;
}
if (existingStyle.fontSize) {
content.style.fontSize = existingStyle.fontSize;
}
}
let savedRange = null; let savedRange = null;
const saveSelection = () => { const saveSelection = () => {
@@ -235,29 +244,42 @@
saveSelection(); saveSelection();
} catch {} } catch {}
}; };
const getSelectionRange = () => {
try {
const docRef = content.ownerDocument || document;
const sel = docRef.getSelection();
if (!sel || sel.rangeCount === 0) return null;
const range = sel.getRangeAt(0);
if (!content.contains(range.commonAncestorContainer)) return null;
return range;
} catch {
return null;
}
};
const applyInlineStyle = (styleProp, value) => { const applyInlineStyle = (styleProp, value) => {
try { try {
content.focus(); content.focus();
restoreSelection(); restoreSelection();
const docRef = content.ownerDocument || document; const docRef = content.ownerDocument || document;
const sel = docRef.getSelection(); const range = getSelectionRange();
if (!sel || sel.rangeCount === 0) return; if (!range || range.collapsed) return;
const range = sel.getRangeAt(0);
if (range.collapsed) return;
const wrapper = docRef.createElement('span'); const wrapper = docRef.createElement('span');
wrapper.style[styleProp] = value; wrapper.style[styleProp] = value;
const fragment = range.extractContents(); const fragment = range.extractContents();
wrapper.appendChild(fragment); wrapper.appendChild(fragment);
range.insertNode(wrapper); range.insertNode(wrapper);
sel.removeAllRanges(); const sel = docRef.getSelection();
const newRange = docRef.createRange(); if (sel) {
newRange.selectNodeContents(wrapper); sel.removeAllRanges();
sel.addRange(newRange); const newRange = docRef.createRange();
newRange.selectNodeContents(wrapper);
sel.addRange(newRange);
}
saveSelection(); saveSelection();
} catch {} } catch {}
}; };
const addButton = (labelHtml, title, cmd, valueGetter) => { const addButton = (labelHtml, title, cmd, valueGetter, handler) => {
const btn = doc.createElement('button'); const btn = doc.createElement('button');
btn.type = 'button'; btn.type = 'button';
btn.innerHTML = labelHtml; btn.innerHTML = labelHtml;
@@ -273,6 +295,10 @@
saveSelection(); saveSelection();
}); });
btn.addEventListener('click', () => { btn.addEventListener('click', () => {
if (typeof handler === 'function') {
handler();
return;
}
const value = typeof valueGetter === 'function' ? valueGetter() : valueGetter; const value = typeof valueGetter === 'function' ? valueGetter() : valueGetter;
if (value === null || value === undefined) return; if (value === null || value === undefined) return;
if (cmd === 'createLink' && !value) return; if (cmd === 'createLink' && !value) return;
@@ -307,9 +333,27 @@
}; };
const icon = (path) => `<svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path d="${path}" fill="currentColor"/></svg>`; const icon = (path) => `<svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path d="${path}" fill="currentColor"/></svg>`;
addButton(icon('M6 4h5a3 3 0 0 1 0 6H6V4zm0 8h6a3 3 0 0 1 0 6H6v-6z'), 'Fett', 'bold'); addButton(
addButton(icon('M10 4h8v2h-3l-4 12h3v2H6v-2h3l4-12h-3V4z'), 'Kursiv', 'italic'); icon('M6 4h5a3 3 0 0 1 0 6H6V4zm0 8h6a3 3 0 0 1 0 6H6v-6z'),
addButton(icon('M5 4h14v2h-6v3h4a4 4 0 0 1 0 8H7v-2h10a2 2 0 0 0 0-4h-4V6H5V4z'), 'Unterstrichen', 'underline'); 'Fett',
'bold',
null,
() => applyInlineStyle('fontWeight', '700')
);
addButton(
icon('M10 4h8v2h-3l-4 12h3v2H6v-2h3l4-12h-3V4z'),
'Kursiv',
'italic',
null,
() => applyInlineStyle('fontStyle', 'italic')
);
addButton(
icon('M5 4h14v2h-6v3h4a4 4 0 0 1 0 8H7v-2h10a2 2 0 0 0 0-4h-4V6H5V4z'),
'Unterstrichen',
'underline',
null,
() => applyInlineStyle('textDecoration', 'underline')
);
addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h10v2H4z'), 'Liste (ungeordnet)', 'insertUnorderedList'); addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h10v2H4z'), 'Liste (ungeordnet)', 'insertUnorderedList');
addButton(icon('M4 6h4v2H4V6zm0 4h4v2H4v-2zm0 4h4v2H4v-2zm6-8h10v2H10V6zm0 4h10v2H10v-2zm0 4h10v2H10v-2z'), 'Liste (geordnet)', 'insertOrderedList'); addButton(icon('M4 6h4v2H4V6zm0 4h4v2H4v-2zm0 4h4v2H4v-2zm6-8h10v2H10V6zm0 4h10v2H10v-2zm0 4h10v2H10v-2z'), 'Liste (geordnet)', 'insertOrderedList');
addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h12v2H4z'), 'Linksbundig', 'justifyLeft'); addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h12v2H4z'), 'Linksbundig', 'justifyLeft');
@@ -356,10 +400,15 @@
} catch {} } catch {}
}; };
addSelect([{ label: 'Schriftart', value: '' }, ...fontOptions], 'Schriftart', (value) => { const pendingComponentStyle = {};
const fontSelect = addSelect([{ label: 'Schriftart', value: '' }, ...fontOptions], 'Schriftart', (value) => {
if (!value) return; if (!value) return;
pendingComponentStyle.fontFamily = value;
applyComponentStyle({ fontFamily: value }, { preview: true }); applyComponentStyle({ fontFamily: value }, { preview: true });
}); });
if (existingStyle && existingStyle.fontFamily && fontSelect) {
fontSelect.value = existingStyle.fontFamily;
}
addSelect([ addSelect([
{ label: 'Groesse', value: '' }, { label: 'Groesse', value: '' },
{ label: '10px', value: '10' }, { label: '10px', value: '10' },
@@ -375,10 +424,22 @@
const raw = prompt('Schriftgroesse in px', '14'); const raw = prompt('Schriftgroesse in px', '14');
const num = Number(raw || 0); const num = Number(raw || 0);
if (!Number.isFinite(num) || num <= 0) return; if (!Number.isFinite(num) || num <= 0) return;
applyInlineStyle('fontSize', `${num}px`); const range = getSelectionRange();
if (range && !range.collapsed) {
applyInlineStyle('fontSize', `${num}px`);
} else {
pendingComponentStyle.fontSize = `${num}px`;
applyComponentStyle({ fontSize: `${num}px` }, { preview: true });
}
return; return;
} }
applyInlineStyle('fontSize', `${value}px`); const range = getSelectionRange();
if (range && !range.collapsed) {
applyInlineStyle('fontSize', `${value}px`);
return;
}
pendingComponentStyle.fontSize = `${value}px`;
applyComponentStyle({ fontSize: `${value}px` }, { preview: true });
}); });
// Emoji-Picker entfernt (auf Wunsch) kann spaeter als echter Picker wiederkommen. // Emoji-Picker entfernt (auf Wunsch) kann spaeter als echter Picker wiederkommen.
@@ -419,6 +480,9 @@
component.__bridgeRteLastContent = html; component.__bridgeRteLastContent = html;
logConsoleSnapshot(editor, component, 'before-save'); logConsoleSnapshot(editor, component, 'before-save');
const forceApply = () => { const forceApply = () => {
if (Object.keys(pendingComponentStyle).length) {
applyComponentStyle(pendingComponentStyle);
}
applyContentToComponent(editor, component, html); applyContentToComponent(editor, component, html);
logConsoleSnapshot(editor, component, 'after-save'); logConsoleSnapshot(editor, component, 'after-save');
}; };