I am trying to make a small text editor.
When I select a text, I want to know if the selected text is alone in a span
or a div
, then I want to change the style of this element.
Example :
<span style="font-size:12px">Hola</span>
If I select Hola I want to retrieve the parent node <span style="font-size:12px">Hola</span>
<span style="font-size:56px">
Hola <span style="font-size:12px">Hello</span>
</span>
If I select Hello I want to retrieve only <span style="font-size:12px">Hello</span>
Now, when I try in Chrome, I get the correct result with
range.startContainer.parentNode;
But with Firefox in the second example I retrieve
<span style="font-size:56px">
Hola <span style="font-size:12px">Hello</span>
</span>
How can I get the same result in Chrome and in Firefox?
Your problem is that selections work slightly differently between browsers when one or both of the selection boundaries coincide with DOM node boundaries. For example, if the user selected the word "bar" in page content with the following HTML
<p>foo<i>bar</i></p>
... there are four different possible locations for the selection start that all look visually identical to the user:
<p>
element (node <p>
, offset 1)<i>
element (node <i>
, offset 0)Most browsers do not allow all these positions in practice, but unfortunately different browsers make different choices. In Firefox, the selection you've made selects the whole <span>
element and the selection range's startContainer
is the <span>
's parent node. You could detect this by examining the range to see if it selects a single node:
function rangeSelectsSingleNode(range) {
var startNode = range.startContainer;
return startNode === range.endContainer &&
startNode.hasChildNodes() &&
range.endOffset === range.startOffset + 1;
}
You can use this to detect what kind of selection you have and obtain the selected element accordingly:
var selectedElement = null;
if (rangeSelectsSingleNode(range)) {
// Selection encompasses a single element
selectedElement = range.startContainer.childNodes[range.startOffset];
} else if (range.startContainer.nodeType === 3) {
// Selection range starts inside a text node, so get its parent
selectedElement = range.startContainer.parentNode;
} else {
// Selection starts inside an element
selectedElement = range.startContainer;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With