Skip to content

Instantly share code, notes, and snippets.

@gorango
Last active June 3, 2020 15:00
Show Gist options
  • Save gorango/bcfbbfef68a16aaaa4f5245bf27366ea to your computer and use it in GitHub Desktop.
Save gorango/bcfbbfef68a16aaaa4f5245bf27366ea to your computer and use it in GitHub Desktop.
function highlightSentences (sentences) {
const highlights = []
const body = document.body
const contentNodes = gatherTextNodes(body)
sentences.forEach(sentence => {
const range = document.createRange()
let rangeSentence = sentence.toLowerCase()
let start = false
contentNodes.forEach(node => {
const nodeSentence = node.textContent.toLowerCase()
const sentIndex = rangeSentence.indexOf(nodeSentence)
const nodeIndex = nodeSentence.indexOf(rangeSentence)
const s = rangeSentence
if (sentIndex > -1) {
if (!start) {
start = true
range.setStart(node, sentIndex)
}
rangeSentence = rangeSentence.slice(nodeSentence.length)
}
if (nodeIndex > -1) {
if (!start) {
start = true
range.setStart(node, nodeIndex)
}
range.setEnd(node, nodeIndex + s.length)
start = false
rangeSentence = sentence
addHighlight(range)
}
})
})
function addHighlight (range) {
const parentEl = getRangeParent(range)
Object.assign(parentEl.style, { zIndex: 2, position: 'relative' })
const { x, y } = getOffsets(parentEl)
Array.from(range.getClientRects()).forEach(({ top, left, width, height }) => {
[top, left] = [top - y, left - x]
const highlight = { top, left, width, height }
const exists = highlights.reduce((bool, h) => {
return bool || isObjEq({ ...h }, highlight)
}, false)
!exists && highlights.push(highlight)
})
}
function getRangeParent (range) {
const el = range.commonAncestorContainer
if (el.nodeName === '#text') {
return el.parentNode
}
return el
}
function gatherTextNodes (node) {
if (node.nodeName !== '#text') {
let res = []
node.childNodes.forEach(child => {
res = res.concat(gatherTextNodes(child))
})
return res
} else {
return [node]
}
}
function isObjEq (a, b) {
var aProps = Object.getOwnPropertyNames(a)
var bProps = Object.getOwnPropertyNames(b)
if (aProps.length !== bProps.length) {
return false
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i]
if (a[propName] !== b[propName]) {
return false
}
}
return true
}
function getOffsets (el) {
let x = -(document.documentElement.scrollLeft || document.body.scrollLeft)
let y = -(document.documentElement.scrollTop || document.body.scrollTop)
el = el.offsetParent
while (el) {
x += (el.offsetLeft - el.scrollLeft + el.clientLeft)
y += (el.offsetTop - el.scrollTop + el.clientTop)
el = el.offsetParent
}
return { x, y }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment