let wordsList = []; let currentWordIndex = 0; let inputHistory = []; let currentInput = ""; let time = 0; let timers = []; let testActive = false; let testStart, testEnd; let wpmHistory = []; let currentCommands = commands; let restartCount = 0; let accuracyStats = { correct: 0, incorrect: 0 } let customText = "The quick brown fox jumps over the lazy dog"; function showNotification(text, time) { let noti = $(".notification"); noti.text(text); noti.css('top', `-${noti.outerHeight()}px`); noti.stop(true, true).animate({ top: "1rem" }, 250, 'swing', () => { noti.stop(true, true).animate({ opacity: 1 }, time, () => { noti.stop(true, true).animate({ top: `-${noti.outerHeight()}px` }, 250, 'swing'); }) }); } function test() { $("#resultScreenshot").removeClass("hidden"); html2canvas($("#resultScreenshot"), { onclone: function(clonedDoc) { clonedDoc.getElementById("resultScreenshot").style.display = "block"; } }).then((canvas) => { $("#resultScreenshot").removeClass("hidden"); document.body.appendChild(canvas); }); } function getReleasesFromGitHub() { $.getJSON("https://api.github.com/repos/Miodec/monkey-type/releases", data => { $('#bottom .version').text(data[0].name).css('opacity', 1); $("#versionHistory .releases").empty(); data.forEach(release => { if (!release.draft && !release.prerelease) { $("#versionHistory .releases").append(`
${release.name}
${moment(release.published_at).format('DD MMM YYYY')}
${release.body.replace(/\r\n/g, '
')}
`); } }) }) } function getLastChar(word) { return word.charAt(word.length - 1); } function setFocus(foc) { if (foc) { // focus = true; $("#top").addClass("focus"); $("#bottom").addClass("focus"); $("body").css("cursor", "none"); } else { startCaretAnimation(); $("#top").removeClass("focus"); $("#bottom").removeClass("focus"); $("body").css("cursor", "default"); } } function capitalizeFirstLetter(str) { return str.charAt(0).toUpperCase() + str.slice(1); } function initWords() { testActive = false; wordsList = []; currentWordIndex = 0; accuracyStats = { correct: 0, incorrect: 0 } inputHistory = []; currentInput = ""; let language = words[config.language]; if (language == undefined || language == []) { config.language = "english"; language = words[config.language]; } if (config.mode == "time" || config.mode == "words") { let wordsBound = config.mode == "time" ? 50 : config.words; let randomWord = language[Math.floor(Math.random() * language.length)]; while (randomWord.indexOf(' ') > -1) { randomWord = language[Math.floor(Math.random() * language.length)]; } wordsList.push(randomWord); for (let i = 1; i < wordsBound; i++) { randomWord = language[Math.floor(Math.random() * language.length)]; previousWord = wordsList[i - 1]; while (randomWord == previousWord || (!config.punctuation && randomWord == "I") || randomWord.indexOf(' ') > -1) { randomWord = language[Math.floor(Math.random() * language.length)]; } wordsList.push(randomWord); } } else if (config.mode == "custom") { let w = customText.split(" "); for (let i = 0; i < w.length; i++) { wordsList.push(w[i]); } } if (config.punctuation && config.mode != "custom") { wordsList = buildSentences(wordsList); } showWords(); } function buildSentences() { let returnList = []; $.each(wordsList, (index, word) => { let previousWord = returnList[index - 1]; if (index == 0 || getLastChar(previousWord) == "." || getLastChar(previousWord) == "?" || getLastChar(previousWord) == "!") { //always capitalise the first word or if there was a dot word = capitalizeFirstLetter(word); } else if ( //10% chance to end a sentence (Math.random() < 0.1 && getLastChar(previousWord) != "." && index != wordsList.length - 2) || index == wordsList.length - 1) { let rand = Math.random(); if (rand <= 0.8) { word += "."; } else if (rand > .8 && rand < .9){ word += "?"; } else { word += "!"; } } else if (Math.random() < 0.01 && getLastChar(previousWord) != "," && getLastChar(previousWord) != ".") { //1% chance to add quotes word = `"${word}"`; } else if (Math.random() < 0.01) { //1% chance to add a colon word = word + ":"; } else if ( Math.random() < 0.01 && getLastChar(previousWord) != "," && getLastChar(previousWord) != "." && previousWord != "-" ) { //1% chance to add a dash word = "-"; } else if ( Math.random() < 0.2 && getLastChar(previousWord) != "," ) { //2% chance to add a comma word += ","; } returnList.push(word); }) return returnList; } function addWord() { let language = words[config.language]; let randomWord = language[Math.floor(Math.random() * language.length)]; while (randomWord.indexOf(' ') > -1) { randomWord = language[Math.floor(Math.random() * language.length)]; } wordsList.push(randomWord); let w = "
"; for (let c = 0; c < randomWord.length; c++) { w += "" + randomWord.charAt(c) + ""; } w += "
"; $("#words").append(w); } function showWords() { $("#words").empty(); if (config.mode == "words" || config.mode == "custom") { $("#words").css("height", "auto"); for (let i = 0; i < wordsList.length; i++) { let w = "
"; for (let c = 0; c < wordsList[i].length; c++) { w += "" + wordsList[i].charAt(c) + ""; } w += "
"; $("#words").append(w); } } else if (config.mode == "time") { for (let i = 0; i < wordsList.length; i++) { let w = "
"; for (let c = 0; c < wordsList[i].length; c++) { w += "" + wordsList[i].charAt(c) + ""; } w += "
"; $("#words").append(w); } $("#words").removeClass('hidden'); const wordHeight = $($(".word")[0]).outerHeight(); $("#words").css("height", wordHeight * 3 + 'px').css("overflow", "hidden"); } updateActiveElement(); updateCaretPosition(); } function updateActiveElement() { $("#words .word").removeClass("active"); $($("#words .word")[currentWordIndex]) .addClass("active") .removeClass("error"); } function compareInput() { $(".word.active").empty(); let ret = ""; let currentWord = wordsList[currentWordIndex]; let letterElems = $($("#words .word")[currentWordIndex]).children("letter"); for (let i = 0; i < currentInput.length; i++) { if (currentWord[i] == currentInput[i]) { ret += '' + currentWord[i] + ""; // $(letterElems[i]).removeClass('incorrect').addClass('correct'); } else { if (currentWord[i] == undefined) { ret += '' + currentInput[i] + ""; // $($('#words .word')[currentWordIndex]).append('' + currentInput[i] + ""); } else { ret += '' + currentWord[i] + ""; // $(letterElems[i]).removeClass('correct').addClass('incorrect'); } } } if (currentInput.length < currentWord.length) { for (let i = currentInput.length; i < currentWord.length; i++) { ret += "" + currentWord[i] + ""; } } $(".word.active").html(ret); if (currentWord == currentInput && currentWordIndex == wordsList.length - 1) { inputHistory.push(currentInput); currentInput = ""; showResult(); } // liveWPM() } function highlightBadWord() { $(".word.active").addClass("error"); } function showTimer() { $("#timerWrapper").css("opacity", 1); } function hideTimer() { $("#timerWrapper").css("opacity", 0); } function updateTimerBar() { let percent = ((time + 1) / config.time) * 100; $("#timer") .stop(true, true) .css("width", percent + "vw"); } function hideCaret() { $("#caret").addClass("hidden"); } function showCaret() { updateCaretPosition(); $("#caret").removeClass("hidden"); startCaretAnimation(); } function stopCaretAnimation() { $("#caret").css("animation-name", "none"); $("#caret").css("background-color", "var(--caret-color)"); } function startCaretAnimation() { $("#caret").css("animation-name", "caretFlash"); } function updateCaretPosition() { if ($("#words").hasClass('hidden')) return; let caret = $("#caret"); let activeWord = $("#words .word.active"); let inputLen = currentInput.length; let currentLetterIndex = inputLen - 1; if (currentLetterIndex == -1) { currentLetterIndex = 0; } let currentLetter = $($("#words .word.active letter")[currentLetterIndex]); let currentLetterPos = currentLetter.position(); let letterHeight = currentLetter.height(); let newTop = 0; let newLeft = 0; newTop = currentLetterPos.top - letterHeight / 4; if (inputLen == 0) { // caret.css({ // top: currentLetterPos.top - letterHeight / 4, // left: currentLetterPos.left - caret.width() / 2 // }); newLeft = currentLetterPos.left - caret.width() / 2; } else { // caret.css({ // top: currentLetterPos.top - letterHeight / 4, // left: currentLetterPos.left + currentLetter.width() - caret.width() / 2 // }); newLeft = currentLetterPos.left + currentLetter.width() - caret.width() / 2; } let duration = 0; // if (config.smoothCaret && Math.round(caret.position().top) == Math.round(newTop)) { // duration = 100; // } if (config.smoothCaret) { duration = 100; } if (Math.round(caret.position().top) != Math.round(newTop)) { caret.css("top", newTop); duration = 10; } caret.stop(true, true).animate({ top: newTop, left: newLeft }, duration) } function countChars() { let correctWordChars = 0; let correctChars = 0; let incorrectChars = 0; let extraChars = 0; let missedChars = 0; for (let i = 0; i < inputHistory.length; i++) { if (inputHistory[i] == wordsList[i]) { //the word is correct //+1 for space correctWordChars += wordsList[i].length + 1; correctChars += wordsList[i].length; } else if (inputHistory[i].length >= wordsList[i].length) { //too many chars for (let c = 0; c < inputHistory[i].length; c++) { if (c < wordsList[i].length) { //on char that still has a word list pair if (inputHistory[i][c] == wordsList[i][c]) { correctChars++; } else { incorrectChars++; } } else { //on char that is extra extraChars++; } } } else { //not enough chars for (let c = 0; c < wordsList[i].length; c++) { if (c < inputHistory[i].length) { //on char that still has a word list pair if (inputHistory[i][c] == wordsList[i][c]) { correctChars++; } else { incorrectChars++; } } else { //on char that is extra missedChars++; } } } } return { correctWordChars: correctWordChars, allCorrectChars: correctChars, incorrectChars: incorrectChars, extraChars: extraChars, missedChars: missedChars } } function calculateStats() { if (config.mode == "words") { if (inputHistory.length != wordsList.length) return; } let chars = countChars(); let totalChars = chars.allCorrectChars + chars.incorrectChars + chars.extraChars + chars.missedChars; let testNow = Date.now(); let testSeconds = (testNow - testStart) / 1000; let wpm = Math.round((chars.correctWordChars * (60 / testSeconds)) / 5); let acc = Math.floor((accuracyStats.correct / (accuracyStats.correct + accuracyStats.incorrect)) * 100); return { wpm: wpm, acc: acc, correctChars: chars.allCorrectChars, incorrectChars: chars.incorrectChars + chars.extraChars + chars.missedChars }; } function hideCrown() { $("#result .stats .wpm .crownWrapper").css('width', 0); } function showCrown() { $("#result .stats .wpm .crownWrapper").animate({ width: '1.7rem' }, 250); } function showResult() { testEnd = Date.now(); let stats = calculateStats(); clearIntervals(); $("#result .stats .wpm .bottom").text(stats.wpm); $("#result .stats .acc .bottom").text(stats.acc + "%"); $("#result .stats .key .bottom").text(stats.correctChars + "/" + stats.incorrectChars); let mode2 = ""; if (config.mode == "time") { mode2 = config.time; } else if (config.mode == "words") { mode2 = config.words; } hideCrown(); let completedEvent = { wpm: stats.wpm, correctChars: stats.correctChars, incorrectChars: stats.incorrectChars, acc: stats.acc, mode: config.mode, mode2: mode2, punctuation: config.punctuation, timestamp: Date.now(), language: config.language, restartCount: restartCount }; console.log(restartCount); restartCount = 0; if (stats.wpm > 0 && stats.wpm < 600 && stats.acc > 50 && stats.acc <= 100) { if (firebase.auth().currentUser != null) { db_getUserHighestWpm(config.mode, mode2).then(data => { // console.log(`highest wpm for this mode is ${data}, current is ${stats.wpm}`); if (data < stats.wpm) { showCrown(); } completedEvent.uid = firebase.auth().currentUser.uid; try{ firebase.analytics().logEvent('testCompleted', completedEvent); }catch(e){ console.log("Analytics unavailable"); } db_testCompleted(completedEvent); dbSnapshot.unshift(completedEvent); }); $("#result .loginTip").addClass('hidden'); } else { try{ firebase.analytics().logEvent('testCompletedNoLogin', completedEvent); }catch(e){ console.log("Analytics unavailable"); } $("#result .loginTip").removeClass('hidden'); // showNotification("Sign in to save your result",3000); } } else { showNotification("Test invalid", 3000); try{ firebase.analytics().logEvent('testCompletedInvalid', completedEvent); }catch(e){ console.log("Analytics unavailable"); } } let infoText = ""; infoText += config.mode; if (config.mode == "time") { infoText += " " + config.time } else if (config.mode == "words") { infoText += " " + config.words } if(config.mode != "custom"){ infoText += "
" + config.language.replace('_', ' '); } if (config.punctuation) { infoText += "
with punctuation" } $("#result .stats .info .bottom").html(infoText); testActive = false; setFocus(false); hideCaret(); hideLiveWpm(); let labels = []; for (let i = 1; i <= wpmHistory.length; i++) { labels.push(i.toString()); } let mainColor = getComputedStyle(document.body).getPropertyValue('--main-color').replace(' ', ''); let subColor = getComputedStyle(document.body).getPropertyValue('--sub-color').replace(' ', ''); wpmOverTimeChart.options.scales.xAxes[0].ticks.minor.fontColor = subColor; wpmOverTimeChart.options.scales.yAxes[0].ticks.minor.fontColor = subColor; wpmOverTimeChart.data.datasets[0].borderColor = mainColor; wpmOverTimeChart.data.labels = labels; wpmOverTimeChart.data.datasets[0].data = wpmHistory; wpmOverTimeChart.update({ duration: 0 }); swapElements($("#words"),$("#result"),250); } function restartTest() { clearIntervals(); time = 0; let fadetime = 125; setFocus(false); hideCaret(); testActive = false; hideLiveWpm(); let el = null; if($("#words").hasClass('hidden')){ //results are being displayed el = $("#result"); }else if($("#result").hasClass('hidden')){ //words are being displayed el = $("#words"); } el.stop(true, true).animate({ opacity: 0 }, 125, () => { initWords(); $("#result").addClass('hidden'); $("#words").css('opacity', 0).removeClass('hidden').stop(true, true).animate({ opacity: 1 }, 125, () => { clearIntervals(); $("#restartTestButton").css('opacity', 1); if ($("#commandLineWrapper").hasClass('hidden')) focusWords(); wpmHistory = []; hideTimer(); setTimeout(function() { $("#timer") .css("transition", "none") .css("width", "0vw") .stop(true, true) .animate({ top: 0 }, 0, () => { $("#timer").css("transition", "1s linear"); }); }, 250); // let oldHeight = $("#words").height(); // let newHeight = $("#words") // .css("height", "fit-content") // .css("height", "-moz-fit-content") // .height(); // if (testMode == "words" || testMode == "custom") { // $("#words") // .stop(true, true) // .css("height", oldHeight) // .animate({ height: newHeight }, 250, () => { // $("#words") // .css("height", "fit-content") // .css("height", "-moz-fit-content"); // $("#wordsInput").focus(); // updateCaretPosition(); // }); // } else if (testMode == "time") { // $("#words") // .stop(true, true) // .css("height", oldHeight) // .animate({ height: 78 }, 250, () => { // $("#wordsInput").focus(); // updateCaretPosition(); // }); // } }); }) } function focusWords() { if (!$("#words").hasClass('hidden')) $("#wordsInput").focus(); } function changeCustomText() { customText = prompt("Custom text"); customText = customText.replace(/[\n\r\t ]/gm, ' '); customText = customText.replace(/ +/gm, ' '); initWords(); } function changeWordCount(wordCount) { changeMode("words"); config.words = parseInt(wordCount); $("#top .config .wordCount .button").removeClass("active"); $("#top .config .wordCount .button[wordCount='" + wordCount + "']").addClass( "active" ); restartTest(); saveConfigToCookie(); } function changeTimeConfig(time) { changeMode("time"); config.time = time; $("#top .config .time .button").removeClass("active"); $("#top .config .time .button[timeConfig='" + time + "']").addClass("active"); restartTest(); saveConfigToCookie(); } function changePage(page) { let activePage = $(".page.active"); $(".page").removeClass('active'); $("#wordsInput").focusout(); if (page == "test" || page == "") { $(".page.pageTest").addClass('active'); swapElements(activePage, $(".page.pageTest"), 250, focusWords); history.pushState('/', null, '/'); showTestConfig(); hideSignOutButton(); restartCount = 0; } else if (page == "about") { $(".page.pageAbout").addClass('active'); swapElements(activePage, $(".page.pageAbout"), 250); history.pushState('about', null, 'about'); hideTestConfig(); hideSignOutButton(); } else if (page == "settings") { updateSettingsPage() $(".page.pageSettings").addClass('active'); swapElements(activePage, $(".page.pageSettings"), 250); history.pushState('settings', null, 'settings'); hideTestConfig(); hideSignOutButton(); } else if (page == "account") { if (!firebase.auth().currentUser) { changePage("login"); } else { $(".page.pageAccount").addClass('active'); swapElements(activePage, $(".page.pageAccount"), 250); refreshAccountPage(); history.pushState('account', null, 'account'); hideTestConfig(); showSignOutButton(); } } else if (page == "login") { if (firebase.auth().currentUser != null) { changePage('account'); } else { $(".page.pageLogin").addClass('active'); swapElements(activePage, $(".page.pageLogin"), 250); history.pushState('login', null, 'login'); hideTestConfig(); hideSignOutButton(); } } } function changeMode(mode) { config.mode = mode; $("#top .config .mode .button").removeClass("active"); $("#top .config .mode .button[mode='" + mode + "']").addClass("active"); if (config.mode == "time") { $("#top .config .wordCount").addClass("hidden"); $("#top .config .time").removeClass("hidden"); $("#top .config .customText").addClass("hidden"); $("#top .config .punctuationMode").removeClass("hidden"); } else if (config.mode == "words") { $("#top .config .wordCount").removeClass("hidden"); $("#top .config .time").addClass("hidden"); $("#top .config .customText").addClass("hidden"); $("#top .config .punctuationMode").removeClass("hidden"); } else if (config.mode == "custom") { $("#top .config .wordCount").addClass("hidden"); $("#top .config .time").addClass("hidden"); $("#top .config .customText").removeClass("hidden"); $("#top .config .punctuationMode").addClass("hidden"); } saveConfigToCookie(); } function liveWPM() { let correctWordChars = 0; for (let i = 0; i < inputHistory.length; i++) { if (inputHistory[i] == wordsList[i]) { //the word is correct //+1 for space correctWordChars += wordsList[i].length + 1; } } let testNow = Date.now(); let testSeconds = (testNow - testStart) / 1000; wpm = (correctWordChars * (60 / testSeconds)) / 5; return Math.round(wpm); } function updateLiveWpm(wpm) { if (!config.showLiveWpm) return; if (wpm == 0 || !testActive) hideLiveWpm(); // let wpmstring = wpm < 100 ? ` ${wpm}` : `${wpm}`; $("#liveWpm").html(wpm); } function showLiveWpm() { if (!config.showLiveWpm) return; if (!testActive) return; $("#liveWpm").css('opacity', 0.25); } function hideLiveWpm() { $("#liveWpm").css('opacity', 0); } function swapElements(el1, el2, totalDuration, callback = function() { return; }) { if ( (el1.hasClass('hidden') && !el2.hasClass('hidden')) || (!el1.hasClass('hidden') && el2.hasClass('hidden')) ) { //one of them is hidden and the other is visible if (el1.hasClass("hidden")) { return false; } $(el1).stop(true, true).removeClass('hidden').css('opacity', 1).animate({ opacity: 0 }, totalDuration / 2, () => { $(el1).addClass('hidden'); $(el2).stop(true, true).removeClass('hidden').css('opacity', 0).animate({ opacity: 1 }, totalDuration / 2, () => { callback(); }); }); } else if (el1.hasClass('hidden') && el2.hasClass('hidden')) { //both are hidden, only fade in the second $(el2).stop(true, true).removeClass('hidden').css('opacity', 0).animate({ opacity: 1 }, totalDuration, () => { callback(); }); } } function clearIntervals() { timers.forEach(timer => { clearInterval(timer); }) } function updateAccountLoginButton() { if (firebase.auth().currentUser != null) { swapElements($("#menu .button.login"), $("#menu .button.account"), 250); // $("#menu .button.account").removeClass('hidden'); // $("#menu .button.login").addClass('hidden'); } else { swapElements($("#menu .button.login"), $("#menu .button.account"), 250); // $("#menu .button.login").removeClass('hidden'); // $("#menu .button.account").addClass('hidden'); } } $(document).on("click", "#top .logo", (e) => { changePage('test'); }); $(document).on("click", "#top .config .wordCount .button", (e) => { wrd = e.currentTarget.innerHTML; changeWordCount(wrd); }); $(document).on("click", "#top .config .time .button", (e) => { time = e.currentTarget.innerHTML; changeTimeConfig(time); }); $(document).on("click", "#top .config .customText .button", (e) => { changeCustomText(); }); $(document).on("click", "#top .config .punctuationMode .button", (e) => { togglePunctuation(); restartTest(); }); $("#words").click((e) => { focusWords(); }); $(document).on("click", "#top .config .mode .button", (e) => { if ($(e.currentTarget).hasClass("active")) return; mode = e.currentTarget.innerHTML; changeMode(mode); restartTest(); }); $(document).on("click", "#top #menu .button", (e) => { href = $(e.currentTarget).attr('href'); changePage(href.replace('/', '')); }) $(window).on('popstate', (e) => { let state = e.originalEvent.state; if (state == "" || state == "/") { // show test changePage('test') } else if (state == "about") { // show about changePage("about"); } else if (state == "account" || state == "login") { if (firebase.auth().currentUser) { changePage("account"); } else { changePage('login'); } } }); $(document).on("keypress", "#restartTestButton", (event) => { if (event.keyCode == 32 || event.keyCode == 13) { if (testActive) { restartCount++; } restartTest(); } }); $(document.body).on("click", "#restartTestButton", (event) => { restartTest(); }); $(document.body).on("click", ".version", (event) => { $("#versionHistoryWrapper").css('opacity', 0).removeClass('hidden').animate({ opacity: 1 }, 125); }); $(document.body).on("click", "#versionHistoryWrapper", (event) => { $("#versionHistoryWrapper").css('opacity', 1).animate({ opacity: 0 }, 125, () => { $("#versionHistoryWrapper").addClass('hidden'); }); }); $("#wordsInput").keypress((event) => { event.preventDefault(); }); $("#wordsInput").on("focus", (event) => { showCaret(); }); $("#wordsInput").on("focusout", (event) => { hideCaret(); }); $(window).resize(() => { updateCaretPosition(); }); $(document).mousemove(function(event) { setFocus(false); }); //keypresses for the test, using different method to be more responsive $(document).keypress(function(event) { if (!$("#wordsInput").is(":focus")) return; if (event["keyCode"] == 13) return; if (event["keyCode"] == 32) return; if (event["keyCode"] == 27) return; //start the test if (currentInput == "" && inputHistory.length == 0) { try{ if (firebase.auth().currentUser != null) { firebase.analytics().logEvent('testStarted'); } else { firebase.analytics().logEvent('testStartedNoLogin'); } }catch(e){ console.log("Analytics unavailable"); } testActive = true; stopCaretAnimation(); testStart = Date.now(); if (config.mode == "time") { showTimer(); } updateTimerBar(); clearIntervals(); timers.push(setInterval(function() { time++; updateTimerBar(); let wpm = liveWPM(); updateLiveWpm(wpm); showLiveWpm(); wpmHistory.push(wpm); if (config.mode == "time") { if (time >= config.time) { clearIntervals(); hideCaret(); testActive = false; showResult(); } } }, 1000)); } else { if (!testActive) return; } if (wordsList[currentWordIndex].substring(currentInput.length, currentInput.length + 1) != event["key"]) { accuracyStats.incorrect++; } else { accuracyStats.correct++; } currentInput += event["key"]; setFocus(true); compareInput(); updateCaretPosition(); }); //handle keyboard events $(document).keydown((event) => { //tab if (event["keyCode"] == 9) { if (config.quickTab && $(".pageTest").hasClass("active")) { event.preventDefault(); if (testActive) { restartCount++; } restartTest(); } } //only for the typing test if ($("#wordsInput").is(":focus")) { //backspace if (event["keyCode"] == 8) { event.preventDefault(); if (!testActive) return; if (currentInput == "" && inputHistory.length > 0) { if ( inputHistory[currentWordIndex - 1] == wordsList[currentWordIndex - 1] || $($(".word")[currentWordIndex - 1]).hasClass("hidden") ) { return; } else { if (event["ctrlKey"] || event["altKey"]) { currentInput = ""; inputHistory.pop(); } else { currentInput = inputHistory.pop(); } currentWordIndex--; updateActiveElement(); compareInput(); } } else { // if ($($(".word")[currentWordIndex - 1]).hasClass("hidden")) { // return; // } if (event["ctrlKey"]) { currentInput = ""; } else { currentInput = currentInput.substring(0, currentInput.length - 1); } compareInput(); } updateCaretPosition(); } //space if (event["keyCode"] == 32) { if (!testActive) return; event.preventDefault(); if (currentInput == "") return; let currentWord = wordsList[currentWordIndex]; if (config.mode == "time") { let currentTop = $($("#words .word")[currentWordIndex]).position().top; let nextTop = $($("#words .word")[currentWordIndex + 1]).position().top; if (nextTop > currentTop) { //last word of the line for (let i = 0; i < currentWordIndex + 1; i++) { $($("#words .word")[i]).addClass("hidden"); // addWordLine(); } } } if (currentWord == currentInput) { inputHistory.push(currentInput); currentInput = ""; currentWordIndex++; updateActiveElement(); updateCaretPosition(); } else { inputHistory.push(currentInput); highlightBadWord(); currentInput = ""; currentWordIndex++; if (currentWordIndex == wordsList.length) { showResult(); return; } updateActiveElement(); updateCaretPosition(); } if (config.mode == "time") { addWord(); } } } }); loadConfigFromCookie(); getReleasesFromGitHub(); if (firebase.app().options.projectId === "monkey-type-dev-67af4") { $("#top .logo .bottom").text("monkey-dev"); $("head title").text("Monkey Dev") } if (window.location.hostname === "localhost") { $("#top .logo .top").text("localhost"); $("head title").text($("head title").text() + " (localhost)"); } $(document).ready(() => { updateFavicon(32,14); $('body').css('transition', '.25s'); restartTest(); if (config.quickTab) { $("#restartTestButton").addClass('hidden'); } $("#centerContent").css("opacity", "0").removeClass("hidden").stop(true, true).animate({ opacity: 1 }, 250); }); let ctx = $("#wpmChart"); let wpmOverTimeChart = new Chart(ctx, { type: 'line', data: { labels: [], datasets: [{ label: "wpm", data: [], // backgroundColor: 'rgba(255, 255, 255, 0.25)', borderColor: 'rgba(125, 125, 125, 1)', borderWidth: 2 }], }, options: { tooltips: { titleFontFamily: "Roboto Mono", bodyFontFamily: "Roboto Mono" }, legend: { display: false, labels: { defaultFontFamily: "Roboto Mono" } }, responsive: true, maintainAspectRatio: false, tooltips: { mode: 'index', intersect: false, }, hover: { mode: 'nearest', intersect: true }, scales: { xAxes: [{ ticks: { fontFamily: "Roboto Mono" }, display: true, scaleLabel: { display: false, labelString: 'Seconds' } }], yAxes: [{ display: true, scaleLabel: { display: false, labelString: 'Words per Minute' }, ticks: { fontFamily: 'Roboto Mono', beginAtZero: true } }] } } });