Following this SO post, I am able to place the caret inside a span
element, which is inside a div contenteditable="true"
.
I am able to target whichever span
I desire, via its id
, while also being able to decide which character should the caret be placed after.
But how can I place the caret inside a span that has no text inside?
Simply using the function, as is, gets me this error: TypeError: Range.setStart: Argument 1 is not an object.
Also, for some reason, when the span
has content, it works fine, in Firefox. But not in Chrome, where the caret is placed outside the span
. Any way to also solve this problem?
I am open to jQuery, if it makes things easier.
Here is my code:
JSFiddle
function setCaret(x, y) {
var element = document.getElementById(x);
var range = document.createRange();
var node;
node = document.getElementById(y);
range.setStart(node.childNodes[0], 0);
var sel = window.getSelection();
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
element.focus();
}
body {
font-family: sans-serif;
}
input {
margin-bottom: 5px;
padding: 3px;
}
input:last-of-type {
margin-top: 30px;
}
div {
width: 300px;
padding: 5px;
border: solid 1px #000;
}
span {
font-weight: bold;
}
<input type="button" value="place caret" onclick="setCaret('editableDiv1', 'span1');">
<div id="editableDiv1" contenteditable="true" spellcheck="false">This one <span id="span1">is</span> working.</div>
<input type="button" value="place caret" onclick="setCaret('editableDiv2', 'span2');">
<div id="editableDiv2" contenteditable="true" spellcheck="false">This one <span id="span2"></span> is not.</div>
Following this SO post, I am able to place the caret inside a span
element, which is inside a div contenteditable="true"
.
I am able to target whichever span
I desire, via its id
, while also being able to decide which character should the caret be placed after.
But how can I place the caret inside a span that has no text inside?
Simply using the function, as is, gets me this error: TypeError: Range.setStart: Argument 1 is not an object.
Also, for some reason, when the span
has content, it works fine, in Firefox. But not in Chrome, where the caret is placed outside the span
. Any way to also solve this problem?
I am open to jQuery, if it makes things easier.
Here is my code:
JSFiddle
function setCaret(x, y) {
var element = document.getElementById(x);
var range = document.createRange();
var node;
node = document.getElementById(y);
range.setStart(node.childNodes[0], 0);
var sel = window.getSelection();
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
element.focus();
}
body {
font-family: sans-serif;
}
input {
margin-bottom: 5px;
padding: 3px;
}
input:last-of-type {
margin-top: 30px;
}
div {
width: 300px;
padding: 5px;
border: solid 1px #000;
}
span {
font-weight: bold;
}
<input type="button" value="place caret" onclick="setCaret('editableDiv1', 'span1');">
<div id="editableDiv1" contenteditable="true" spellcheck="false">This one <span id="span1">is</span> working.</div>
<input type="button" value="place caret" onclick="setCaret('editableDiv2', 'span2');">
<div id="editableDiv2" contenteditable="true" spellcheck="false">This one <span id="span2"></span> is not.</div>
Share
Improve this question
edited Oct 15, 2020 at 11:13
MikeMichaels
asked Oct 15, 2020 at 10:58
MikeMichaelsMikeMichaels
4942 gold badges6 silver badges27 bronze badges
4
-
On Chrome, when I click the "place caret" button on the one that says it's working and start typing, what I type doesn't go in the
span
, it goes before the span (e.g., it's not bold). On Firefox what I type is within the span. So I hate to say it, but the code is already problematic even when thespan
has content. – T.J. Crowder Commented Oct 15, 2020 at 11:04 - Firefox here. Still haven't tested it in other browsers. Here, it works as intended. I click on the button, it moves the caret inside the span, and it stays there as I type. – MikeMichaels Commented Oct 15, 2020 at 11:07
- See also stackoverflow./questions/53747581/… – John M Commented Oct 19, 2020 at 9:16
-
2
You can correct the first issue by checking if there's a child node and adding an empty text element if not:
if (node.childNodes.length === 0) { var t = document.createTextNode(''); node.appendChild(t); }
Can't help with the Chrome issue though :-( – John M Commented Oct 19, 2020 at 9:18
3 Answers
Reset to default 9 +100There's a nice trick with zero-width space that you may consider (look at at the code below) and CSS property white-space: pre
that allows spaces to be "visible" when focused.
function makeTextNode() {
return document.createTextNode('') // <-- there a zero-width space between quotes
}
function placeCaretInSpan() {
const range = document.createRange()
const editable = document.getElementById("editable")
const span = editable.querySelector("span")
if (span.childNodes.length === 0) {
span.appendChild(makeTextNode()) // <-- you have to have something in span in order to place caret inside
}
range.setStart(span.childNodes[0], 1) // <-- offset by 1 to be inside SPAN element and not before it
let selection = window.getSelection()
range.collapse(true)
selection.removeAllRanges()
selection.addRange(range)
editable.focus()
}
span {
font-weight: bold;
background: yellow;
}
#editable:focus {
white-space: pre;
}
<div contenteditable="true" id="editable">This should be <span></span> editable.</div>
<button onclick="placeCaretInSpan()">place caret</button>
try with OR operator, this will return the node if node.childNodes[0] is undefined:
range.setStart(node.childNodes[0] || node, 0);
The problem occurs in the second case because span2
has no content and node.childNodes[0]
bees undefined
. A small workaround is used in the below snippet. The only line changed in your code is this:
range.setStart(node.childNodes[0], 0);
and became
range.setStart((typeof node.childNodes[0] !== 'undefined' ? node.childNodes[0] : node), 0);
You can check the result below.
function setCaret(x, y) {
let element = document.getElementById(x);
let range = document.createRange();
let node = document.getElementById(y);
range.setStart((typeof node.childNodes[0] !== 'undefined' ? node.childNodes[0] : node), 0);
let sel = window.getSelection();
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
element.focus();
}
body {
padding: 10px;
font-family: sans-serif;
}
input {
margin-bottom: 10px;
padding: 5px;
}
input:last-of-type {
margin-top: 50px;
}
div {
width: 300px;
padding: 5px;
border: solid 1px #000;
}
span {
font-weight: bold;
}
<input type="button" value="place caret" onclick="setCaret('editableDiv1', 'span1');">
<div id="editableDiv1" contenteditable="true" spellcheck="false">This one <span id="span1">is</span> working.</div>
<input type="button" value="place caret" onclick="setCaret('editableDiv2', 'span2');">
<div id="editableDiv2" contenteditable="true" spellcheck="false">This one <span id="span2"></span> is working also.</div>
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744311546a4567972.html
评论列表(0条)