Context
I'm trying to get the HTML of selected text based on the text itself. So, if the following HTML was implemented into a page:
<p>Random content <span>here and other</span> random content here.</p>
It would show up like so:
Random content here and other random content here.
If the user selects content here and, I would want to get not only the text, but the surrounding HTML. I found the following function, which does this effectively:
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
The result of this would be content <span>here and </span>. The only problem with this is that the <span> tag automatically closes itself, even if I didn't select the text past the closing span tag. When looking at the MDN documentation for .cloneContents(), it says:
Partially selected nodes include the parent tags necessary to make the document fragment valid.
I believe this explains why the tags close themselves.
Question
How do get I the selected text and its HTML without the closing tag (unless I select that as well)? In this case, how do I get the text content <span> here and instead of content <span>here and </span>? If I was to select the whole statement that the span encompassed, though, I would want it to be included.
Things I Have Tried
I tried cutting off the </span> at the end of the string (if it exists) with the following function, but it breaks down when I'm spanning over multiple HTML tags. I want the span, strong, and i tags to be cut off if I don't highlight all the text they encompass. So, when spanning over one element, it works, but when you span over more than one, it doesn't. It also cuts off the span even if I hover over the whole text that the span encompasses, so this solution doesn't work.
$("p").click(function() {
if (window.getSelection) {
sel = window.getSelection();
} else if (document.selection && document.selection.type != "Control") { //for IE
sel = document.selection.createRange();
}
var selectedText = getSelectionHTML();
checkTags(selectedText);
});
function checkTags(selectedText) {
var prohibited = ['</span>', '</strong>', '</i>'];
for (var i = 0; i < prohibited.length; i++) {
if (selectedText.indexOf(prohibited[i]) > -1) {
var splitText = selectedText.split("</");
splitText.pop();
}
}
alert(splitText);
}
function getSelectionHTML() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>This random content is here <span> within the span <span> <strong>other random content</strong> is here.</p>