Reputation: 21
consider the following selected html snippet:
<span>...</span><span>...</span><span>....</span>
.......||||||||||||||||||||||||||||||.......
The second line represents the user selection (the pipes), spanning across several span tags. Using javascript, I'd like to retrieve the (non-text) nodes partially or completely selected (in this example the 3 span tags).
Thanks,
Upvotes: 2
Views: 2674
Reputation: 9119
Solution: window.getSelection().getRangeAt(0).cloneContents()
Source: somebody’s deleted comment @ https://stackoverflow.com/questions/43542742/find-text-on-page-and-select-it
window.getSelection().addRange(new Range());
var dispray = document.querySelectorAll("[id^=dispray]");
var Go = () => {
var fragm = window.getSelection().getRangeAt(0).cloneContents();
dispray[0].innerHTML = "";
dispray[0].appendChild(fragm);
dispray[1].innerText = dispray[0].innerHTML;
}
#sample {color: red;}
#sample > span {color: green;}
#panel {height: 5em; border: 3px solid #ccc; resize: vertical; overflow-y: scroll;}
#panel > table {width: 100%; height: 100%; /* border-collapse: collapse; */}
#panel > table td {vertical-align: top; padding: 0.5em;}
#panel > table #disprayA {border-right: 1px solid #ccc;}
<p id="sample" onMouseUp="Go()"><span>Lorem ipsum <b>dolor sit</b> amet.⇥</span
> Text node <span>⇤Maecenas <b>porttitor a felis</b> in pharetra.⇥</span><span
>⇤Nulla accumsan auctor est sit amet finibus.</span></p>
<div id="panel"><table><tr>
<td id="disprayA">Copied selection goes here...</td>
<td><code id="disprayB">Source code of copied selection goes here...</code></td>
</tr></table></div>
Your “little” requirement that copy of selection contain no bare Text nodes complicates the code greatly.
window.getSelection().addRange(new Range());
var dispray = document.querySelectorAll("[id^=dispray]");
var Go = () => {
dispray[0].innerHTML = "";
var r = window.getSelection().getRangeAt(0);
var fragm = r.cloneContents();
if ([...fragm.childNodes].some(child => child.nodeType === Node.TEXT_NODE)) {
/* if selection contains some bare Text nodes... */
var ancestorElement = r.commonAncestorContainer;
if (ancestorElement.nodeType === Node.TEXT_NODE)
ancestorElement = ancestorElement.parentElement;
var ancestorElement2 = ancestorElement.cloneNode(false);
ancestorElement2.appendChild(fragm);
dispray[0].appendChild(ancestorElement2);
}
else dispray[0].appendChild(fragm);
dispray[1].innerText = dispray[0].innerHTML;
}
#sample {color: red;}
#sample > span {color: green;}
#panel {height: 5em; border: 3px solid #ccc; resize: vertical; overflow-y: scroll;}
#panel > table {width: 100%; height: 100%; /* border-collapse: collapse; */}
#panel > table td {vertical-align: top; padding: 0.5em;}
#panel > table #disprayA {border-right: 1px solid #ccc;}
<p id="sample" onMouseUp="Go()"><span>Lorem ipsum <b>dolor sit</b> amet.⇥</span
> Text node <span>⇤Maecenas <b>porttitor a felis</b> in pharetra.⇥</span><span
>⇤Nulla accumsan auctor est sit amet finibus.</span></p>
<div id="panel"><table><tr>
<td id="disprayA">Copied selection goes here...</td>
<td><code id="disprayB">Source code of copied selection goes here...</code></td>
</tr></table></div>
Upvotes: 3
Reputation: 324607
To do this cross browser (including IE) and quite conveniently, you can use my Rangy library, which provides extended DOM Range and Selection objects in all browsers. The code would look something like:
var sel = rangy.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
var selectedElements = range.getNodes([1]); // [1] is an array of node types
alert("Found " + selectedElements.length + " selected elements");
}
Upvotes: 2
Reputation: 2964
Unfortunately, there is no instant solution for that problem. To solve this you will need to use var sel = window.getSelection()
to get an instance of a Selection object which represents the selected elements. From there, you can use sel.anchorNode()
to get the element where the selection starts and sel.focusNode()
to get the element where it ends. Keep in mind, these will be instances of TextNode and will actually be children of the span that you want.
You will have to come up with a way to determine the shortest path between the two nodes (anchor and focus) which will give you all the information you need.
EDIT: Oh, btw, this is the mozilla/webkit implementation. IE is a completely different beast. You will need to use var sel = document.selection
. Check out How can I get the DOM element which contains the current selection? for more information on how to do this in a cross browser way
Upvotes: 0