I’m trying to use Mark.js to find a search value in data attribute values. When a match is found, I’d like to highlight the attribute’s element. In the HTML below, I want to highlight .terms
, when a match is found in the data-definition
value.
HTML
<div class="search-in-doc">
<input type="search" placeholder="Search this page" >
<button data-search="prev"><i class="fas fa-chevron-left"></i></button>
<button data-search="next"><i class="fas fa-chevron-right"></i></button>
<button data-search="clear"><i class="fas fa-times"></i></button>
</div>
<div id="main">
<p>Lorem ipsum dolor sit amet, <a class="terms" data-definition="third-person singular present active subjunctive of consector." href="https://example.com">consectetur</a> adipiscing elit, sed do eiusmod.</p>
<p>Excepteur sint occaecat cupidatat non proident, sunt in <a class="terms" data-definition="actionable negligence or fault" href="https://anotherexample.com">culpa</a>.</p>
</div>
Javascript (in this code, I’m targeting #main
as the context for testing. But I want to figure out how to target data-definition
instead)
var $input = $(".search-in-doc input[type='search']"),
// clear button
$clearBtn = $("button[data-search='clear']"),
// prev button
$prevBtn = $("button[data-search='prev']"),
// next button
$nextBtn = $("button[data-search='next']"),
// the context where to search
$content = $("#main"),
// jQuery object to save <mark> elements
$results,
// the class that will be appended to the current
// focused element
currentClass = "current",
// top offset for the jump (the search bar)
offsetTop = 50,
// the current index of the focused element
currentIndex = 0;
/**
* Jumps to the element matching the currentIndex
*/
function jumpTo() {
if ($results.length) {
var position,
$current = $results.eq(currentIndex);
$results.removeClass(currentClass);
if ($current.length) {
$current.addClass(currentClass);
position = $current.offset().top - offsetTop;
window.scrollTo(0, position);
}
}
}
/**
* Searches for the entered keyword in the
* specified context on input
*/
$input.on("input", function() {
localStorage.clear();
searchVal = this.value;
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
jumpTo();
}
});
}
});
});
/**
* Clears the search
*/
$clearBtn.on("click", function() {
localStorage.clear();
console.log(localStorage);
$content.unmark();
$input.val("").focus();
});
/**
* Next and previous search jump to
*/
$nextBtn.add($prevBtn).on("click", function() {
if ($results.length) {
currentIndex += $(this).is($prevBtn) ? -1 : 1;
if (currentIndex < 0) {
currentIndex = $results.length - 1;
}
if (currentIndex > $results.length - 1) {
currentIndex = 0;
}
jumpTo();
}
});
I tried The JS below returns all elements with the data-definition
attribute. But searches within this context match on the anchor element’s text, not the attribute’s value.
$content = document.querySelectorAll('[data-definition]');
If I can add my search value to the method below, then I get a NodeList of elements with a match in data-definition
. Great. These results could be highlighted and the matches would be correct. But I’m not sure how to incorporate this into Mark.js. I don’t know how or where to pass the search value as a variable to this context definition. And maybe there’s another way that works better with Mark.js
$content = document.querySelectorAll('[data-definition*="' + searchVal + '"]');