My problem is when I want to remove the format of a selected text, the format of the whole text will be removed.
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);
// const selectedText = document.createTextNode(document.getSelection().toString());
//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);
}
}
<button id="bold">B</button>
<button id="italic">I</button>
<div contentEditable="true">Lorem</div>
Select Lorem and click on the B button. So Lorem will be bold. Now type ipsum after Lorem. Ipsum will also be bold. Select ipsum and click again on the B button. Now not only ipsum lost its format but also Lorem.
It is fine when the text that gets entered will have the same format as the text before. But the user should be able to remove the format of the selected text only.
So when they start to type, the value should be Lorem ipsum and when the remove the format of ipsum, it should be Lorem ipsum.
How can I do this?
I also tried it with
const selectedText = document.createTextNode(document.getSelection().toString());
but then the unselected text will be removed. See JSFiddle