So I actually have this mostly working, but I’ve run into an issue that I can’t quite get sorted. First I need to give a quick explanation of what I’m trying to do:
What I’m trying to do and the accompanying code
The page displays a chapter from the Bible. For any verse, I would like to allow the user to either highlight the whole verse by double clicking on it, or they can just highlight a portion of the sentence rather than the whole verse by selecting it with their mouse.
So far, so good. My code allows the user to do both, as intended. Here is the code I have that I am using to do so.
First, an example of HTML output that displays a verse:
<span id="1" class="bogus" data-book="Genesis" data-chapter="1" data-verse="1">
<sup class="verse">1</sup>
<span id="verseText-1">In the beginning God created the heaven and the earth</span>
</span>
For highlighting entire verse by double clicking on it:
$('.bogus').on('dblclick', function() {
const { book, chapter, verse } = $(this).data();
highlighter(book, chapter, verse);
});
function highlighter( book, chapter, verse )
{
// Hightlight / remove highlight from verse
if($("#" + verse).hasClass('highlight'))
{
$("#" + verse).removeClass('highlight');
$.ajax({
type: "POST",
url: "{{ base_url }}bible/removeHighlight/",
data: {
book: book,
chapter: chapter,
verse: verse
},
dataType: "json",
encode: true,
});
} else {
$("#" + verse).addClass('highlight');
$.ajax({
type: "POST",
url: "{{ base_url }}bible/addHighlight/",
data: {
book: book,
chapter: chapter,
verse: verse
},
dataType: "json",
encode: true,
});
}
}
For highlighting a portion of a verse that user has selected with mouse:
// Wrap the text that user has selected
// with '<mark>' element
function markSelection()
{
let selection= window.getSelection().getRangeAt(0);
let selectedContent = selection.extractContents();
var mark= document.createElement("mark");
// mark.style.backgroundColor = "lightpink";
mark.appendChild(selectedContent);
selection.insertNode(mark);
}
// Get the text that was highlighted
// so we can save it to DB
function getSelectionText()
{
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
}
$('.bogus').on("mouseup", function (e){
const { book, chapter, verse } = $(this).data();
if($("#" + verse).hasClass("highlight"))
{
// do nothing
} else {
if(getSelectionText() != '' && getSelectionText() != ' ')
{
markSelection();
}
}
})
The problem I am encountering
Highlighting a random string with the mouse works fine, HOWEVER, if the user single clicks anywhere on a verse, it inserts the <mark>
element in an empty space:
I<mark></mark>n the beginning God created the heaven and the earth.
This is no bueno, obviously. Really, what should be happening is that a string should only be highlighted if it meets the following conditions –
- The user actually selects a string
- The current verse is not already highlighted (highlighted verses have the “highlight” class added to the parent
span
tag
I’m hoping one of you S.O. legends can guide me here and tell me what I’m missing in my code above. As always, thank you so much for your help and contributions to the community.