// ==UserScript==
// @name Duolingo HearEverything
// @namespace http://tampermonkey.net/
// @version 0.39
// @description Let's you hear phrases and words from single choice questions based on your browsers speech synthesis (right now only phrases).
// @author Esh
// @match https://*.duolingo.com/*
// @grant GM_setValue
// @grant GM_getValue
// @downloadURL none
// ==/UserScript==
/*
// 0.7: Mutation Observer instead of setInterval
// 0.6: Add voice to choices on click
// 0.6.1: check why not the innerText of the answer is displayed in the full sentence?
// 0.8.1: fix speaking numbers for options
// 0.9: Move speak button near the continue button
// 0.10.2: set better newPage = true - deleted
// 0.10.3: debug quirks from setting newPage
// 0.11: cleaned up some code
// 0.12: finally got rid of the new page problem
// 0.13: show some debug infos on the page
// 0.14: more working reading
// 0.15: added more challenges to read
// 0.16: Challenges, which work (some partially) // FORM, TRANSLATE, DIALOGUE, GAP_FILL, COMPLETE_REVERSE_TRANSLATION, TAP_COMPLETE
// 0.17: added shortcut ALT+l
// 0.18: listening button for DIALOGUE and bugfixing TRANSLATE
// 0.19: better listening button
// 0.20: Voice selection
// 0.21: cleaned up code
// 0.22: challenge translate (tap) working
// 0.22.1: no speaker button with translate from learning language
// 0.23: Alt + l for Duo buttons, too
// 0.24: tap-complete working
// 0.25: form challenge working
// 0.25.1: bugfix: challenge-translate
// 0.26: challenge read-comprehension
// 0.27: challenge name
// 0.28: autoplay for challenge translate
// 0.29: replace prompt at challenge gap fill
// 0.30: gap fill auto play
// 0.30.1: fixed playback stops
// 0.31: stops playback on new page
// 0.31.1: fixed gap fill not reading whole answer
// 0.32: auto play for complete reverse translation
// 0.33: toggle options readout at gap fill challenge
// 0.34: challenge dialogue auto play, auto intro, play options
// 0.34.1: bug fix only render intro button at challenge dialogue
// 0.35: challenge tapComplete
// 0.36: challenge form
// 0.37: challenge gap fill - extended
// bug fix challenge Tap Complete
// 0.38: better looking config menu
// 0.38.1: removed unused code
// 0.39: hide config on mouse click outside
*/
/*
// 0.30.2: TODO: move autoplay and config check/uncheck checkbox GM_setValue to own function
// 0.30.3: TODO: move let utter to own function
// TODO: close button / close with outside click on config bubble
// TODO: config for challenges
// TODO: replace gaps with correct answers FORM,
// TODO: DIALOGUE should start with reading speaker 1
// TODO: maybe add listening to speaking experience?
// TODO: clean up the script even more
// TODO: Tipp-Page
// TODO: Hoots
// TODO: selector where the speak button should be
// TODO: translateInput speaker position top - where to place?
// TODO: Voice selector (automagic) - 1/4 done
// TODO: Add autoplay selector
// more examples on the bottom
// TODO: popup could be toggled by mouseover/mouseout
*/
const VERSION = '0.39 --- 1 ---';
const LOG_STRING = 'Duolingo HearEverything: ';
const buttonPosition = 'bottom'; // bottom / top allowed
let voiceSelect;
let config = {};
const DEBUG = false;
// for config mouse hover
let hover = true;
let synth = window.speechSynthesis;
let voices = [];
let newPage = false;
let addedSpeech = false;
let speakerButton = `
`;
// Element definitions
const WRONG_ANSWER_CLASS = '._1UqAr._1sqiF';
const RIGHT_ANSWER_CLASS = '._1UqAr._1Nmv6';
const RIGHT_CLASS = '._1Nmv6';
const WRONG_CLASS = '._1sqiF';
const ANSWER_HEADLINE = '._1x6Dk';
const ANSWER_CONTAINER = '._2ez4I';
const DIALOGUE_SPEAKER_CLASS = '_29e-M _39MJv _2Hg6H';
// currently used
const ANSWER_CLASS = '._1UqAr';
const ANSWER = 'blame';
const ANSWER_QS = '[data-test~="' + ANSWER + '"]';
const RIGHT_ANSWER = 'blame-correct';
const RIGHT_ANSWER_QS = '[data-test~="' + RIGHT_ANSWER + '"]';
const WRONG_ANSWER = 'blame-incorrect';
const WRONG_ANSWER_QS = '[data-test~="' + WRONG_ANSWER + '"]';
const CHALLENGE_TAP_TOKEN = 'challenge-tap-token'; // challenge-translate (tap)
const CHALLENGE_TAP_TOKEN_QS = '[data-test="' + CHALLENGE_TAP_TOKEN + '"]';
const WORD_BANK = 'word-bank'; // if exists it's tap instead of keyboard (challenge-translate)
const WORD_BANK_QS = '[data-test="' + WORD_BANK + '"]';
const TRANSLATE_INPUT = 'challenge-translate-input';
const TRANSLATE_INPUT_QS = '[data-test="' + TRANSLATE_INPUT + '"]';
const SPEAKER_BUTTON = 'speaker-button';
const SPEAKER_BUTTON_QS = '[data-test="' + SPEAKER_BUTTON + '"]';
const HINT_SENTENCE = 'hint-sentence';
const HINT_SENTENCE_QS = '[data-test="' + HINT_SENTENCE + '"]';
const CHALLENGE_JUDGE = 'challenge-judge-text';
const CHALLENGE_JUDGE_QS = '[data-test="' + CHALLENGE_JUDGE + '"]';
const FORM_PROMPT = 'challenge-form-prompt';
const FORM_PROMPT_QS = '[data-test="' + FORM_PROMPT + '"]';
const RIGHT_OPTION_QS = '[aria-checked="true"] div';
const TEXT_INPUT = 'challenge-text-input';
const TEXT_INPUT_QS = '[data-test="' + TEXT_INPUT + '"]';
const SPEAK_INTRO = 'speakIntro';
const SPEAK_INTRO_QS = '#' + SPEAK_INTRO;
// used page types
const FORM = 'challenge challenge-form';
const TRANSLATE = 'challenge challenge-translate';
const DIALOGUE = 'challenge challenge-dialogue';
const GAP_FILL = 'challenge challenge-gapFill';
const COMPLETE_REVERSE_TRANSLATION = 'challenge challenge-completeReverseTranslation';
const TAP_COMPLETE = 'challenge challenge-tapComplete';
const LISTEN_COMPREHENSION = 'challenge challenge-listenComprehension';
const READ_COMPREHENSION = 'challenge challenge-readComprehension';
const NAME = 'challenge challenge-name';
// unused page types
const LISTEN = 'challenge challenge-listen';
// Word bank stuff
// is not read out by Duo all the time (but at "Tap what you hear");
const LISTEN_TAP = 'challenge challenge-listenTap';
// has word bank and some filled up answer to read
// duo reads aloud
const SELECT_TRANSCRIPTION = 'challenge challenge-selectTranscription';
// allowed challenge types
const TEST = [FORM, TRANSLATE, DIALOGUE, GAP_FILL, COMPLETE_REVERSE_TRANSLATION, TAP_COMPLETE, LISTEN_COMPREHENSION, READ_COMPREHENSION, NAME];
var buttonDisabled = true;
function debug(s) {
console.debug(LOG_STRING + s);
}
window.onload = function() {
'use strict';
console.debug(LOG_STRING + VERSION);
// console.log('---------------------onload-------------------------');
voices = window.speechSynthesis.getVoices();
console.debug(voices);
//setVoice();
readConfig();
new MutationObserver(start).observe(document.body, {
// attributes: true,
childList: true,
subtree: true
});
console.debug('MutationObserver running');
}
function setVoice() {
voiceSelect = GM_getValue('voiceSelect', 1000);
console.debug('HearEverything: stored voice = ' + voiceSelect);
var duoState = JSON.parse(localStorage.getItem('duo.state'));
config.lang = duoState.user.learningLanguage;
if(voiceSelect == 1000) {
for (let i = 0; i < voices.length; i++) {
if(voices[i].lang.includes(config.lang)) {
voiceSelect = i;
console.debug('HearEverything: auto set voice');
}
}
}
console.debug(`HearEverything: voice = ${voiceSelect}, learning language = ${config.lang}`);
}
// toggles visibility
function togglePopout(id) {
let popout = document.getElementById(id);
// popout.style.display === "none" ? popout.style.display = "block" : popout.style.display = "none";
if (popout.style.display === 'none') {
popout.style.display = 'block';
document.addEventListener('click', closePopout);
popout.addEventListener('mouseenter', setHover);
popout.addEventListener('mouseleave', removeHover);
} else {
popout.style.display = 'none';
document.removeEventListener('click', closePopout);
popout.removeEventListener('mouseenter', setHover);
popout.removeEventListener('mouseleave', removeHover);
}
}
function setHover() {
hover = true;
// debug('hover = true');
}
function removeHover() {
setTimeout(function() { hover = false; }, '100');
// debug('hover = false');
}
function closePopout() {
// debug('closePopout: hover = ' + hover);
if (!hover) {
hover = true;
togglePopout('hearEverythingConfig');
}
}
function readConfig() {
config.ap_timeout = 1000; // GM_getValue('he_auto_timeout', 1000);
config.he_ct_auto = GM_getValue('he_ct_auto', true);
config.he_cgf_auto = GM_getValue('he_cgf_auto', true);
config.he_cgf_click = GM_getValue('he_cgf_click', true);
config.he_cd_auto = GM_getValue('he_cd_auto', false);
config.he_cd_click = GM_getValue('he_cd_click', true);
config.he_cd_autointro = GM_getValue('he_cd_autointro', true);
config.he_cf_auto = GM_getValue('he_cf_auto', true);
config.he_cf_click = GM_getValue('he_cf_click', true);
config.he_ctc_auto = GM_getValue('he_ctc_auto', true);
config.he_ctc_click = GM_getValue('he_ctc_click', false);
setVoice();
console.debug(config);
}
function addConfig() {
if(!document.querySelector('#hearEverythingGear') && document.querySelector('[role="progressbar"]')) {
let configButton = document.createElement('button');
configButton.setAttribute('id', 'hearEverythingGear');
configButton.setAttribute('class', '_2hiHn _2kfEr _1nlVc _2fOC9 UCrz7 t5wFJ _1DC8p _2jNpf');
configButton.setAttribute('style', `grid-column: 3/3; background-image:url(//d35aaqx5ub95lt.cloudfront.net/images/gear.svg);
background-position: 0px 0px; background-repeat: no-repeat; background-size: contain;`);
let configDiv = document.createElement('div');
configDiv.setAttribute('class','_3yqw1 np6Tv _1Xlh1');
configDiv.setAttribute('style','display: none; position: fixed; margin-top: 1rem;');
configDiv.setAttribute('id','hearEverythingConfig');
let options = '';
for (let i = 0; i < voices.length; i++) {
options += ``;
}
let styleCheckbox = 'style="vertical-align: bottom;"';
let configTranslate = `
`;
let configGapFill = `
`;
let configTapComplete = `
`;
let configForm = `
`;
let configDialogue = `
`;
configDiv.innerHTML = `
${configTranslate}
${configGapFill}
${configTapComplete}
${configForm}
${configDialogue}
`;
document.querySelector('[role="progressbar"]').insertAdjacentElement('afterend',configButton);
configButton.insertAdjacentElement('afterend', configDiv);
configButton.addEventListener('click', function () { togglePopout('hearEverythingConfig'); });
let configLanguage = document.getElementById('configLanguage')
configLanguage.querySelector('[value="' + voiceSelect + '"]').setAttribute('selected', true);
configLanguage.addEventListener('change', function() {
voiceSelect = configLanguage.options[configLanguage.selectedIndex].value;
GM_setValue('voiceSelect', voiceSelect);
setVoice();
});
document.getElementById('he_ct_auto').checked = config.he_ct_auto;
document.getElementById('he_cgf_auto').checked = config.he_cgf_auto;
document.getElementById('he_cgf_click').checked = config.he_cgf_click;
document.getElementById('he_ctc_auto').checked = config.he_ctc_auto;
document.getElementById('he_ctc_click').checked = config.he_ctc_click;
document.getElementById('he_cf_auto').checked = config.he_cf_auto;
document.getElementById('he_cf_click').checked = config.he_cf_click;
document.getElementById('he_cd_auto').checked = config.he_cd_auto;
document.getElementById('he_cd_click').checked = config.he_cd_click;
document.getElementById('he_cd_autointro').checked = config.he_cd_autointro;
document.getElementById('hearEverythingConfig').addEventListener('change', function(e) {
// console.debug(LOG_STRING + 'Target ID = ' + e.target.id);
GM_setValue(e.target.id, e.target.checked);
config[e.target.id] = e.target.checked;
});
}
}
function start() {
if (document.querySelector('[data-test="challenge-header"]')) {
addConfig();
buildDebug();
checkNewPage();
let challenge = getChallengeType();
if(challenge !== null) {
if (newPage === true) {
if (document.querySelector(ANSWER_QS) !== null) {
renderAnswerSpeakButton();
} else if(addedSpeech===false) {
if (document.querySelectorAll(CHALLENGE_JUDGE_QS).length!==0) {
if (challenge[0] === LISTEN_COMPREHENSION) { // || challenge[0] === READ_COMPREHENSION) {
let hint = document.querySelectorAll(HINT_SENTENCE_QS)[1].innerText.replace('...', '');
addSpeech(CHALLENGE_JUDGE_QS, hint);
addedSpeech = true;
}
if (challenge[0] === FORM && config.he_cf_click === true) {
addSpeech(CHALLENGE_JUDGE_QS);
addedSpeech = true;
}
if (challenge[0] === GAP_FILL && config.he_cgf_click === true) {
addSpeech(CHALLENGE_JUDGE_QS);
addedSpeech = true;
}
if (challenge[0] === DIALOGUE && config.he_cd_click === true) {
addSpeech(CHALLENGE_JUDGE_QS);
addedSpeech = true;
}
} else if (document.querySelectorAll(CHALLENGE_TAP_TOKEN_QS).length !== 0) {
if (challenge[0] === TAP_COMPLETE && config.he_ctc_click === true) {
addSpeech(CHALLENGE_TAP_TOKEN_QS);
addedSpeech = true;
}
}
}
renderIntroSpeakButton();
}
} else {
// we detected no content to use, so we are not interested in this page
newPage = false;
}
} // end challenge-header detection
}
function prepareChallengeGapFill() {
let answer;
if (document.querySelector(RIGHT_ANSWER_QS)) {
answer = document.querySelector(RIGHT_OPTION_QS).innerText;
}
if (document.querySelector(WRONG_ANSWER_QS)) {
let answerElement = document.querySelector(ANSWER_CLASS);
if(answerElement.lastElementChild) {
answer = answerElement.lastElementChild.innerText;
} else {
answer = answerElement.innerText;
}
}
// question
let read = document.querySelector(HINT_SENTENCE_QS).parentNode.innerText;
// new type, which has two blanc places
if (answer.includes('...')) {
let answers = answer.split(' ... ');
debug('answer 1 = ' + answers[0]);
debug('answer 2 = ' + answers[1]);
let reads = read.split('\n');
debug('reads = ' + reads);
if (reads.length === 2) {
read = answers[0] + reads[0] + answers[1] + reads[1];
} else {
read = reads[0] + answers[0] + reads[1] + answers[1] + reads[2];
}
} else {
// if the answer is at the start of the sentence, there's no \n
if (read.includes('\n')) {
read = read.replace('\n', answer);
} else {
read = answer + read;
}
}
document.querySelector(HINT_SENTENCE_QS).parentNode.innerHTML = `
${read}`;
return read;
}
function prepareChallengeForm() {
let answer;
if (document.querySelector(RIGHT_ANSWER_QS)) {
answer = document.querySelector(RIGHT_OPTION_QS).innerText;
}
if (document.querySelector(WRONG_ANSWER_QS)) {
let answerElement = document.querySelector(ANSWER_CLASS);
if(answerElement.lastElementChild) {
answer = answerElement.lastElementChild.innerText;
} else {
answer = answerElement.innerText;
}
}
let read = document.querySelector(FORM_PROMPT_QS).getAttribute('data-prompt').replace(/_+/, answer);
document.querySelector(FORM_PROMPT_QS).innerHTML = `
${read}`;
return read;
}
function prepareChallengeName() {
let read;
if (document.querySelector(RIGHT_ANSWER_QS)) {
read = document.querySelector(TEXT_INPUT_QS).value;
}
if (document.querySelector(WRONG_ANSWER_QS)) {
read = document.querySelector(ANSWER_CLASS).innerText;
}
return read;
}
function prepareChallengeTranslate() {
let read;
if (document.querySelector(RIGHT_ANSWER_QS)) {
if (document.querySelector(WORD_BANK_QS)) {
// debug('innerText = ' + document.querySelector(CHALLENGE_TAP_TOKEN_QS).parentNode.parentNode.innerText);
read = document.querySelector(CHALLENGE_TAP_TOKEN_QS).parentNode.parentNode.innerText.replace(/\n/g, ' ');
read = read.replace(/' /g, "'");
} else {
let tI = document.querySelector(TRANSLATE_INPUT_QS);
if (tI.lang === config.lang) read = tI.innerHTML;
}
}
if (document.querySelector(WRONG_ANSWER_QS)) {
let answer = document.querySelector(ANSWER_CLASS);
if(answer.lastElementChild) {
read = answer.lastElementChild.innerText;
} else {
read = answer.innerText;
}
}
if (document.querySelector(SPEAKER_BUTTON_QS)) read = '';
// console.debug('HearEverything: read = ' + read);
return read;
}
function prepareChallengeTapComplete() {
let read;
if (document.querySelector(RIGHT_ANSWER_QS)) {
read = document.querySelector(HINT_SENTENCE_QS).parentNode.innerText.replace(/\n/g, '');
}
if (document.querySelector(WRONG_ANSWER_QS)) {
read = document.querySelector(ANSWER_CLASS).innerText;
}
// console.debug('HearEverything: read = ' + read);
return read;
}
function prepareChallengeDialogue() {
let read;
let speaker1 = document.querySelector('[class="' + DIALOGUE_SPEAKER_CLASS + '"]').innerText;
let speaker2;
if(document.querySelector(WRONG_ANSWER_QS)) {
speaker2 = document.querySelector('._1UqAr._1sqiF').innerText;
} else {
speaker2 = document.querySelector('[aria-checked="true"]').querySelector('[data-test="challenge-judge-text"]').innerText;
}
read = speaker1 + '\n' + speaker2;
return read
}
function introChallengeDialogue() {
let read = document.querySelector(HINT_SENTENCE_QS).parentNode.innerText;
let speaker = document.createElement('div');
speaker.innerHTML = speakerButton;
speaker.children[0].id = SPEAK_INTRO;
speaker.children[0].style = 'width:40px; height:40px; background:transparent; margin-left:-16px; margin-right:0px;padding-bottom:5px';
document.querySelector(HINT_SENTENCE_QS).insertAdjacentElement('beforeBegin', speaker);
return read;
}
function prepareChallengeReadComprehension() {
let read;
let speaker1 = document.querySelector(HINT_SENTENCE_QS).innerText;
let speaker2;
if(document.querySelector(WRONG_ANSWER_QS)) {
speaker2 = document.querySelector(ANSWER_CLASS).innerText;
} else {
speaker2 = document.querySelector(RIGHT_OPTION_QS).innerText;
}
read = speaker1 + '\n' + document.querySelectorAll(HINT_SENTENCE_QS)[1].innerText.replace('...', ' ' +speaker2);
return read
}
function renderIntroSpeakButton() {
if (document.querySelector(SPEAK_INTRO_QS) === null) {
let read = '';
let challenge = getChallengeType()[0];
if (challenge === DIALOGUE) {
read = introChallengeDialogue();
}
if (read !== '') {
debug('intro = ' + read);
let utter = generateUtter(read);
addSpeakListener(SPEAK_INTRO, utter, read);
if (challenge === DIALOGUE && config.he_cd_autointro) document.querySelector(SPEAK_INTRO_QS).click();
}
}
}
function renderAnswerSpeakButton() {
let read = '';
let challenge = getChallengeType()[0];
if (challenge === FORM) {
read = prepareChallengeForm();
}
if (challenge === TRANSLATE) {
read = prepareChallengeTranslate();
}
if (challenge === DIALOGUE) {
read = prepareChallengeDialogue();
}
if (challenge === READ_COMPREHENSION) {
read = prepareChallengeReadComprehension();
}
if (challenge === NAME) {
read = prepareChallengeName();
}
if (challenge === GAP_FILL) {
read = prepareChallengeGapFill();
}
if (challenge === COMPLETE_REVERSE_TRANSLATION) {
read = prepareChallengeTranslate();
}
if (challenge === TAP_COMPLETE) {
read = prepareChallengeTapComplete();
}
console.debug('HearEverything: read = ' + read);
let utter = generateUtter(read);
// add speaker button to answer and fill in the correct answer in the headline
updateText(read);
// if we have added the speaker button, we find it in the document
addSpeakListener('speak', utter, read);
// do it for every page to trigger the Duo speaker button also
document.removeEventListener('keydown', myShortcutListener);
document.addEventListener('keydown', myShortcutListener);
newPage = false;
// console.debug('Now it\'s an old page');
addedSpeech = false;
// console.debug('Reset: speech isn\'t attached to options any more');
if (DEBUG) document.querySelector('#myOptions').innerText = 'disabled';
// if you like autoplay, it waits 1 second an plays it
if (((challenge === TRANSLATE) || (challenge === COMPLETE_REVERSE_TRANSLATION)) && config.he_ct_auto === true) {
timeoutAutoplay(challenge, utter);
}
if (challenge === GAP_FILL && config.he_cgf_auto === true) {
timeoutAutoplay(challenge, utter);
}
if (challenge === TAP_COMPLETE && config.he_ctc_auto === true) {
timeoutAutoplay(challenge, utter);
}
if (challenge === FORM && config.he_cf_auto === true) {
timeoutAutoplay(challenge, utter);
}
if (challenge === DIALOGUE && config.he_cd_auto === true) {
timeoutAutoplay(challenge, utter);
}
}
function timeoutAutoplay(challenge, utter) {
setTimeout(function() {
console.debug(LOG_STRING + 'auto play ' + challenge);
synth.cancel();
synth.speak(utter);
},config.ap_timeout);
}
function addSpeakListener(id, utter, read) {
let speak = document.querySelector('#' + id);
if(speak) {
speak.addEventListener('click',function () { synth.cancel(); synth.speak(utter); });
// console.debug('EventListener bound to speak button');
if (DEBUG) document.querySelector('#mySentence').innerText = read;
document.getElementById(id).title = read;
} else {
console.debug('HearEverything: No speak button found');
}
}
function generateUtter(read) {
let utter = new SpeechSynthesisUtterance(read);
utter.voice = voices[voiceSelect];
utter.volume = 1;
utter.pitch = 1;
utter.rate = 1;
utter.lang = config.lang;
return utter;
}
function myShortcutListener(event) {
let speak = document.querySelector('#speak');
let duoSpeak = document.querySelector(SPEAKER_BUTTON_QS);
// ALT + l combo
if (event.altKey && event.key === 'l') {
if (speak) { speak.click(); }
else if (duoSpeak) duoSpeak.click();
console.debug(LOG_STRING + 'alt = ' + event.altKey + ' + ' + event.key);
}
}
function readTapComplete(tap) {
let read = '';
let words = tap.childNodes;
words.forEach(function(word) {
if (word.nodeName === 'SPAN') read += word.children[0].innerText;
if (word.nodeName === 'DIV') {
read += word.querySelector('[class="_2Z2xv"]').children[0].innerText;
}
});
return read;
}
// gives some debug information directly in the Duo-GUI
function buildDebug() {
if(DEBUG) {
if(!document.querySelector('#myChallenge')) {
let debug = document.createElement('div');
debug.innerHTML = `
Challenge-Name: ${getChallengeType(true)[0]}
Sentence to speak:
Speak options: disabled`;
debug.style = "font-size: small; text-align:left; display:grid;";
document.querySelector('[data-test="challenge-header"]').insertAdjacentElement('afterend', debug);
}
}
}
function checkNewPage() {
if(!document.querySelector('#myNewPage')) {
let nP = document.createElement('div');
nP.id = 'myNewPage';
document.querySelector('[data-test="challenge-header"]').insertAdjacentElement('afterend', nP);
//console.debug('---- div - newPage ----');
console.debug('HearEverything: Challenge Type = ' + getChallengeType(true)[0]);
newPage = true;
synth.cancel();
} else {
//console.debug('---- div - oldPage ----');
}
}
// gets the type of the current challenge
// returns array [type, HTMLElement]
// returns null if no usable type is found
// if returnEverything = true, it returns also noType
function getChallengeType(returnEverything = false) {
let type = null;
let noType = ['Unidentified Page Type'];
for (let i = 0; i < TEST.length; i++) {
if (document.querySelector(`[data-test="${TEST[i]}"]`)) {
type = [TEST[i], document.querySelector(`[data-test="${TEST[i]}"]`)];
}
}
if (document.querySelector(`[data-test="${SELECT_TRANSCRIPTION}"]`)) { noType = ['No usable page type (' + SELECT_TRANSCRIPTION + ')','']; }
if (document.querySelector(`[data-test="${READ_COMPREHENSION}"]`)) { noType = ['No usable page type (' + READ_COMPREHENSION + ')','']; }
if (document.querySelector(`[data-test="${LISTEN}"]`)) { noType = ['No usable page type (' + LISTEN + ')','']; }
if (document.querySelector(`[data-test="${LISTEN_TAP}"]`)) { noType = ['No usable page type (' + LISTEN_TAP + ')','']; }
if (document.querySelector(`[data-test="${LISTEN_COMPREHENSION}"]`)) { noType = ['No usable page type (' + LISTEN_COMPREHENSION + ')','']; }
// type ? console.info('HearEverything: Page Type = ' + type[0]) : console.info('HearEverything: ' + noType[0]);
if(returnEverything) {
return type ? type : noType;
} else {
return type;
}
}
function addSpeech(qs, t = '') {
//console.debug('Add speech to the option buttons:');
if (t !== '') t += ' ';
let options = document.querySelectorAll(qs);
for (let i=0; i