Skip to content

Instantly share code, notes, and snippets.

@neet
Last active June 25, 2019 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neet/57f1f38e9bfa86393a0ab17b71a9839a to your computer and use it in GitHub Desktop.
Save neet/57f1f38e9bfa86393a0ab17b71a9839a to your computer and use it in GitHub Desktop.
10fastfingers mods
const speechedWords = new Set<number>();
const skip = 1;
const skipNNodes = (node: Node, n: number): Node =>
n === 0 ? node : skipNNodes(node.nextSibling, n - 1);
const getWordId = (element: Element) => Number(element.getAttribute("wordnr"));
function speechText(element: Element) {
if (skip > 0) {
// 10fastfingers has blank #text after span
const skipped = skipNNodes(element, skip * 2);
if (skipped instanceof Element) element = skipped;
}
if (speechedWords.has(getWordId(element))) {
return;
}
const utter = new SpeechSynthesisUtterance();
utter.rate = 1.2;
utter.lang = "en";
utter.text = element.textContent;
speechSynthesis.speak(utter);
speechedWords.add(getWordId(element));
return utter;
}
function highlightHandler(mutation: MutationRecord) {
if (!(mutation.target instanceof Element)) {
return;
}
if (
mutation.target.classList.contains("correct") &&
getWordId(mutation.target) === Math.max(...speechedWords.values())
) {
speechSynthesis.cancel();
}
if (mutation.target.classList.contains("highlight")) {
speechText(mutation.target);
}
}
function removeHandler(mutation: MutationRecord) {
if (mutation.removedNodes.length) {
speechedWords.clear();
}
}
function mutationHandler(
mutations: MutationRecord[],
_mutationObserver: MutationObserver
) {
for (const mutation of mutations) {
switch (mutation.type) {
case "attributes":
highlightHandler(mutation);
case "childList":
removeHandler(mutation);
default:
return;
}
}
}
function observeWords(node: Element) {
const mutationObserver = new MutationObserver(mutationHandler);
mutationObserver.observe(node, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ["class"],
attributeOldValue: true
});
}
function main() {
const element = document.querySelector("#words > #row1");
if (element) observeWords(element);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment