-> ,
// but
is a parent of the , so we add and remove
paragraphs = paragraphs.filter((p) => {
return !isChildOf(p, currentParent)
})
paragraphs.push(currentNode.parentElement)
}
paragraphs.forEach((p) => {
if (makeParagraph(p)) {
createPlayer(p)
}
})
const underline = document.createElement('div')
underline.classList.add('tts-underline')
document.body.insertAdjacentElement('beforeend', underline)
}
static extractTextToSpeak = () => {
const paragraphs = Array.from(document.querySelectorAll('[tts-paragraph-index]'))
.map((p) => {
return p.textContent
})
return {
title: document.title,
author: this.$(this.metaDataDivId)?.querySelector('.author')?.textContent,
desciption: this.$(this.metaDataDivId)?.querySelector('.subhead')?.textContent,
paragraphs: paragraphs
}
}
static highlightWord = (paragraph, start, end) => {
if (!paragraph || start >= end) {
CSS.highlights.clear()
const underline = document.querySelector('.tts-underline')
underline.classList.remove('tts-underline-visible')
underline.setAttribute('data-top', 0)
return
}
const nodes = document.createNodeIterator(
paragraph,
NodeFilter.SHOW_TEXT,
{ acceptNode(n) { return NodeFilter.FILTER_ACCEPT } })
const range = new Range()
let startNode = null
let endNode = null
let node = null
// eslint-disable-next-line no-cond-assign
while (node = nodes.nextNode()) {
if (!startNode) {
if (start < node.textContent.length) {
startNode = node
range.setStart(node, start)
}
start -= node.textContent.length
}
if (!endNode) {
if (end <= node.textContent.length) {
endNode = node
range.setEnd(endNode, end)
}
end -= node.textContent.length
}
}
const underline = document.querySelector('.tts-underline')
const bodyRect = document.body.getBoundingClientRect()
const highlightedRect = range.getBoundingClientRect()
const top = highlightedRect.bottom - bodyRect.top
const left = highlightedRect.left - bodyRect.left
const width = highlightedRect.width + 2;
underline.classList.toggle('tts-underline-newline',
underline.getAttribute('data-top') != top)
underline.classList.toggle('tts-underline-decrease',
underline.getAttribute('data-width') < width)
underline.classList.add('tts-underline-visible')
underline.setAttribute('data-top', top)
underline.setAttribute('data-width', width)
underline.style.setProperty('--tts-underline-top', top + 'px');
underline.style.setProperty('--tts-underline-left', left + 'px');
underline.style.setProperty('--tts-underline-width', width + 'px');
CSS.highlights.set('tts-highlighted-word', new Highlight(range))
}
static setTtsButtonIcon = (e, i) => {
const button = e?.querySelector('.tts-paragraph-player-button')
if (button) {
button.classList.remove('tts-play-icon', 'tts-pause-icon')
button.classList.add(i)
}
}
static highlightText = (ttsParagraphIndex, charIndex, length) => {
if (!this.isTtsEnabled()) {
return
}
document.querySelectorAll('.tts-highlighted').forEach((e) => {
if (e.getAttribute('tts-paragraph-index') != ttsParagraphIndex) {
e.classList.remove('tts-highlighted')
this.setTtsButtonIcon(e, 'tts-play-icon')
}
})
const paragraph = document.querySelector(
'[tts-paragraph-index="' + ttsParagraphIndex + '"]')
if (paragraph) {
paragraph.classList.add('tts-highlighted')
if (this.speedreaderData.ttsReading) {
this.setTtsButtonIcon(paragraph, 'tts-pause-icon')
} else {
this.setTtsButtonIcon(paragraph, 'tts-play-icon')
}
}
this.highlightWord(paragraph, charIndex, charIndex + length)
}
static setTtsReadingState = (reading) => {
this.speedreaderData.ttsReading = reading
if (!this.speedreaderData.ttsReading) {
this.setTtsButtonIcon(document.querySelector('.tts-highlighted'), 'tts-play-icon')
}
}
}
(() => {
speedreaderUtils.speedreaderData = Object.assign(
speedreaderUtils.defaultSpeedreaderData,
window.speedreaderData)
speedreaderUtils.adoptStyles()
speedreaderUtils.initShowOriginalLink()
speedreaderUtils.calculateReadtime()
speedreaderUtils.initTextToSpeak()
})()