Reputation: 801
I have a problem with my custom WYSIWYG editor.
Select a text and click on a button. The text will be formatted. Unselect the same text and select it again. Now click again on the same button to remove the format.
Select a text and click on a button. The text will be formatted. Now click again on the same button to remove the format.
I assume, that it probably doesn't work, because I am inserting an element inside the parent element. So at this moment, this element is not selected. With selectedText?.selectNode(node)
I have tried to select the correct node but this doesn't change anything.
So how can I remove the format, when the text stays selected?
document.getElementById('bold').addEventListener('click', () => edit('STRONG'));
document.getElementById('italic').addEventListener('click', () => edit('EM'));
function edit(format) {
const parentElementOfSelectedText = document.getSelection().getRangeAt(0).commonAncestorContainer.parentElement;
// If element is already formatted, undo the format
if (parentElementOfSelectedText.tagName === format) {
let grandParentOfSelectedText = parentElementOfSelectedText.parentElement;
if (parentElementOfSelectedText.textContent) {
const selectedText = document.createTextNode(parentElementOfSelectedText.textContent);
grandParentOfSelectedText.insertBefore(selectedText, parentElementOfSelectedText);
grandParentOfSelectedText.removeChild(parentElementOfSelectedText);
grandParentOfSelectedText.normalize();
}
} else {
const selectedText = document.getSelection().getRangeAt(0);
const node = document.createElement(format);
const fragment = selectedText.extractContents();
if (fragment) {
node.appendChild(fragment);
}
selectedText.insertNode(node);
}
}
<button id="bold">B</button>
<button id="italic">I</button>
<p>Lorem ipsum</p>
Upvotes: 0
Views: 1003
Reputation: 584
I assume, that it probably doesn't work, because I am inserting an element inside the parent element. So at this moment, this element is not selected.
correct. but you can just re-select it in js too.
document.getElementById('bold').addEventListener('click', () => edit('STRONG'));
document.getElementById('italic').addEventListener('click', () => edit('EM'));
function edit(format) {
let parentElementOfSelectedText = document.getSelection().getRangeAt(0).commonAncestorContainer;
// If element is already formatted, undo the format
if (parentElementOfSelectedText.tagName === format || parentElementOfSelectedText.parentElement.tagName === format) {
if(parentElementOfSelectedText.tagName !== format) parentElementOfSelectedText = parentElementOfSelectedText.parentElement;
let grandParentOfSelectedText = parentElementOfSelectedText.parentElement;
if (parentElementOfSelectedText.textContent) {
const selectedText = document.createTextNode(parentElementOfSelectedText.textContent);
//work with range of old element because
//text nodes are pass by value
//and we cant create a range after its a text node
const range = document.createRange();
range.selectNode(parentElementOfSelectedText);
//this replaces some of your code but uses a range
range.deleteContents();
range.insertNode(selectedText);
grandParentOfSelectedText.normalize();
//select the range again :)
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
} else {
let selectedText = document.getSelection().getRangeAt(0);
const node = document.createElement(format);
const fragment = selectedText.extractContents();
if (fragment) {
node.appendChild(fragment);
}
selectedText.insertNode(node);
//make only the inside of the node a range
//so [...].commonAncestorContainer is "STRONG" or "EM"
//and gets recognized
const range = document.createRange();
range.selectNodeContents(node);
const selection = window.getSelection();
selection.removeAllRanges()
selection.addRange(range);
}
}
<body>
<button id="bold">B</button>
<button id="italic">I</button>
<p>Lorem ipsum</p>
</body>
edits: adding comments to code; debugging
Upvotes: 1