ysdasds
This commit is contained in:
@@ -188,11 +188,53 @@
|
|||||||
|| '';
|
|| '';
|
||||||
content.innerHTML = initialHtml;
|
content.innerHTML = initialHtml;
|
||||||
|
|
||||||
|
let savedRange = null;
|
||||||
|
const saveSelection = () => {
|
||||||
|
try {
|
||||||
|
const sel = (content.ownerDocument || document).getSelection();
|
||||||
|
if (!sel || sel.rangeCount === 0) return;
|
||||||
|
const range = sel.getRangeAt(0);
|
||||||
|
if (content.contains(range.commonAncestorContainer)) {
|
||||||
|
savedRange = range.cloneRange();
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
const restoreSelection = () => {
|
||||||
|
try {
|
||||||
|
const sel = (content.ownerDocument || document).getSelection();
|
||||||
|
if (!sel || !savedRange) return;
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(savedRange);
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
const exec = (cmd, value) => {
|
const exec = (cmd, value) => {
|
||||||
try {
|
try {
|
||||||
content.focus();
|
content.focus();
|
||||||
|
restoreSelection();
|
||||||
const docRef = content.ownerDocument || document;
|
const docRef = content.ownerDocument || document;
|
||||||
docRef.execCommand(cmd, false, value);
|
docRef.execCommand(cmd, false, value);
|
||||||
|
saveSelection();
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
const applyInlineStyle = (styleProp, value) => {
|
||||||
|
try {
|
||||||
|
content.focus();
|
||||||
|
restoreSelection();
|
||||||
|
const docRef = content.ownerDocument || document;
|
||||||
|
const sel = docRef.getSelection();
|
||||||
|
if (!sel || sel.rangeCount === 0) return;
|
||||||
|
const range = sel.getRangeAt(0);
|
||||||
|
if (range.collapsed) return;
|
||||||
|
const wrapper = docRef.createElement('span');
|
||||||
|
wrapper.style[styleProp] = value;
|
||||||
|
const fragment = range.extractContents();
|
||||||
|
wrapper.appendChild(fragment);
|
||||||
|
range.insertNode(wrapper);
|
||||||
|
sel.removeAllRanges();
|
||||||
|
const newRange = docRef.createRange();
|
||||||
|
newRange.selectNodeContents(wrapper);
|
||||||
|
sel.addRange(newRange);
|
||||||
|
saveSelection();
|
||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -201,11 +243,16 @@
|
|||||||
btn.type = 'button';
|
btn.type = 'button';
|
||||||
btn.innerHTML = labelHtml;
|
btn.innerHTML = labelHtml;
|
||||||
btn.title = title;
|
btn.title = title;
|
||||||
|
btn.setAttribute('aria-label', title);
|
||||||
btn.style.padding = '4px 8px';
|
btn.style.padding = '4px 8px';
|
||||||
btn.style.border = '1px solid #cbd5f5';
|
btn.style.border = '1px solid #cbd5f5';
|
||||||
btn.style.borderRadius = '4px';
|
btn.style.borderRadius = '4px';
|
||||||
btn.style.background = '#f8fafc';
|
btn.style.background = '#f8fafc';
|
||||||
btn.style.cursor = 'pointer';
|
btn.style.cursor = 'pointer';
|
||||||
|
btn.addEventListener('mousedown', (evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
saveSelection();
|
||||||
|
});
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
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;
|
||||||
@@ -218,6 +265,7 @@
|
|||||||
const addSelect = (options, title, onChange) => {
|
const addSelect = (options, title, onChange) => {
|
||||||
const select = doc.createElement('select');
|
const select = doc.createElement('select');
|
||||||
select.title = title;
|
select.title = title;
|
||||||
|
select.setAttribute('aria-label', title);
|
||||||
select.style.padding = '4px 8px';
|
select.style.padding = '4px 8px';
|
||||||
select.style.border = '1px solid #cbd5f5';
|
select.style.border = '1px solid #cbd5f5';
|
||||||
select.style.borderRadius = '4px';
|
select.style.borderRadius = '4px';
|
||||||
@@ -228,6 +276,10 @@
|
|||||||
optEl.textContent = opt.label;
|
optEl.textContent = opt.label;
|
||||||
select.appendChild(optEl);
|
select.appendChild(optEl);
|
||||||
});
|
});
|
||||||
|
select.addEventListener('mousedown', (evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
saveSelection();
|
||||||
|
});
|
||||||
select.addEventListener('change', () => {
|
select.addEventListener('change', () => {
|
||||||
const value = select.value;
|
const value = select.value;
|
||||||
if (value) onChange(value);
|
if (value) onChange(value);
|
||||||
@@ -237,23 +289,22 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
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('<strong>B</strong>', 'Fett', 'bold');
|
addButton(icon('M6 4h5a3 3 0 0 1 0 6H6V4zm0 8h6a3 3 0 0 1 0 6H6v-6z'), 'Fett', 'bold');
|
||||||
addButton('<em>I</em>', 'Kursiv', 'italic');
|
addButton(icon('M10 4h8v2h-3l-4 12h3v2H6v-2h3l4-12h-3V4z'), 'Kursiv', 'italic');
|
||||||
addButton('<span style="text-decoration:underline">U</span>', 'Unterstrichen', 'underline');
|
addButton(icon('M5 4h14v2h-6v3h4a4 4 0 0 1 0 8H7v-2h10a2 2 0 0 0 0-4h-4V6H5V4z'), 'Unterstrichen', 'underline');
|
||||||
addButton('<span style="text-decoration:line-through">S</span>', 'Durchgestrichen', 'strikethrough');
|
|
||||||
addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h10v2H4z'), 'Liste (ungeordnet)', 'insertUnorderedList');
|
addButton(icon('M4 7h10v2H4zM4 11h16v2H4zM4 15h10v2H4z'), 'Liste (ungeordnet)', 'insertUnorderedList');
|
||||||
addButton(icon('M4 7h14v2H4zM4 11h14v2H4zM4 15h14v2H4z') + '<span style="font-size:10px;margin-left:4px">1.</span>', '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');
|
||||||
addButton(icon('M5 7h14v2H5zM4 11h16v2H4zM5 15h14v2H5z'), 'Zentriert', 'justifyCenter');
|
addButton(icon('M5 7h14v2H5zM4 11h16v2H4zM5 15h14v2H5z'), 'Zentriert', 'justifyCenter');
|
||||||
addButton(icon('M10 7h10v2H10zM4 11h16v2H4zM8 15h12v2H8z'), 'Rechtsbundig', 'justifyRight');
|
addButton(icon('M10 7h10v2H10zM4 11h16v2H4zM8 15h12v2H8z'), 'Rechtsbuendig', 'justifyRight');
|
||||||
addButton(icon('M4 7h16v2H4zM4 11h16v2H4zM4 15h16v2H4z'), 'Blocksatz', 'justifyFull');
|
addButton(icon('M4 7h16v2H4zM4 11h16v2H4zM4 15h16v2H4z'), 'Blocksatz', 'justifyFull');
|
||||||
addButton('Link', 'Link einfuegen', 'createLink', () => prompt('Link-URL eingeben', 'https://'));
|
addButton(icon('M7 7h10l-1.5 1.5-3-3-5.5 5.5v5h5l5.5-5.5-3-3L17 7z'), 'Link einfuegen', 'createLink', () => prompt('Link-URL eingeben', 'https://'));
|
||||||
addButton('Unlink', 'Link entfernen', 'unlink');
|
addButton(icon('M7 7h4v2H7v4H5V9a2 2 0 0 1 2-2zm10 0a2 2 0 0 1 2 2v4h-2V9h-4V7h4zm0 10h-4v-2h4v-4h2v4a2 2 0 0 1-2 2zm-10 0a2 2 0 0 1-2-2v-4h2v4h4v2H7z'), 'Link entfernen', 'unlink');
|
||||||
addButton('Sub', 'Tiefgestellt', 'subscript');
|
addButton(icon('M7 6h10v2H7zM9 10h6v2H9zM10 14h4v2h-4z'), 'Tiefgestellt', 'subscript');
|
||||||
addButton('Sup', 'Hochgestellt', 'superscript');
|
addButton(icon('M7 6h10v2H7zM9 10h6v2H9zM8 14h8v2H8z'), 'Hochgestellt', 'superscript');
|
||||||
addButton('Einr.', 'Einzug', 'indent');
|
addButton(icon('M7 4h4v4H7V4zm6 12h4v4h-4v-4zM7 10h10v2H7v-2z'), 'Einzug', 'indent');
|
||||||
addButton('Aus.', 'Ausruecken', 'outdent');
|
addButton(icon('M13 4h4v4h-4V4zM7 16h4v4H7v-4zM7 10h10v2H7v-2z'), 'Ausruecken', 'outdent');
|
||||||
addButton('Clear', 'Formatierung entfernen', 'removeFormat');
|
addButton(icon('M5 5h14v2H5zM5 9h10v2H5zM5 13h14v2H5zM5 17h10v2H5z'), 'Formatierung entfernen', 'removeFormat');
|
||||||
|
|
||||||
const fontOptions = (B.RTE_FONTS && Array.isArray(B.RTE_FONTS) && B.RTE_FONTS.length)
|
const fontOptions = (B.RTE_FONTS && Array.isArray(B.RTE_FONTS) && B.RTE_FONTS.length)
|
||||||
? B.RTE_FONTS
|
? B.RTE_FONTS
|
||||||
@@ -267,17 +318,27 @@
|
|||||||
{ label: 'Trebuchet MS', value: 'Trebuchet MS, sans-serif' },
|
{ label: 'Trebuchet MS', value: 'Trebuchet MS, sans-serif' },
|
||||||
{ label: 'Verdana', value: 'Verdana, sans-serif' },
|
{ label: 'Verdana', value: 'Verdana, sans-serif' },
|
||||||
];
|
];
|
||||||
addSelect([{ label: 'Schriftart', value: '' }, ...fontOptions], 'Schriftart', (value) => exec('fontName', value));
|
addSelect([{ label: 'Schriftart', value: '' }, ...fontOptions], 'Schriftart', (value) => applyInlineStyle('fontFamily', value));
|
||||||
addSelect([
|
addSelect([
|
||||||
{ label: 'Groesse', value: '' },
|
{ label: 'Groesse', value: '' },
|
||||||
{ label: '10px', value: '1' },
|
{ label: '10px', value: '10' },
|
||||||
{ label: '12px', value: '2' },
|
{ label: '12px', value: '12' },
|
||||||
{ label: '14px', value: '3' },
|
{ label: '14px', value: '14' },
|
||||||
{ label: '16px', value: '4' },
|
{ label: '16px', value: '16' },
|
||||||
{ label: '18px', value: '5' },
|
{ label: '18px', value: '18' },
|
||||||
{ label: '24px', value: '6' },
|
{ label: '24px', value: '24' },
|
||||||
{ label: '32px', value: '7' },
|
{ label: '32px', value: '32' },
|
||||||
], 'Schriftgroesse', (value) => exec('fontSize', value));
|
{ label: 'Custom…', value: '__custom__' },
|
||||||
|
], 'Schriftgroesse', (value) => {
|
||||||
|
if (value === '__custom__') {
|
||||||
|
const raw = prompt('Schriftgroesse in px', '14');
|
||||||
|
const num = Number(raw || 0);
|
||||||
|
if (!Number.isFinite(num) || num <= 0) return;
|
||||||
|
applyInlineStyle('fontSize', `${num}px`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applyInlineStyle('fontSize', `${value}px`);
|
||||||
|
});
|
||||||
|
|
||||||
const emojiBtn = doc.createElement('button');
|
const emojiBtn = doc.createElement('button');
|
||||||
emojiBtn.type = 'button';
|
emojiBtn.type = 'button';
|
||||||
@@ -288,6 +349,10 @@
|
|||||||
emojiBtn.style.borderRadius = '4px';
|
emojiBtn.style.borderRadius = '4px';
|
||||||
emojiBtn.style.background = '#f8fafc';
|
emojiBtn.style.background = '#f8fafc';
|
||||||
emojiBtn.style.cursor = 'pointer';
|
emojiBtn.style.cursor = 'pointer';
|
||||||
|
emojiBtn.addEventListener('mousedown', (evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
saveSelection();
|
||||||
|
});
|
||||||
emojiBtn.addEventListener('click', () => {
|
emojiBtn.addEventListener('click', () => {
|
||||||
const pick = prompt('Emoticon eingeben', ':)');
|
const pick = prompt('Emoticon eingeben', ':)');
|
||||||
if (pick) exec('insertText', pick);
|
if (pick) exec('insertText', pick);
|
||||||
@@ -296,6 +361,9 @@
|
|||||||
|
|
||||||
container.appendChild(toolbar);
|
container.appendChild(toolbar);
|
||||||
container.appendChild(content);
|
container.appendChild(content);
|
||||||
|
content.addEventListener('keyup', saveSelection);
|
||||||
|
content.addEventListener('mouseup', saveSelection);
|
||||||
|
content.addEventListener('focus', saveSelection);
|
||||||
|
|
||||||
const actions = doc.createElement('div');
|
const actions = doc.createElement('div');
|
||||||
actions.style.display = 'flex';
|
actions.style.display = 'flex';
|
||||||
|
|||||||
Reference in New Issue
Block a user