Reputation: 91
I have a div tag with contenteditable set to true. I want the user to be able to edit the text inside that div, but not remove any additional div or span tags inside. For example with the following code.
<div class="container" contenteditable="true">
This Content Should be Editable
<span contenteditable="false"
style="display: inline;">
This Should not be Editable</span>
</div>
I have the desired result in the span tag when I set its contenteditable to false. But when i press backspace in the div tag i am also able to remove the whole span tag. I want to lock the span tag in the div, like dont allow the user to remove it or edit it. For now I think having a contenteditable div tag is allowing the user to remove the span completely. Is there a work around to achieve this. And I donot want to have the editable text in another span.
Upvotes: 5
Views: 1309
Reputation: 1
i suggest <pre contenteditable="plaintext-only"></pre
this may help? (i know its outdated question but i have a answer.)
Upvotes: 0
Reputation: 540
Updated #2: A combination of things seemed to work in this example.
It took first listening to the container for the 'Delete' keydown event and also listening to the contenteditable="false"
span for its accidental deletion from the container.
Inpsired by this post on cursor position and this post on manually dispatching keyboard events
const DOMNodeRemoved = 'DOMNodeRemoved';
const DELETE = 'Delete';
const container = document.querySelector(".container");
container.addEventListener('keydown', containerListner, false);
const unEditableSelector = '[contenteditable="false"]';
const unEditable = container.querySelector(unEditableSelector);
unEditable.addEventListener("DOMNodeRemoved", unEditableListner, false)
function containerListner(e) { return e.key === DELETE && manuallyTriggerDeleteKey(e) }
function unEditableListner(e) { return e.type === DOMNodeRemoved && container.append(unEditable) }
function manuallyTriggerDeleteKey(e) {
const cursorPosition = window.getSelection().getRangeAt(0).startOffset
const stringToDelete = e.target.textContent.substr(cursorPosition).trim();
const stripped = unEditable.textContent.trim();
if (stripped === stringToDelete ) { return e.preventDefault(); }
return new KeyboardEvent('keypress', { 'key': 'Delete' })
}
<div class="container" contenteditable="true">
This Content Should be Editable
<span contenteditable="false"
style="display: inline;">
This Should not be Editable</span>
</div>
You could try to take advantage of the focus
and blur
events and selectively hide and show manage the span.
Updated 1: The issue is that the span could get deleted if the user does something like uses delete key instead of backspace
With a DOMNodeRemoved event listener, you could append the node back to the container in case of accidental deletion.
here's an example inspired by this post on DOM mutation events
const DOMNodeRemoved = 'DOMNodeRemoved';
let unEditable = null;
const unEditableSelector = '*[contenteditable="false"]';
const container = document.querySelector(".container");
const appendUneditable = (evt) => unEditable &&
!evt.relatedNode.querySelector(unEditableSelector) &&
evt.relatedNode.append(unEditable);
const listener = (evt) => evt.type === DOMNodeRemoved && appendUneditable(evt);
container.addEventListener("focus", focus);
container.addEventListener("blur", blur);
function focus(e) {
unEditable = e.target.querySelector(unEditableSelector);
unEditable.addEventListener("DOMNodeRemoved", listener, false);
}
function blur(e) {
unEditable && e.target.append(unEditable);
unEditable && unEditable.removeEventListener("DOMNodeRemoved", listener);
}
Upvotes: 3