// node detection helpers.
function isElementNode(node) {
return (node && (node.nodeType === 1));
}
function isNonEmptyTextNode(node) {
return (
node
&& (node.nodeType === 3)
&& (node.nodeValue.trim() !== '')
&& (node.parentNode.tagName.toLowerCase() !== 'script')
);
}
// dom node render helper.
function insertNodeAfter(node, referenceNode) {
const { parentNode, nextSibling } = referenceNode;
if (nextSibling !== null) {
node = parentNode.insertBefore(node, nextSibling);
} else {
node = parentNode.appendChild(node);
}
return node;
}
// text node reducer functionality.
function collectNonEmptyTextNode(list, node) {
if (isNonEmptyTextNode(node)) {
list.push(node);
}
return list;
}
function collectTextNodeList(list, elmNode) {
return Array.from(
elmNode.childNodes
).reduce(
collectNonEmptyTextNode,
list
);
}
function getTextNodeList(rootNode) {
rootNode = (isElementNode(rootNode) && rootNode) || document.body;
const elementNodeList = Array.from(
rootNode.getElementsByTagName('*')
);
elementNodeList.unshift(rootNode);
return elementNodeList.reduce(collectTextNodeList, []);
}
// highlight functinality.
function createSearchMatch(text) {
const elmMatch = document.createElement('mark');
// elmMatch.classList.add("highlight");
elmMatch.textContent = text;
return elmMatch;
}
function aggregateSearchResult(collector, text, idx, arr) {
const { previousNode, regXSearch } = collector;
const currentNode = regXSearch.test(text)
? createSearchMatch(text)
: document.createTextNode(text);
if (idx === 0) {
previousNode.parentNode.replaceChild(currentNode, previousNode);
} else {
insertNodeAfter(currentNode, previousNode);
}
collector.previousNode = currentNode;
return collector;
}
function highlightSearch(textNode, regXSearch) {
// console.log(regXSearch);
textNode.textContent
.split(regXSearch)
.filter(text => text !== '')
.reduce(aggregateSearchResult, {
previousNode: textNode,
regXSearch,
})
}
function highlightSearchFromBoundContext(/* evt */) {
const { elmSearch, sourceNode, targetNode } = this;
const replacementNode = sourceNode.cloneNode(true);
const searchValue = elmSearch.value.trim();
if (searchValue !== '') {
const regXSearchString = searchValue
// from the OP's original code ... escaping of regex specific characters.
.replace((/[.*+?^${}()|[]\]/g), '\$&')
// additional escaping of whitespace (sequences).
.replace((/s+/g), '\s+');
const regXSearch = RegExp(`(${ regXSearchString })`, 'gi');
getTextNodeList(replacementNode).forEach(textNode =>
highlightSearch(textNode, regXSearch)
);
}
targetNode.parentNode.replaceChild(replacementNode, targetNode);
this.targetNode = replacementNode;
}
// initialize search behavior
function initializeSearchAndHighlight() {
const elmSearch = document
.querySelector('#block-multiblock-2 input[type="search"]');
const elmHighlight = elmSearch && document
.querySelector('.group-informacie .field-name-body');
if (elmHighlight && (elmHighlight.textContent.trim() !== '')) {
const handleChangeEvent = highlightSearchFromBoundContext.bind({
elmSearch,
targetNode: elmHighlight,
sourceNode: elmHighlight.cloneNode(true),
});
const handleChangeEventThrottled = _.throttle(handleChangeEvent, 200);
elmSearch.addEventListener('input', handleChangeEventThrottled);
handleChangeEvent();
}
}
initializeSearchAndHighlight();
p { margin: 7px 0 0 0; }
/*
.as-console-wrapper { max-height: 67px!important; }
*/
<label id="block-multiblock-2">
<span class="label">Highlight search ...</span>
<input
type="search"
placeholder="... type some text"
value="dolor (sit) amet"
/>
</label>
<article class="group-informacie">
<section class="field-name-body">
<p>
Lorem ipsum dolor (sit) amet, consetetur sadipscing elitr, ??sed?? diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam [erat], sed diam voluptua.
</p>
<p>
At vero [eos] et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, (no) **sea** takimata sanctus est Lorem ipsum dolor [sit] amet.
</p>
<p>
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
</p>
</section>
</article>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>