Icons Buttosn RTE

This commit is contained in:
2026-01-29 00:56:44 +01:00
parent 21579f45cb
commit f9875f82ba
2 changed files with 131 additions and 9 deletions

View File

@@ -1 +1 @@
1.1.54
1.1.55

View File

@@ -502,6 +502,87 @@
saveSelection();
} catch {}
};
const selectionHasStyle = (range, styleProp, tags, styleMatch) => {
if (!range) return false;
try {
const fragment = range.cloneContents();
const walker = (node) => {
if (!node) return false;
if (node.nodeType === 1) {
const tag = node.tagName ? node.tagName.toUpperCase() : '';
if (tags && tags.includes(tag)) return true;
if (styleProp && node.style) {
if (styleMatch && styleMatch(node.style[styleProp] || '', node)) return true;
}
for (const child of Array.from(node.childNodes)) {
if (walker(child)) return true;
}
}
return false;
};
for (const child of Array.from(fragment.childNodes)) {
if (walker(child)) return true;
}
} catch {}
return false;
};
const removeInlineStyle = (styleProp, tags, clearFn) => {
try {
content.focus();
restoreSelection();
const docRef = content.ownerDocument || document;
const range = getSelectionRange();
if (!range || range.collapsed) return;
const fragment = range.extractContents();
const unwrap = (node) => {
const parent = node.parentNode;
if (!parent) return;
while (node.firstChild) parent.insertBefore(node.firstChild, node);
parent.removeChild(node);
};
const strip = (node) => {
if (!node) return;
if (node.nodeType === 1) {
const tag = node.tagName ? node.tagName.toUpperCase() : '';
if (tags && tags.includes(tag)) {
const children = Array.from(node.childNodes);
children.forEach(strip);
unwrap(node);
return;
}
if (styleProp && node.style) {
if (typeof clearFn === 'function') {
clearFn(node.style);
} else {
node.style[styleProp] = '';
}
const styleAttr = node.getAttribute('style');
if (!styleAttr || !String(styleAttr).trim()) {
const children = Array.from(node.childNodes);
children.forEach(strip);
unwrap(node);
return;
}
}
Array.from(node.childNodes).forEach(strip);
}
};
Array.from(fragment.childNodes).forEach(strip);
range.insertNode(fragment);
saveSelection();
} catch {}
};
const toggleInlineStyle = (cmd, styleProp, value, tags, styleMatch, clearFn) => {
const range = getSelectionRange();
if (!range || range.collapsed) return;
if (selectionHasStyle(range, styleProp, tags, styleMatch)) {
if (cmd) exec(cmd);
removeInlineStyle(styleProp, tags, clearFn);
return;
}
if (cmd) exec(cmd);
if (styleProp) applyInlineStyle(styleProp, value);
};
const removeInlineFormatting = () => {
try {
content.focus();
@@ -669,25 +750,52 @@
if (!ui.overrideToolbar) {
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'),
'<strong>B</strong>',
'Fett',
'bold',
null,
() => applyInlineStyle('fontWeight', '700')
() => toggleInlineStyle(
'bold',
'fontWeight',
'700',
['B', 'STRONG'],
(val) => {
const num = parseInt(String(val || '').replace(/[^0-9]/g, ''), 10);
return Number.isFinite(num) ? num >= 600 : /bold/i.test(String(val || ''));
},
(style) => { style.fontWeight = ''; }
)
);
addButton(
icon('M10 4h8v2h-3l-4 12h3v2H6v-2h3l4-12h-3V4z'),
'<em>I</em>',
'Kursiv',
'italic',
null,
() => applyInlineStyle('fontStyle', 'italic')
() => toggleInlineStyle(
'italic',
'fontStyle',
'italic',
['I', 'EM'],
(val) => String(val || '').toLowerCase() === 'italic',
(style) => { style.fontStyle = ''; }
)
);
addButton(
icon('M5 4h14v2h-6v3h4a4 4 0 0 1 0 8H7v-2h10a2 2 0 0 0 0-4h-4V6H5V4z'),
'<span style="text-decoration:underline;">U</span>',
'Unterstrichen',
'underline',
null,
() => applyInlineStyle('textDecoration', 'underline')
() => toggleInlineStyle(
'underline',
'textDecoration',
'underline',
['U'],
(val) => /underline/i.test(String(val || '')),
(style) => {
style.textDecoration = '';
style.textDecorationLine = '';
}
)
);
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');
@@ -702,7 +810,7 @@
addButton(icon('M7 4h4v4H7V4zm6 12h4v4h-4v-4zM7 10h10v2H7v-2z'), 'Einzug', 'indent');
addButton(icon('M13 4h4v4h-4V4zM7 16h4v4H7v-4zM7 10h10v2H7v-2z'), 'Ausruecken', 'outdent');
addButton(
icon('M5 5h14v2H5zM5 9h10v2H5zM5 13h14v2H5zM5 17h10v2H5z'),
'<span style="font-weight:600;">Tx</span>',
'Formatierung entfernen',
null,
null,
@@ -776,7 +884,21 @@
editorCss = editor && typeof editor.getCss === 'function' ? String(editor.getCss() || '') : '';
} catch {}
const frameCss = this.collectFrameCss(editor);
injectedStyle.textContent = `${fontCss}\n${editorCss}\n${frameCss}`.trim();
const rteUiCss = `
.bridge-rte-toolbar { gap: 8px; }
.bridge-rte-btn {
font-size: 14px;
line-height: 1;
min-height: 30px;
min-width: 30px;
color: #0f172a;
background: #f1f5f9;
}
.bridge-rte-btn:hover { background: #e2e8f0; }
.bridge-rte-btn:active { transform: translateY(1px); }
.bridge-rte-actions .bridge-rte-btn { min-width: 88px; }
`.trim();
injectedStyle.textContent = [fontCss, editorCss, frameCss, rteUiCss].filter(Boolean).join('\n');
if (injectedStyle.textContent) {
container.appendChild(injectedStyle);
}