Last active
June 3, 2020 15:00
-
-
Save gorango/bcfbbfef68a16aaaa4f5245bf27366ea to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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