| 8 | * span elements with the given class name. |
| 9 | */ |
| 10 | const _highlight = (node, addItems, text, className) => { |
| 11 | if (node.nodeType === Node.TEXT_NODE) { |
| 12 | const val = node.nodeValue; |
| 13 | const parent = node.parentNode; |
| 14 | const pos = val.toLowerCase().indexOf(text); |
| 15 | if ( |
| 16 | pos >= 0 && |
| 17 | !parent.classList.contains(className) && |
| 18 | !parent.classList.contains("nohighlight") |
| 19 | ) { |
| 20 | let span; |
| 21 | |
| 22 | const closestNode = parent.closest("body, svg, foreignObject"); |
| 23 | const isInSVG = closestNode && closestNode.matches("svg"); |
| 24 | if (isInSVG) { |
| 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); |
| 26 | } else { |
| 27 | span = document.createElement("span"); |
| 28 | span.classList.add(className); |
| 29 | } |
| 30 | |
| 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); |
| 32 | parent.insertBefore( |
| 33 | span, |
| 34 | parent.insertBefore( |
| 35 | document.createTextNode(val.substr(pos + text.length)), |
| 36 | node.nextSibling |
| 37 | ) |
| 38 | ); |
| 39 | node.nodeValue = val.substr(0, pos); |
| 40 | |
| 41 | if (isInSVG) { |
| 42 | const rect = document.createElementNS( |
| 43 | "http://www.w3.org/2000/svg", |
| 44 | "rect" |
| 45 | ); |
| 46 | const bbox = parent.getBBox(); |
| 47 | rect.x.baseVal.value = bbox.x; |
| 48 | rect.y.baseVal.value = bbox.y; |
| 49 | rect.width.baseVal.value = bbox.width; |
| 50 | rect.height.baseVal.value = bbox.height; |
| 51 | rect.setAttribute("class", className); |
| 52 | addItems.push({ parent: parent, target: rect }); |
| 53 | } |
| 54 | } |
| 55 | } else if (node.matches && !node.matches("button, select, textarea")) { |
| 56 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); |
| 57 | } |
| 58 | }; |
| 59 | const _highlightText = (thisNode, text, className) => { |
| 60 | let addItems = []; |
| 61 | _highlight(thisNode, addItems, text, className); |