How to remove all nodes from selected ranges - javascript

For example, I have such text:
Some test <span> in span1</span> sss <span>in span2</span> end of text.
when I select " test in span1 sss in spa" I want to just delete parent spans of selected ranges and create new range
that will contain my selected text.
Some<span> test in span1 sss in spa</span>n2 end of text.
I'm using window.getSelection(),range,nodes
Please help!

You can do this with the deleteContents(), toString() and insertNode() methods of a range obtained from the selection.
The following will work in all major browsers except IE <= 8. You'll need a different approach for those browsers, which I can outline if you need it.
Demo: http://jsfiddle.net/HUm2K/
Code:
var sel = window.getSelection();
if (sel.rangeCount > 0) {
var range = sel.getRangeAt(0);
var newSpan = document.createElement("span");
var selectedTextNode = document.createTextNode( range.toString() );
newSpan.appendChild(selectedTextNode);
range.deleteContents();
range.insertNode(newSpan);
range.selectNode(newSpan);
sel.removeAllRanges();
sel.addRange(range);
}

Related

Is there a way to select text through multiple elements?

var range = document.createRange();
var root_node = document.getElementById("test");
// Start at the `hello` element.
range.setStart(root_node.childNodes[0], 2);
// End in the `world` node
range.setEnd(root_node.childNodes[1], 2);
range.selectNodeContents(root_node);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div id="test">
hello
<span>world</span>
</div>
I'd like to select text but because it's in different elements it hasn't been working. Is there a way to do this?
I don't mean to highlight both words in their entirety but portions of each word.
#Matt answer is in the right direction, but doesn't achieve what the OP wants, which is to "span" the range across multiple elements (nodes), while using offsets within those elements.
The following achieve it:
var range = document.createRange();
var root_node = document.getElementById("test");
range.setStart(root_node.querySelector('a').firstChild, 2);
range.setEnd(root_node.querySelector('span').firstChild, 3);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div id="test">
hello
<span>world</span>
</div>
Note how on both setStart and setEnd we pass a text node - this is the firstChild of the anchor and span elements.
For further reading on this subject, please refer to this excellent explanation.
You called setStart twice, instead of setStart followed by setEnd, and you are specifying an offset of 2 in each case, but I don't think you want an offset because that puts your node index out of range (and throws an error).
var range = document.createRange();
var root_node = document.getElementById("test");
// Start at the `hello` element.
range.setStart(root_node.childNodes[0], 0);
// End in the `world` node
range.setEnd(root_node.childNodes[1], 0);
range.selectNodeContents(root_node);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div id="test">
hello
<span>world</span>
</div>

How to select text range within a contenteditable div that has no child nodes?

I'd like to select text within a content editable div. I'd like to provide a start index and an end index.
For example if I have a div:
<div id="main" contenteditable="true">
Hello World
</div>
I'd like a function to do something like "selectText('#main',6,10)" and it would select set the focus to main and select "World".
But all the examples that I see online assume that the container div has children. But mine don't have any children. Just the text within the div.
This is what I've tried so far to no avail:
$('#main').focus();
var mainDiv = document.getElementById("main");
var startNode = mainDiv;
var endNode = mainDiv;
var range = document.createRange();
range.setStart(startNode, 6);
range.setEnd(endNode, 10);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
But I get:
Uncaught IndexSizeError: Failed to execute 'setStart' on 'Range': There is no child at offset 6.
My jsfiddle:
http://jsfiddle.net/foreyez/h4bL5u4g/
But mine don't have any children. Just the text within the div.
The text within the div is a child – it's a text node. That's what you want to target.
You will also need to trim its nodeValue to get the proper offset. Otherwise, the leading spaces will be included.
This seems to do what you want:
function SelectText(obj, start, stop) {
var mainDiv = $(obj)[0],
startNode = mainDiv.childNodes[0],
endNode = mainDiv.childNodes[0];
startNode.nodeValue = startNode.nodeValue.trim();
var range = document.createRange();
range.setStart(startNode, start);
range.setEnd(endNode, stop + 1);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} //SelectText
$('#main').focus();
SelectText('#main', 6, 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main" contenteditable="true">
Hello World
</div>

Add tags around selected text in an element

How can I add <span> tags around selected text within an element?
For example, if somebody highlights "John", I would like to add span tags around it.
HTML
<p>My name is Jimmy John, and I hate sandwiches. My name is still Jimmy John.</p>
JS
function getSelectedText() {
t = (document.all) ? document.selection.createRange().text : document.getSelection();
return t;
}
$('p').mouseup(function(){
var selection = getSelectedText();
var selection_text = selection.toString();
console.log(selection);
console.log(selection_text);
// How do I add a span around the selected text?
});
http://jsfiddle.net/2w35p/
There is a identical question here: jQuery select text and add span to it in an paragraph, but it uses outdated jquery methods (e.g. live), and the accepted answer has a bug.
I have a solution. Get the Range of the selecion and deleteContent of it, then insert a new span in it .
$('body').mouseup(function(){
var selection = getSelectedText();
var selection_text = selection.toString();
// How do I add a span around the selected text?
var span = document.createElement('SPAN');
span.textContent = selection_text;
var range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(span);
});
You can see the DEMO here
UPDATE
Absolutly, the selection will be delete at the same time. So you can add the selection range with js code if you want.
You can simply do like this.
$('body').mouseup(function(){
var span = document.createElement("span");
if (window.getSelection) {
var sel = window.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0).cloneRange();
range.surroundContents(span);
sel.removeAllRanges();
sel.addRange(range);
}
}
});
Fiddle
Reference Wrapping a selected text node with span
You can try this:
$('body').mouseup(function(){
var selection = getSelectedText();
var innerHTML = $('p').html();
var selectionWithSpan = '<span>'+selection+'</span>';
innerHTML = innerHTML.replace(selection,selectionWithSpan);
$('p').html(innerHTML);
});
and In your fiddle you are again opening a new <p> instead of a closing </p>. Update that please.
THIS WORKS (mostly*)!! (technically, it does what you want, but it needs HALP!)
JSFiddle
This adds <span ...> and </span> correctly, even if there are multiple instances of the selection in your element and you only care about the instance that's selected!
It works perfectly the first time if you include my commented line. It's after that when things get funky.
I can add the span tags, but I'm having a hard time replacing the plaintext with html. Maybe you can figure it out? We're almost there!! This uses nodes from getSelection. Nodes can be hard to work with though.
document.getElementById('d').addEventListener('mouseup',function(e){
var s = window.getSelection();
var n = s.anchorNode; //DOM node
var o = s.anchorOffset; //index of start selection in the node
var f = s.focusOffset; //index of end selection in the node
n.textContent = n.textContent.substring(0,o)+'<span style="color:red;">'
+n.textContent.substring(o,f)+'</span>'
+n.textContent.substring(f,n.textContent.length);
//adds the span tag
// document.getElementById('d').innerHTML = n.textContent;
// this line messes stuff up because of the difference
// between a node's textContent and it's innerHTML.
});

How do I select (get range or selection object) an element in a contenteditable div if I know the element ID?

I have this contenteditable element:
<div id="editMe" contenteditable="true">
There is some text here.
<span id="selectThisText">This is the target text.</span>
And some here.
</div>
I want to use Javascript to select (get range object) the contents of #selectThisText. How do I get the range of the content in that element?
Thanks in advance!
Create a range and use its selectNodeContents() method.
var span = document.getElementById("selectThisText");
var range = document.createRange();
range.selectNodeContents(span);
This doesn't work in IE <= 8, which doesn't support DOM Range. However, this is one case which is just as easy in old IE:
var span = document.getElementById("selectThisText");
var textRange = document.body.createTextRange();
textRange.moveToElementText(span);
//get Selection
var selection = window.getSelection();
//get Range
var range = selection.getRangeAt(0); //where the range selection happens.
var text = $('#selectThisText').text();
Demo: http://jsfiddle.net/5NBnP/

javascript contenteditable: set cursor at character offset

I need to set the cursor at a specific character offset. In the example below, I'd want to, for example, set it between the "a" and the "b".
<ul contenteditable = true >
<li id = "test">abcdef</li>
</ul>
I asked before and got this fiddle: http://jsfiddle.net/5a9uD/1/
That worked great for the given example and for what I needed it for then. But it does not work with this example: http://jsfiddle.net/mdwWN/ It gets an IndexSizeError at
range = sel.getRangeAt(0);
You just have to pass text container's childNodes[0] to range.setStart function.
Check this out.
function setSelectionRange(aNode, childElem, aOffset) {
aNode.focus();
var sel = window.getSelection(),
range = sel.getRangeAt(0);
range.collapse(true);
range.setStart(childElem.childNodes[0], aOffset),
sel.removeAllRanges();
sel.addRange(range);
}
var container = document.getElementById("test");
var childElement = document.getElementById('item1');
setSelectionRange(container, childElement, 1);
Here is the working fiddle.

Categories