diff --git a/frontend/src/js/controllers/chart-controller.js b/frontend/src/js/controllers/chart-controller.js index 66806f202..df0f599f0 100644 --- a/frontend/src/js/controllers/chart-controller.js +++ b/frontend/src/js/controllers/chart-controller.js @@ -1,5 +1,5 @@ import Chart from "chart.js"; -import * as TestStats from "../test/test-stats"; +import * as TestInput from "./../test/test-input"; import * as ThemeColors from "../elements/theme-colors"; import * as Misc from "../misc"; import Config, * as UpdateConfig from "../config"; @@ -61,7 +61,7 @@ export let result = new Chart($("#wpmChart"), { $(".wordInputAfter").remove(); let wordsToHighlight = - TestStats.keypressPerSecond[parseInt(ti.xLabel) - 1].words; + TestInput.keypressPerSecond[parseInt(ti.xLabel) - 1].words; let unique = [...new Set(wordsToHighlight)]; unique.forEach((wordIndex) => { diff --git a/frontend/src/js/controllers/input-controller.js b/frontend/src/js/controllers/input-controller.js index 1357fa7e6..aaa914d81 100644 --- a/frontend/src/js/controllers/input-controller.js +++ b/frontend/src/js/controllers/input-controller.js @@ -27,6 +27,8 @@ import * as WeakSpot from "../test/weak-spot"; import * as Leaderboards from "../elements/leaderboards"; import * as ActivePage from "./../states/active-page"; import * as TestActive from "./../states/test-active"; +import * as TestInput from "./../test/test-input"; +import * as TestWords from "./../test/test-words"; let dontInsertSpace = false; let correctShiftUsed = true; @@ -47,9 +49,9 @@ function updateUI() { if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( - TestLogic.words + TestWords.words .getCurrent() - .charAt(TestLogic.input.current.length) + .charAt(TestInput.input.current.length) .toString() .toUpperCase() ); @@ -60,16 +62,16 @@ function backspaceToPrevious() { if (!TestActive.get()) return; if ( - TestLogic.input.history.length == 0 || + TestInput.input.history.length == 0 || TestUI.currentWordElementIndex == 0 ) return; if ( - (TestLogic.input.history[TestLogic.words.currentIndex - 1] == - TestLogic.words.get(TestLogic.words.currentIndex - 1) && + (TestInput.input.history[TestWords.words.currentIndex - 1] == + TestWords.words.get(TestWords.words.currentIndex - 1) && !Config.freedomMode) || - $($(".word")[TestLogic.words.currentIndex - 1]).hasClass("hidden") + $($(".word")[TestWords.words.currentIndex - 1]).hasClass("hidden") ) { return; } @@ -78,15 +80,15 @@ function backspaceToPrevious() { return; } - TestLogic.input.current = TestLogic.input.popHistory(); - TestLogic.corrected.popHistory(); + TestInput.input.current = TestInput.input.popHistory(); + TestInput.corrected.popHistory(); if (Config.funbox === "nospace" || Config.funbox === "arrows") { - TestLogic.input.current = TestLogic.input.current.slice(0, -1); + TestInput.input.current = TestInput.input.current.slice(0, -1); } - TestLogic.words.decreaseCurrentIndex(); + TestWords.words.decreaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1); TestUI.updateActiveElement(true); - Funbox.toggleScript(TestLogic.words.getCurrent()); + Funbox.toggleScript(TestWords.words.getCurrent()); TestUI.updateWordElement(); Caret.updatePosition(); @@ -96,23 +98,23 @@ function backspaceToPrevious() { function handleSpace() { if (!TestActive.get()) return; - if (TestLogic.input.current === "") return; + if (TestInput.input.current === "") return; if (Config.mode == "zen") { $("#words .word.active").removeClass("active"); $("#words").append("
"); } - let currentWord = TestLogic.words.getCurrent(); + let currentWord = TestWords.words.getCurrent(); if (Config.funbox === "layoutfluid" && Config.mode !== "time") { // here I need to check if Config.customLayoutFluid exists because of my scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function const layouts = Config.customLayoutfluid ? Config.customLayoutfluid.split("#") : ["qwerty", "dvorak", "colemak"]; let index = 0; - let outof = TestLogic.words.length; + let outof = TestWords.words.length; index = Math.floor( - (TestLogic.input.history.length + 1) / (outof / layouts.length) + (TestInput.input.history.length + 1) / (outof / layouts.length) ); if (Config.layout !== layouts[index] && layouts[index] !== undefined) { Notifications.add(`--- !!! ${layouts[index]} !!! ---`, 0); @@ -120,9 +122,9 @@ function handleSpace() { UpdateConfig.setLayout(layouts[index]); UpdateConfig.setKeymapLayout(layouts[index]); Keymap.highlightKey( - TestLogic.words + TestWords.words .getCurrent() - .charAt(TestLogic.input.current.length) + .charAt(TestInput.input.current.length) .toString() .toUpperCase() ); @@ -136,19 +138,19 @@ function handleSpace() { //correct word or in zen mode const isWordCorrect = - currentWord == TestLogic.input.current || Config.mode == "zen"; + currentWord == TestInput.input.current || Config.mode == "zen"; MonkeyPower.addPower(isWordCorrect, true); - TestStats.incrementAccuracy(isWordCorrect); + TestInput.incrementAccuracy(isWordCorrect); if (isWordCorrect) { PaceCaret.handleSpace(true, currentWord); - TestLogic.input.pushHistory(); - TestLogic.words.increaseCurrentIndex(); + TestInput.input.pushHistory(); + TestWords.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); - Funbox.toggleScript(TestLogic.words.getCurrent()); + Funbox.toggleScript(TestWords.words.getCurrent()); Caret.updatePosition(); - TestStats.incrementKeypressCount(); - TestStats.pushKeypressWord(TestLogic.words.currentIndex); + TestInput.incrementKeypressCount(); + TestInput.pushKeypressWord(TestWords.words.currentIndex); if (Config.funbox !== "nospace" && Config.funbox !== "arrows") { Sound.playClick(Config.playSoundOnClick); } @@ -161,17 +163,17 @@ function handleSpace() { Sound.playError(Config.playSoundOnError); } } - TestStats.pushMissedWord(TestLogic.words.getCurrent()); - TestStats.incrementKeypressErrors(); - let cil = TestLogic.input.current.length; - if (cil <= TestLogic.words.getCurrent().length) { - if (cil >= TestLogic.corrected.current.length) { - TestLogic.corrected.current += "_"; + TestInput.pushMissedWord(TestWords.words.getCurrent()); + TestInput.incrementKeypressErrors(); + let cil = TestInput.input.current.length; + if (cil <= TestWords.words.getCurrent().length) { + if (cil >= TestInput.corrected.current.length) { + TestInput.corrected.current += "_"; } else { - TestLogic.corrected.current = - TestLogic.corrected.current.substring(0, cil) + + TestInput.corrected.current = + TestInput.corrected.current.substring(0, cil) + "_" + - TestLogic.corrected.current.substring(cil + 1); + TestInput.corrected.current.substring(cil + 1); } } if (Config.stopOnError != "off") { @@ -190,20 +192,20 @@ function handleSpace() { } PaceCaret.handleSpace(false, currentWord); if (Config.blindMode) $("#words .word.active letter").addClass("correct"); - TestLogic.input.pushHistory(); + TestInput.input.pushHistory(); TestUI.highlightBadWord(TestUI.currentWordElementIndex, !Config.blindMode); - TestLogic.words.increaseCurrentIndex(); + TestWords.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); - Funbox.toggleScript(TestLogic.words.getCurrent()); + Funbox.toggleScript(TestWords.words.getCurrent()); Caret.updatePosition(); - TestStats.incrementKeypressCount(); - TestStats.pushKeypressWord(TestLogic.words.currentIndex); - TestStats.updateLastKeypress(); + TestInput.incrementKeypressCount(); + TestInput.pushKeypressWord(TestWords.words.currentIndex); + TestInput.updateLastKeypress(); if (Config.difficulty == "expert" || Config.difficulty == "master") { TestLogic.fail("difficulty"); return; - } else if (TestLogic.words.currentIndex == TestLogic.words.length) { + } else if (TestWords.words.currentIndex == TestWords.words.length) { //submitted last word that is incorrect TestLogic.finish(); return; @@ -213,9 +215,9 @@ function handleSpace() { let wordLength; if (Config.mode === "zen") { - wordLength = TestLogic.input.current.length; + wordLength = TestInput.input.current.length; } else { - wordLength = TestLogic.words.getCurrent().length; + wordLength = TestWords.words.getCurrent().length; } let flex = Misc.whorf(Config.minBurstCustomSpeed, wordLength); @@ -227,7 +229,7 @@ function handleSpace() { return; } - TestLogic.corrected.pushHistory(); + TestInput.corrected.pushHistory(); if ( !Config.showAllLines || @@ -284,7 +286,7 @@ function isCharCorrect(char, charIndex) { return true; } - const originalChar = TestLogic.words.getCurrent()[charIndex]; + const originalChar = TestWords.words.getCurrent()[charIndex]; if (originalChar == char) { return true; @@ -389,7 +391,7 @@ function handleChar(char, charIndex) { if ( Config.mode !== "zen" && - TestLogic.words.getCurrent()[charIndex] !== "\n" && + TestWords.words.getCurrent()[charIndex] !== "\n" && char === "\n" ) { return; @@ -406,40 +408,40 @@ function handleChar(char, charIndex) { let thisCharCorrect = isCharCorrect(char, charIndex); if (thisCharCorrect && Config.mode !== "zen") { - char = TestLogic.words.getCurrent().charAt(charIndex); + char = TestWords.words.getCurrent().charAt(charIndex); } if (!thisCharCorrect && char === "\n") { - if (TestLogic.input.current === "") return; + if (TestInput.input.current === "") return; char = " "; } - if (TestLogic.input.current === "") { - TestStats.setBurstStart(performance.now()); + if (TestInput.input.current === "") { + TestInput.setBurstStart(performance.now()); } const resultingWord = - TestLogic.input.current.substring(0, charIndex) + + TestInput.input.current.substring(0, charIndex) + char + - TestLogic.input.current.substring(charIndex + 1); + TestInput.input.current.substring(charIndex + 1); if (!thisCharCorrect && Misc.trailingComposeChars.test(resultingWord)) { - TestLogic.input.current = resultingWord; + TestInput.input.current = resultingWord; TestUI.updateWordElement(); Caret.updatePosition(); return; } MonkeyPower.addPower(thisCharCorrect); - TestStats.incrementAccuracy(thisCharCorrect); + TestInput.incrementAccuracy(thisCharCorrect); if (!thisCharCorrect) { - TestStats.incrementKeypressErrors(); - TestStats.pushMissedWord(TestLogic.words.getCurrent()); + TestInput.incrementKeypressErrors(); + TestInput.pushMissedWord(TestWords.words.getCurrent()); } WeakSpot.updateScore( - Config.mode === "zen" ? char : TestLogic.words.getCurrent()[charIndex], + Config.mode === "zen" ? char : TestWords.words.getCurrent()[charIndex], thisCharCorrect ); @@ -456,22 +458,22 @@ function handleChar(char, charIndex) { if (!correctShiftUsed && Config.difficulty != "master") return; //update current corrected version. if its empty then add the current char. if its not then replace the last character with the currently pressed one / add it - if (TestLogic.corrected.current === "") { - TestLogic.corrected.current += resultingWord; + if (TestInput.corrected.current === "") { + TestInput.corrected.current += resultingWord; } else { - if (charIndex >= TestLogic.corrected.current.length) { - TestLogic.corrected.current += char; + if (charIndex >= TestInput.corrected.current.length) { + TestInput.corrected.current += char; } else if (!thisCharCorrect) { - TestLogic.corrected.current = - TestLogic.corrected.current.substring(0, charIndex) + + TestInput.corrected.current = + TestInput.corrected.current.substring(0, charIndex) + char + - TestLogic.corrected.current.substring(charIndex + 1); + TestInput.corrected.current.substring(charIndex + 1); } } - TestStats.incrementKeypressCount(); - TestStats.updateLastKeypress(); - TestStats.pushKeypressWord(TestLogic.words.currentIndex); + TestInput.incrementKeypressCount(); + TestInput.updateLastKeypress(); + TestInput.pushKeypressWord(TestWords.words.currentIndex); if (Config.stopOnError == "letter" && !thisCharCorrect) { return; @@ -484,8 +486,8 @@ function handleChar(char, charIndex) { //update the active word top, but only once if ( - TestLogic.input.current.length === 1 && - TestLogic.words.currentIndex === 0 + TestInput.input.current.length === 1 && + TestWords.words.currentIndex === 0 ) { TestUI.setActiveWordTop(document.querySelector("#words .active").offsetTop); } @@ -494,14 +496,14 @@ function handleChar(char, charIndex) { if ( (Config.mode === "zen" && charIndex < 30) || (Config.mode !== "zen" && - charIndex < TestLogic.words.getCurrent().length + 20) + charIndex < TestWords.words.getCurrent().length + 20) ) { - TestLogic.input.current = resultingWord; + TestInput.input.current = resultingWord; } if (!thisCharCorrect && Config.difficulty == "master") { - TestLogic.input.pushHistory(); - TestLogic.corrected.pushHistory(); + TestInput.input.pushHistory(); + TestInput.corrected.pushHistory(); TestLogic.fail("difficulty"); return; } @@ -514,17 +516,17 @@ function handleChar(char, charIndex) { if (Config.mode != "zen") { //not applicable to zen mode //auto stop the test if the last word is correct - let currentWord = TestLogic.words.getCurrent(); - let lastindex = TestLogic.words.currentIndex; + let currentWord = TestWords.words.getCurrent(); + let lastindex = TestWords.words.currentIndex; if ( - (currentWord == TestLogic.input.current || + (currentWord == TestInput.input.current || (Config.quickEnd && - currentWord.length == TestLogic.input.current.length && + currentWord.length == TestInput.input.current.length && Config.stopOnError == "off")) && - lastindex == TestLogic.words.length - 1 + lastindex == TestWords.words.length - 1 ) { - TestLogic.input.pushHistory(); - TestLogic.corrected.pushHistory(); + TestInput.input.pushHistory(); + TestInput.corrected.pushHistory(); TestLogic.finish(); return; } @@ -540,7 +542,7 @@ function handleChar(char, charIndex) { if ( activeWordTopBeforeJump < newActiveTop && !TestUI.lineTransition && - TestLogic.input.current.length > 1 + TestInput.input.current.length > 1 ) { if (Config.mode == "zen") { let currentTop = Math.floor( @@ -550,7 +552,7 @@ function handleChar(char, charIndex) { ); if (!Config.showAllLines) TestUI.lineJump(currentTop); } else { - TestLogic.input.current = TestLogic.input.current.slice(0, -1); + TestInput.input.current = TestInput.input.current.slice(0, -1); TestUI.updateWordElement(); } } @@ -559,7 +561,7 @@ function handleChar(char, charIndex) { //simulate space press in nospace funbox if ( ((Config.funbox === "nospace" || Config.funbox === "arrows") && - TestLogic.input.current.length === TestLogic.words.getCurrent().length) || + TestInput.input.current.length === TestWords.words.getCurrent().length) || (char === "\n" && thisCharCorrect) ) { handleSpace(); @@ -613,7 +615,7 @@ function handleTab(event) { TestUI.resultVisible || !( (Config.mode == "zen" && !event.shiftKey) || - (TestLogic.hasTab && !event.shiftKey) + (TestWords.hasTab && !event.shiftKey) ) ) { if (event.shiftKey) { @@ -633,21 +635,21 @@ function handleTab(event) { } } else { event.preventDefault(); - handleChar("\t", TestLogic.input.current.length); - setWordsInput(" " + TestLogic.input.current); + handleChar("\t", TestInput.input.current.length); + setWordsInput(" " + TestInput.input.current); } } else if (!TestUI.resultVisible) { if ( - (TestLogic.hasTab && event.shiftKey) || - (!TestLogic.hasTab && Config.mode !== "zen") || + (TestWords.hasTab && event.shiftKey) || + (!TestWords.hasTab && Config.mode !== "zen") || (Config.mode === "zen" && event.shiftKey) ) { event.preventDefault(); $("#restartTestButton").focus(); } else { event.preventDefault(); - handleChar("\t", TestLogic.input.current.length); - setWordsInput(" " + TestLogic.input.current); + handleChar("\t", TestInput.input.current.length); + setWordsInput(" " + TestInput.input.current); } } } else if (Config.quickTab) { @@ -706,17 +708,17 @@ $(document).keydown((event) => { return; } - if (TestStats.spacingDebug) + if (TestInput.spacingDebug) console.log( "spacing debug", "keypress", event.key, "length", - TestStats.keypressTimings.spacing.array.length + TestInput.keypressTimings.spacing.array.length ); - TestStats.recordKeypressSpacing(); - TestStats.setKeypressDuration(performance.now()); - TestStats.setKeypressNotAfk(); + TestInput.recordKeypressSpacing(); + TestInput.setKeypressDuration(performance.now()); + TestInput.setKeypressNotAfk(); //blocking firefox from going back in history with backspace if (event.key === "Backspace") { @@ -743,10 +745,10 @@ $(document).keydown((event) => { Monkey.type(); - if (event.key === "Backspace" && TestLogic.input.current.length === 0) { + if (event.key === "Backspace" && TestInput.input.current.length === 0) { backspaceToPrevious(); - if (TestLogic.input.current) - setWordsInput(" " + TestLogic.input.current + " "); + if (TestInput.input.current) + setWordsInput(" " + TestInput.input.current + " "); } if (event.key === "Enter") { @@ -760,20 +762,20 @@ $(document).keydown((event) => { TestLogic.setBailout(true); TestLogic.finish(); } else { - handleChar("\n", TestLogic.input.current.length); - setWordsInput(" " + TestLogic.input.current); + handleChar("\n", TestInput.input.current.length); + setWordsInput(" " + TestInput.input.current); } } //show dead keys if ( event.key === "Dead" && - !Misc.trailingComposeChars.test(TestLogic.input.current) + !Misc.trailingComposeChars.test(TestInput.input.current) ) { Sound.playClick(Config.playSoundOnClick); $( document.querySelector("#words .word.active").querySelectorAll("letter")[ - TestLogic.input.current.length + TestInput.input.current.length ] ).toggleClass("dead"); } @@ -789,9 +791,9 @@ $(document).keydown((event) => { if (char === "ArrowDown") char = "s"; if (char === "ArrowUp") char = "w"; event.preventDefault(); - handleChar(char, TestLogic.input.current.length); + handleChar(char, TestInput.input.current.length); updateUI(); - setWordsInput(" " + TestLogic.input.current); + setWordsInput(" " + TestInput.input.current); } } else if ( Config.layout !== "default" && @@ -803,9 +805,9 @@ $(document).keydown((event) => { const char = LayoutEmulator.getCharFromEvent(event); if (char !== null) { event.preventDefault(); - handleChar(char, TestLogic.input.current.length); + handleChar(char, TestInput.input.current.length); updateUI(); - setWordsInput(" " + TestLogic.input.current); + setWordsInput(" " + TestInput.input.current); } } }); @@ -818,11 +820,11 @@ $("#wordsInput").keyup((event) => { if (TestUI.resultVisible) return; let now = performance.now(); - if (TestStats.keypressTimings.duration.current !== -1) { - let diff = Math.abs(TestStats.keypressTimings.duration.current - now); - TestStats.pushKeypressDuration(diff); + if (TestInput.keypressTimings.duration.current !== -1) { + let diff = Math.abs(TestInput.keypressTimings.duration.current - now); + TestInput.pushKeypressDuration(diff); } - TestStats.setKeypressDuration(now); + TestInput.setKeypressDuration(now); Monkey.stop(); }); @@ -839,7 +841,7 @@ $("#wordsInput").on("input", (event) => { return; } - TestStats.setKeypressNotAfk(); + TestInput.setKeypressNotAfk(); const realInputValue = event.target.value.normalize(); const inputValue = realInputValue.slice(1); @@ -849,25 +851,25 @@ $("#wordsInput").on("input", (event) => { // the effects of that and takes the input out of compose mode. if ( Config.layout !== "default" && - inputValue.length >= TestLogic.input.current.length + inputValue.length >= TestInput.input.current.length ) { - setWordsInput(" " + TestLogic.input.current); + setWordsInput(" " + TestInput.input.current); return; } - if (realInputValue.length === 0 && TestLogic.input.current.length === 0) { + if (realInputValue.length === 0 && TestInput.input.current.length === 0) { // fallback for when no Backspace keydown event (mobile) backspaceToPrevious(); - } else if (inputValue.length < TestLogic.input.current.length) { - TestLogic.input.current = inputValue; + } else if (inputValue.length < TestInput.input.current.length) { + TestInput.input.current = inputValue; TestUI.updateWordElement(); Caret.updatePosition(); - if (!Misc.trailingComposeChars.test(TestLogic.input.current)) { - Replay.addReplayEvent("setLetterIndex", TestLogic.input.current.length); + if (!Misc.trailingComposeChars.test(TestInput.input.current)) { + Replay.addReplayEvent("setLetterIndex", TestInput.input.current.length); } - } else if (inputValue !== TestLogic.input.current) { + } else if (inputValue !== TestInput.input.current) { let diffStart = 0; - while (inputValue[diffStart] === TestLogic.input.current[diffStart]) + while (inputValue[diffStart] === TestInput.input.current[diffStart]) diffStart++; for (let i = diffStart; i < inputValue.length; i++) { @@ -875,7 +877,7 @@ $("#wordsInput").on("input", (event) => { } } - setWordsInput(" " + TestLogic.input.current); + setWordsInput(" " + TestInput.input.current); updateUI(); // force caret at end of input diff --git a/frontend/src/js/index.js b/frontend/src/js/index.js index c985c125d..0ff56d274 100644 --- a/frontend/src/js/index.js +++ b/frontend/src/js/index.js @@ -27,6 +27,7 @@ import * as TestStats from "./test/test-stats"; import * as Replay from "./test/replay"; import * as TestTimer from "./test/test-timer"; import * as Result from "./test/result"; +import * as TestInput from "./test/test-input"; //try to keep this list short because we need to eliminate it eventually global.getuid = Misc.getuid; @@ -48,4 +49,4 @@ global.getTimerStats = TestTimer.getTimerStats; global.toggleUnsmoothedRaw = Result.toggleUnsmoothedRaw; -global.enableSpacingDebug = TestStats.enableSpacingDebug; +global.enableSpacingDebug = TestInput.enableSpacingDebug; diff --git a/frontend/src/js/test/caret.js b/frontend/src/js/test/caret.js index 04cd65a19..6184074c4 100644 --- a/frontend/src/js/test/caret.js +++ b/frontend/src/js/test/caret.js @@ -1,6 +1,6 @@ import * as Misc from "../misc"; import Config from "../config"; -import * as TestLogic from "./test-logic"; +import * as TestInput from "./test-input"; import * as SlowTimer from "../states/slow-timer"; import * as TestActive from "./../states/test-active"; @@ -37,9 +37,9 @@ export async function updatePosition() { let caret = $("#caret"); - let inputLen = TestLogic.input.current.length; - inputLen = Misc.trailingComposeChars.test(TestLogic.input.current) - ? TestLogic.input.current.search(Misc.trailingComposeChars) + 1 + let inputLen = TestInput.input.current.length; + inputLen = Misc.trailingComposeChars.test(TestInput.input.current) + ? TestInput.input.current.search(Misc.trailingComposeChars) + 1 : inputLen; let currentLetterIndex = inputLen - 1; if (currentLetterIndex == -1) { diff --git a/frontend/src/js/test/funbox.js b/frontend/src/js/test/funbox.js index d98d00efc..edc898049 100644 --- a/frontend/src/js/test/funbox.js +++ b/frontend/src/js/test/funbox.js @@ -1,4 +1,5 @@ import * as TestLogic from "./test-logic"; +import * as TestWords from "./test-words"; import * as Notifications from "../elements/notifications"; import * as TestUI from "./test-ui"; import * as Misc from "../misc"; @@ -60,7 +61,7 @@ function updateMemoryTimer(sec) { export function startMemoryTimer() { resetMemoryTimer(); - memoryTimer = Math.round(Math.pow(TestLogic.words.length, 1.2)); + memoryTimer = Math.round(Math.pow(TestWords.words.length, 1.2)); updateMemoryTimer(memoryTimer); showMemoryTimer(); memoryInterval = setInterval(() => { diff --git a/frontend/src/js/test/pace-caret.js b/frontend/src/js/test/pace-caret.js index aeb19b2ce..51ed6ce69 100644 --- a/frontend/src/js/test/pace-caret.js +++ b/frontend/src/js/test/pace-caret.js @@ -1,4 +1,5 @@ import * as TestLogic from "./test-logic"; +import * as TestWords from "./test-words"; import * as TestUI from "./test-ui"; import Config, * as UpdateConfig from "../config"; import * as DB from "../db"; @@ -34,7 +35,7 @@ function resetCaretPosition() { export async function init() { $("#paceCaret").addClass("hidden"); - let mode2 = Misc.getMode2(Config, TestLogic.randomQuote); + let mode2 = Misc.getMode2(Config, TestWords.randomQuote); let wpm; if (Config.paceCaret === "pb") { wpm = await DB.getLocalPB( @@ -47,7 +48,7 @@ export async function init() { Config.funbox ); } else if (Config.paceCaret === "average") { - let mode2 = Misc.getMode2(Config, TestLogic.randomQuote); + let mode2 = Misc.getMode2(Config, TestWords.randomQuote); wpm = await DB.getUserAverageWpm10( Config.mode, mode2, @@ -97,7 +98,7 @@ export function update(expectedStepEnd) { settings.currentLetterIndex++; if ( settings.currentLetterIndex >= - TestLogic.words.get(settings.currentWordIndex).length + TestWords.words.get(settings.currentWordIndex).length ) { //go to the next word settings.currentLetterIndex = -1; @@ -110,7 +111,7 @@ export function update(expectedStepEnd) { if (settings.currentLetterIndex <= -2) { //go to the previous word settings.currentLetterIndex = - TestLogic.words.get(settings.currentWordIndex - 1).length - 1; + TestWords.words.get(settings.currentWordIndex - 1).length - 1; settings.currentWordIndex--; } settings.correction++; @@ -120,7 +121,7 @@ export function update(expectedStepEnd) { settings.currentLetterIndex++; if ( settings.currentLetterIndex >= - TestLogic.words.get(settings.currentWordIndex).length + TestWords.words.get(settings.currentWordIndex).length ) { //go to the next word settings.currentLetterIndex = -1; @@ -145,7 +146,7 @@ export function update(expectedStepEnd) { try { let newIndex = settings.currentWordIndex - - (TestLogic.words.currentIndex - TestUI.currentWordElementIndex); + (TestWords.words.currentIndex - TestUI.currentWordElementIndex); let word = document.querySelectorAll("#words .word")[newIndex]; if (settings.currentLetterIndex === -1) { currentLetter = word.querySelectorAll("letter")[0]; @@ -217,19 +218,19 @@ export function handleSpace(correct, currentWord) { if (correct) { if ( settings !== null && - settings.wordsStatus[TestLogic.words.currentIndex] === true && + settings.wordsStatus[TestWords.words.currentIndex] === true && !Config.blindMode ) { - settings.wordsStatus[TestLogic.words.currentIndex] = undefined; + settings.wordsStatus[TestWords.words.currentIndex] = undefined; settings.correction -= currentWord.length + 1; } } else { if ( settings !== null && - settings.wordsStatus[TestLogic.words.currentIndex] === undefined && + settings.wordsStatus[TestWords.words.currentIndex] === undefined && !Config.blindMode ) { - settings.wordsStatus[TestLogic.words.currentIndex] = true; + settings.wordsStatus[TestWords.words.currentIndex] = true; settings.correction += currentWord.length + 1; } } diff --git a/frontend/src/js/test/practise-words.js b/frontend/src/js/test/practise-words.js index cd835b5a6..80d60d0cc 100644 --- a/frontend/src/js/test/practise-words.js +++ b/frontend/src/js/test/practise-words.js @@ -1,8 +1,10 @@ import * as TestStats from "./test-stats"; +import * as TestWords from "./test-words"; import * as Notifications from "../elements/notifications"; import Config, * as UpdateConfig from "../config"; import * as CustomText from "./custom-text"; import * as TestLogic from "./test-logic"; +import * as TestInput from "./test-input"; export let before = { mode: null, @@ -21,8 +23,8 @@ export function init(missed, slow) { let sortableMissedWords = []; if (missed) { - Object.keys(TestStats.missedWords).forEach((missedWord) => { - sortableMissedWords.push([missedWord, TestStats.missedWords[missedWord]]); + Object.keys(TestInput.missedWords).forEach((missedWord) => { + sortableMissedWords.push([missedWord, TestInput.missedWords[missedWord]]); }); sortableMissedWords.sort((a, b) => { return b[1] - a[1]; @@ -37,7 +39,7 @@ export function init(missed, slow) { let sortableSlowWords = []; if (slow) { - sortableSlowWords = TestLogic.words.get().map(function (e, i) { + sortableSlowWords = TestWords.words.get().map(function (e, i) { return [e, TestStats.burstHistory[i]]; }); sortableSlowWords.sort((a, b) => { @@ -45,7 +47,7 @@ export function init(missed, slow) { }); sortableSlowWords = sortableSlowWords.slice( 0, - Math.min(limit, Math.round(TestLogic.words.length * 0.2)) + Math.min(limit, Math.round(TestWords.words.length * 0.2)) ); } diff --git a/frontend/src/js/test/test-input.js b/frontend/src/js/test/test-input.js new file mode 100644 index 000000000..d751d9cec --- /dev/null +++ b/frontend/src/js/test/test-input.js @@ -0,0 +1,275 @@ +class Input { + constructor() { + this.current = ""; + this.history = []; + this.length = 0; + } + + reset() { + this.current = ""; + this.history = []; + this.length = 0; + } + + resetHistory() { + this.history = []; + this.length = 0; + } + + setCurrent(val) { + this.current = val; + this.length = this.current.length; + } + + appendCurrent(val) { + this.current += val; + this.length = this.current.length; + } + + resetCurrent() { + this.current = ""; + } + + getCurrent() { + return this.current; + } + + pushHistory() { + this.history.push(this.current); + this.historyLength = this.history.length; + this.resetCurrent(); + } + + popHistory() { + return this.history.pop(); + } + + getHistory(i) { + if (i === undefined) { + return this.history; + } else { + return this.history[i]; + } + } + + getHistoryLast() { + return this.history[this.history.length - 1]; + } +} + +class Corrected { + constructor() { + this.current = ""; + this.history = []; + } + setCurrent(val) { + this.current = val; + } + + appendCurrent(val) { + this.current += val; + } + + resetCurrent() { + this.current = ""; + } + + resetHistory() { + this.history = []; + } + + reset() { + this.resetCurrent(); + this.resetHistory(); + } + + getHistory(i) { + return this.history[i]; + } + + popHistory() { + return this.history.pop(); + } + + pushHistory() { + this.history.push(this.current); + this.current = ""; + } +} + +export let input = new Input(); +export let corrected = new Corrected(); + +export let keypressPerSecond = []; +export let currentKeypress = { + count: 0, + errors: 0, + words: [], + afk: true, +}; +export let lastKeypress; +export let currentBurstStart = 0; +export let missedWords = {}; +export let accuracy = { + correct: 0, + incorrect: 0, +}; +export let keypressTimings = { + spacing: { + current: -1, + array: [], + }, + duration: { + current: -1, + array: [], + }, +}; + +export let spacingDebug = false; +export function enableSpacingDebug() { + spacingDebug = true; + console.clear(); +} + +export function updateLastKeypress() { + lastKeypress = performance.now(); +} + +export function incrementKeypressCount() { + currentKeypress.count++; +} + +export function setKeypressNotAfk() { + currentKeypress.afk = false; +} + +export function incrementKeypressErrors() { + currentKeypress.errors++; +} + +export function pushKeypressWord(word) { + currentKeypress.words.push(word); +} + +export function setBurstStart(time) { + currentBurstStart = time; +} + +export function pushKeypressesToHistory() { + keypressPerSecond.push(currentKeypress); + currentKeypress = { + count: 0, + errors: 0, + words: [], + afk: true, + }; +} + +export function incrementAccuracy(correctincorrect) { + if (correctincorrect) { + accuracy.correct++; + } else { + accuracy.incorrect++; + } +} + +export function setKeypressTimingsTooLong() { + keypressTimings.spacing.array = "toolong"; + keypressTimings.duration.array = "toolong"; +} + +export function pushKeypressDuration(val) { + keypressTimings.duration.array.push(val); +} + +export function setKeypressDuration(val) { + keypressTimings.duration.current = val; +} + +function pushKeypressSpacing(val) { + keypressTimings.spacing.array.push(val); +} + +function setKeypressSpacing(val) { + keypressTimings.spacing.current = val; +} + +export function recordKeypressSpacing() { + let now = performance.now(); + let diff = Math.abs(keypressTimings.spacing.current - now); + if (keypressTimings.spacing.current !== -1) { + pushKeypressSpacing(diff); + if (spacingDebug) + console.log( + "spacing debug", + "push", + diff, + "length", + keypressTimings.spacing.array.length + ); + } + setKeypressSpacing(now); + if (spacingDebug) + console.log( + "spacing debug", + "set", + now, + "length", + keypressTimings.spacing.array.length + ); + if (spacingDebug) + console.log( + "spacing debug", + "recorded", + "length", + keypressTimings.spacing.array.length + ); +} + +export function resetKeypressTimings() { + keypressTimings = { + spacing: { + current: performance.now(), + array: [], + }, + duration: { + current: performance.now(), + array: [], + }, + }; + if (spacingDebug) console.clear(); +} + +export function pushMissedWord(word) { + if (!Object.keys(missedWords).includes(word)) { + missedWords[word] = 1; + } else { + missedWords[word]++; + } +} + +export function restart() { + keypressPerSecond = []; + currentKeypress = { + count: 0, + errors: 0, + words: [], + afk: true, + }; + currentBurstStart = 0; + missedWords = {}; + accuracy = { + correct: 0, + incorrect: 0, + }; + keypressTimings = { + spacing: { + current: -1, + array: [], + }, + duration: { + current: -1, + array: [], + }, + }; +} diff --git a/frontend/src/js/test/test-logic.js b/frontend/src/js/test/test-logic.js index 4e7551c65..964234524 100644 --- a/frontend/src/js/test/test-logic.js +++ b/frontend/src/js/test/test-logic.js @@ -40,6 +40,8 @@ import * as Result from "./result"; import * as MonkeyPower from "./../elements/monkey-power"; import * as ActivePage from "../states/active-page"; import * as TestActive from "./../states/test-active"; +import * as TestInput from "./test-input"; +import * as TestWords from "./test-words"; const objecthash = require("node-object-hash")().hash; @@ -67,169 +69,9 @@ export function setNotSignedInUid(uid) { notSignedInLastResult.hash = objecthash(notSignedInLastResult); } -class Words { - constructor() { - this.list = []; - this.length = 0; - this.currentIndex = 0; - } - get(i, raw = false) { - if (i === undefined) { - return this.list; - } else { - if (raw) { - return this.list[i]?.replace(/[.?!":\-,]/g, "")?.toLowerCase(); - } else { - return this.list[i]; - } - } - } - getCurrent() { - return this.list[this.currentIndex]; - } - getLast() { - return this.list[this.list.length - 1]; - } - push(word) { - this.list.push(word); - this.length = this.list.length; - } - reset() { - this.list = []; - this.currentIndex = 0; - this.length = this.list.length; - } - resetCurrentIndex() { - this.currentIndex = 0; - } - decreaseCurrentIndex() { - this.currentIndex--; - } - increaseCurrentIndex() { - this.currentIndex++; - } - clean() { - for (let s of this.list) { - if (/ +/.test(s)) { - let id = this.list.indexOf(s); - let tempList = s.split(" "); - this.list.splice(id, 1); - for (let i = 0; i < tempList.length; i++) { - this.list.splice(id + i, 0, tempList[i]); - } - } - } - } -} - -class Input { - constructor() { - this.current = ""; - this.history = []; - this.length = 0; - } - - reset() { - this.current = ""; - this.history = []; - this.length = 0; - } - - resetHistory() { - this.history = []; - this.length = 0; - } - - setCurrent(val) { - this.current = val; - this.length = this.current.length; - } - - appendCurrent(val) { - this.current += val; - this.length = this.current.length; - } - - resetCurrent() { - this.current = ""; - } - - getCurrent() { - return this.current; - } - - pushHistory() { - this.history.push(this.current); - this.historyLength = this.history.length; - this.resetCurrent(); - } - - popHistory() { - return this.history.pop(); - } - - getHistory(i) { - if (i === undefined) { - return this.history; - } else { - return this.history[i]; - } - } - - getHistoryLast() { - return this.history[this.history.length - 1]; - } -} - -class Corrected { - constructor() { - this.current = ""; - this.history = []; - } - setCurrent(val) { - this.current = val; - } - - appendCurrent(val) { - this.current += val; - } - - resetCurrent() { - this.current = ""; - } - - resetHistory() { - this.history = []; - } - - reset() { - this.resetCurrent(); - this.resetHistory(); - } - - getHistory(i) { - return this.history[i]; - } - - popHistory() { - return this.history.pop(); - } - - pushHistory() { - this.history.push(this.current); - this.current = ""; - } -} - -export let words = new Words(); -export let input = new Input(); -export let corrected = new Corrected(); -export let currentWordIndex = 0; export let isRepeated = false; export let isPaceRepeat = false; export let lastTestWpm = 0; -export let hasTab = false; -export let randomQuote = null; export let bailout = false; export function setRepeated(tf) { @@ -240,18 +82,10 @@ export function setPaceRepeat(tf) { isPaceRepeat = tf; } -export function setHasTab(tf) { - hasTab = tf; -} - export function setBailout(tf) { bailout = tf; } -export function setRandomQuote(rq) { - randomQuote = rq; -} - let spanishSentenceTracker = ""; export function punctuateWord(previousWord, currentWord, index, maxindex) { let word = currentWord; @@ -430,8 +264,8 @@ export function startTest() { } TestActive.set(true); Replay.startReplayRecording(); - Replay.replayGetWordsList(words.list); - TestStats.resetKeypressTimings(); + Replay.replayGetWordsList(TestWords.words.list); + TestInput.resetKeypressTimings(); TimerProgress.restart(); TimerProgress.show(); $("#liveWpm").text("0"); @@ -470,7 +304,7 @@ export function restart( } if (ActivePage.get() == "pageTest" && !TestUI.resultVisible) { if (!ManualRestart.get()) { - if (hasTab) { + if (TestWords.hasTab) { try { if (!event.shiftKey) return; } catch {} @@ -498,7 +332,7 @@ export function restart( } } if (TestActive.get()) { - TestStats.pushKeypressesToHistory(); + TestInput.pushKeypressesToHistory(); let testSeconds = TestStats.calculateTestSeconds(performance.now()); let afkseconds = TestStats.calculateAfkSeconds(testSeconds); // incompleteTestSeconds += ; @@ -544,7 +378,8 @@ export function restart( ManualRestart.reset(); TestTimer.clear(); TestStats.restart(); - corrected.reset(); + TestInput.restart(); + TestInput.corrected.reset(); ShiftTracker.reset(); Caret.hide(); TestActive.set(false); @@ -625,7 +460,7 @@ export function restart( if (!withSameWordset && !shouldQuoteRepeat) { setRepeated(false); setPaceRepeat(repeatWithPace); - setHasTab(false); + TestWords.setHasTab(false); await init(); PaceCaret.init(nosave); } else { @@ -633,8 +468,8 @@ export function restart( setPaceRepeat(repeatWithPace); TestActive.set(false); Replay.stopReplayRecording(); - words.resetCurrentIndex(); - input.reset(); + TestWords.words.resetCurrentIndex(); + TestInput.input.reset(); if (Config.funbox === "plus_one" || Config.funbox === "plus_two") { Notifications.add( "Sorry, this funbox won't work with repeated tests.", @@ -670,7 +505,7 @@ export function restart( } } - let mode2 = Misc.getMode2(Config, randomQuote); + let mode2 = Misc.getMode2(Config, TestWords.randomQuote); let fbtext = ""; if (Config.funbox !== "none") { fbtext = " " + Config.funbox; @@ -694,9 +529,12 @@ export function restart( true ); Keymap.highlightKey( - words + TestWords.words .getCurrent() - .substring(input.current.length, input.current.length + 1) + .substring( + TestInput.input.current.length, + TestInput.input.current.length + 1 + ) .toString() .toUpperCase() ); @@ -779,16 +617,16 @@ function applyLazyModeToWord(word, language) { async function getNextWord(wordset, language, wordsBound) { let randomWord = wordset.randomWord(); - const previousWord = words.get(words.length - 1, true); - const previousWord2 = words.get(words.length - 2, true); + const previousWord = TestWords.words.get(TestWords.words.length - 1, true); + const previousWord2 = TestWords.words.get(TestWords.words.length - 2, true); if (Config.mode === "quote") { - randomWord = randomQuote.textSplit[words.length]; + randomWord = TestWords.randomQuote.textSplit[TestWords.words.length]; } else if ( Config.mode == "custom" && !CustomText.isWordRandom && !CustomText.isTimeRandom ) { - randomWord = CustomText.text[words.length]; + randomWord = CustomText.text[TestWords.words.length]; } else if ( Config.mode == "custom" && (CustomText.isWordRandom || CustomText.isTimeRandom) && @@ -820,9 +658,9 @@ async function getNextWord(wordset, language, wordsBound) { if (Config.punctuation) { randomWord = punctuateWord( - words.get(words.length - 1), + TestWords.words.get(TestWords.words.length - 1), randomWord, - words.length, + TestWords.words.length, wordsBound ); } @@ -839,15 +677,15 @@ export async function init() { TestActive.set(false); MonkeyPower.reset(); Replay.stopReplayRecording(); - words.reset(); + TestWords.words.reset(); TestUI.setCurrentWordElementIndex(0); // accuracy = { // correct: 0, // incorrect: 0, // }; - input.resetHistory(); - input.resetCurrent(); + TestInput.input.resetHistory(); + TestInput.input.resetCurrent(); let language = await Misc.getLanguage(Config.language); if (language && language.name !== Config.language) { @@ -962,7 +800,7 @@ export async function init() { break; } wordCount++; - words.push(word); + TestWords.words.push(word); } } } else { @@ -970,18 +808,18 @@ export async function init() { let randomWord = await getNextWord(wordset, language, wordsBound); if (/\t/g.test(randomWord)) { - setHasTab(true); + TestWords.setHasTab(true); } if (/ +/.test(randomWord)) { let randomList = randomWord.split(" "); let id = 0; while (id < randomList.length) { - words.push(randomList[id]); + TestWords.words.push(randomList[id]); id++; if ( - words.length == wordsBound && + TestWords.words.length == wordsBound && Config.mode == "custom" && CustomText.isWordRandom ) { @@ -995,10 +833,10 @@ export async function init() { ) { // } else { - i = words.length - 1; + i = TestWords.words.length - 1; } } else { - words.push(randomWord); + TestWords.words.push(randomWord); } } } @@ -1045,7 +883,7 @@ export async function init() { quotes.groups[groupIndex][ Math.floor(Math.random() * quotes.groups[groupIndex].length) ]; - if (randomQuote != null && rq.id === randomQuote.id) { + if (TestWords.randomQuote != null && rq.id === TestWords.randomQuote.id) { rq = quotes.groups[groupIndex][ Math.floor(Math.random() * quotes.groups[groupIndex].length) @@ -1076,9 +914,9 @@ export async function init() { rq.textSplit = rq.text.split(" "); rq.language = Config.language.replace(/_\d*k$/g, ""); - setRandomQuote(rq); + TestWords.setRandomQuote(rq); - let w = randomQuote.textSplit; + let w = TestWords.randomQuote.textSplit; if (Config.showAllLines) { wordsBound = w.length; @@ -1088,14 +926,14 @@ export async function init() { for (let i = 0; i < wordsBound; i++) { if (/\t/g.test(w[i])) { - setHasTab(true); + TestWords.setHasTab(true); } w[i] = applyLazyModeToWord(w[i], language); w[i] = await applyBritishEnglishToWord(w[i]); w[i] = applyFunboxesToWord(w[i]); - words.push(w[i]); + TestWords.words.push(w[i]); } } //handle right-to-left languages @@ -1131,23 +969,29 @@ export function calculateWpmAndRaw() { let correctWordChars = 0; let spaces = 0; //check input history - for (let i = 0; i < input.history.length; i++) { - let word = Config.mode == "zen" ? input.getHistory(i) : words.get(i); - if (input.getHistory(i) == word) { + for (let i = 0; i < TestInput.input.history.length; i++) { + let word = + Config.mode == "zen" + ? TestInput.input.getHistory(i) + : TestWords.words.get(i); + if (TestInput.input.getHistory(i) == word) { //the word is correct //+1 for space correctWordChars += word.length; if ( - i < input.history.length - 1 && - Misc.getLastChar(input.getHistory(i)) !== "\n" + i < TestInput.input.history.length - 1 && + Misc.getLastChar(TestInput.input.getHistory(i)) !== "\n" ) { spaces++; } } - chars += input.getHistory(i).length; + chars += TestInput.input.getHistory(i).length; } - if (input.current !== "") { - let word = Config.mode == "zen" ? input.current : words.getCurrent(); + if (TestInput.input.current !== "") { + let word = + Config.mode == "zen" + ? TestInput.input.current + : TestWords.words.getCurrent(); //check whats currently typed let toAdd = { correct: 0, @@ -1155,9 +999,9 @@ export function calculateWpmAndRaw() { missed: 0, }; for (let c = 0; c < word.length; c++) { - if (c < input.current.length) { + if (c < TestInput.input.current.length) { //on char that still has a word list pair - if (input.current[c] == word[c]) { + if (TestInput.input.current[c] == word[c]) { toAdd.correct++; } else { toAdd.incorrect++; @@ -1178,7 +1022,7 @@ export function calculateWpmAndRaw() { if (Config.funbox === "nospace" || Config.funbox === "arrows") { spaces = 0; } - chars += input.current.length; + chars += TestInput.input.current.length; let testSeconds = TestStats.calculateTestSeconds(performance.now()); let wpm = Math.round(((correctWordChars + spaces) * (60 / testSeconds)) / 5); let raw = Math.round(((chars + spaces) * (60 / testSeconds)) / 5); @@ -1191,7 +1035,10 @@ export function calculateWpmAndRaw() { export async function addWord() { let bound = 100; if (Config.funbox === "wikipedia" || Config.funbox == "poetry") { - if (Config.mode == "time" && words.length - words.currentIndex < 20) { + if ( + Config.mode == "time" && + TestWords.words.length - TestWords.words.currentIndex < 20 + ) { let section = Config.funbox == "wikipedia" ? await Wikipedia.getSection(Config.language) @@ -1202,7 +1049,7 @@ export async function addWord() { break; } wordCount++; - words.push(word); + TestWords.words.push(word); TestUI.addWord(word); } } else { @@ -1213,19 +1060,20 @@ export async function addWord() { if (Config.funbox === "plus_one") bound = 1; if (Config.funbox === "plus_two") bound = 2; if ( - words.length - input.history.length > bound || + TestWords.words.length - TestInput.input.history.length > bound || (Config.mode === "words" && - words.length >= Config.words && + TestWords.words.length >= Config.words && Config.words > 0) || (Config.mode === "custom" && CustomText.isWordRandom && - words.length >= CustomText.word && + TestWords.words.length >= CustomText.word && CustomText.word != 0) || (Config.mode === "custom" && !CustomText.isWordRandom && !CustomText.isTimeRandom && - words.length >= CustomText.text.length) || - (Config.mode === "quote" && words.length >= randomQuote.textSplit.length) + TestWords.words.length >= CustomText.text.length) || + (Config.mode === "quote" && + TestWords.words.length >= TestWords.randomQuote.textSplit.length) ) return; const language = @@ -1244,11 +1092,11 @@ export async function addWord() { let split = randomWord.split(" "); if (split.length > 1) { split.forEach((word) => { - words.push(word); + TestWords.words.push(word); TestUI.addWord(word); }); } else { - words.push(randomWord); + TestWords.words.push(randomWord); TestUI.addWord(randomWord); } } @@ -1364,8 +1212,8 @@ function buildCompletedEvent(difficultyFailed) { difficulty: Config.difficulty, blindMode: Config.blindMode, tags: undefined, - keySpacing: TestStats.keypressTimings.spacing.array, - keyDuration: TestStats.keypressTimings.duration.array, + keySpacing: TestInput.keypressTimings.spacing.array, + keyDuration: TestInput.keypressTimings.duration.array, consistency: undefined, keyConsistency: undefined, funbox: Config.funbox, @@ -1401,17 +1249,17 @@ function buildCompletedEvent(difficultyFailed) { let wpmAndRaw = calculateWpmAndRaw(); TestStats.pushToWpmHistory(wpmAndRaw.wpm); TestStats.pushToRawHistory(wpmAndRaw.raw); - TestStats.pushKeypressesToHistory(); + TestInput.pushKeypressesToHistory(); } //consistency - let rawPerSecond = TestStats.keypressPerSecond.map((f) => + let rawPerSecond = TestInput.keypressPerSecond.map((f) => Math.round((f.count / 5) * 60) ); let stddev = Misc.stdDev(rawPerSecond); let avg = Misc.mean(rawPerSecond); let consistency = Misc.roundTo2(Misc.kogasa(stddev / avg)); - let keyconsistencyarray = TestStats.keypressTimings.spacing.array.slice(); + let keyconsistencyarray = TestInput.keypressTimings.spacing.array.slice(); keyconsistencyarray = keyconsistencyarray.splice( 0, keyconsistencyarray.length - 1 @@ -1448,16 +1296,16 @@ function buildCompletedEvent(difficultyFailed) { ); completedEvent.chartData.err = []; - for (let i = 0; i < TestStats.keypressPerSecond.length; i++) { - completedEvent.chartData.err.push(TestStats.keypressPerSecond[i].errors); + for (let i = 0; i < TestInput.keypressPerSecond.length; i++) { + completedEvent.chartData.err.push(TestInput.keypressPerSecond[i].errors); } if (Config.mode === "quote") { - completedEvent.quoteLength = randomQuote.group; + completedEvent.quoteLength = TestWords.randomQuote.group; completedEvent.lang = Config.language.replace(/_\d*k$/g, ""); } - completedEvent.mode2 = Misc.getMode2(Config, randomQuote); + completedEvent.mode2 = Misc.getMode2(Config, TestWords.randomQuote); if (Config.mode === "custom") { completedEvent.customText = {}; @@ -1494,13 +1342,13 @@ function buildCompletedEvent(difficultyFailed) { export async function finish(difficultyFailed = false) { if (!TestActive.get()) return; - if (Config.mode == "zen" && input.current.length != 0) { - input.pushHistory(); - corrected.pushHistory(); - Replay.replayGetWordsList(input.history); + if (Config.mode == "zen" && TestInput.input.current.length != 0) { + TestInput.input.pushHistory(); + TestInput.corrected.pushHistory(); + Replay.replayGetWordsList(TestInput.input.history); } - TestStats.recordKeypressSpacing(); //this is needed in case there is afk time at the end - to make sure test duration makes sense + TestInput.recordKeypressSpacing(); //this is needed in case there is afk time at the end - to make sure test duration makes sense TestUI.setResultCalculating(true); TestUI.setResultVisible(true); @@ -1519,7 +1367,7 @@ export async function finish(difficultyFailed = false) { Funbox.activate("none", null); //need one more calculation for the last word if test auto ended - if (TestStats.burstHistory.length !== input.getHistory().length) { + if (TestStats.burstHistory.length !== TestInput.input.getHistory().length) { let burst = TestStats.calculateBurst(); TestStats.pushBurstToHistory(burst); } @@ -1536,7 +1384,7 @@ export async function finish(difficultyFailed = false) { ///////// completed event ready //afk check - let kps = TestStats.keypressPerSecond.slice(-5); + let kps = TestInput.keypressPerSecond.slice(-5); let afkDetected = kps.every((second) => second.afk); if (bailout) afkDetected = false; @@ -1626,7 +1474,7 @@ export async function finish(difficultyFailed = false) { afkDetected, isRepeated, tooShort, - randomQuote, + TestWords.randomQuote, dontSave ); @@ -1636,7 +1484,7 @@ export async function finish(difficultyFailed = false) { completedEvent.chartData = "toolong"; completedEvent.keySpacing = "toolong"; completedEvent.keyDuration = "toolong"; - TestStats.setKeypressTimingsTooLong(); + TestInput.setKeypressTimingsTooLong(); } if (dontSave) { @@ -1659,7 +1507,7 @@ export async function finish(difficultyFailed = false) { } completedEvent.uid = firebase.auth().currentUser.uid; - Result.updateRateQuote(randomQuote); + Result.updateRateQuote(TestWords.randomQuote); Result.updateGraphPBLine(); @@ -1737,7 +1585,7 @@ export function fail(reason) { failReason = reason; // input.pushHistory(); // corrected.pushHistory(); - TestStats.pushKeypressesToHistory(); + TestInput.pushKeypressesToHistory(); finish(true); let testSeconds = TestStats.calculateTestSeconds(performance.now()); let afkseconds = TestStats.calculateAfkSeconds(testSeconds); diff --git a/frontend/src/js/test/test-stats.js b/frontend/src/js/test/test-stats.js index bc260f8cb..1fbeedecd 100644 --- a/frontend/src/js/test/test-stats.js +++ b/frontend/src/js/test/test-stats.js @@ -1,6 +1,8 @@ import * as TestLogic from "./test-logic"; import Config from "../config"; import * as Misc from "../misc"; +import * as TestInput from "./test-input"; +import * as TestWords from "./test-words"; export let invalid = false; export let start, end; @@ -9,43 +11,7 @@ export let wpmHistory = []; export let rawHistory = []; export let burstHistory = []; -export let keypressPerSecond = []; -export let currentKeypress = { - count: 0, - errors: 0, - words: [], - afk: true, -}; -export let lastKeypress; -export let currentBurstStart = 0; - -// export let errorsPerSecond = []; -// export let currentError = { -// count: 0, -// words: [], -// }; export let lastSecondNotRound = false; -export let missedWords = {}; -export let accuracy = { - correct: 0, - incorrect: 0, -}; -export let keypressTimings = { - spacing: { - current: -1, - array: [], - }, - duration: { - current: -1, - array: [], - }, -}; - -export let spacingDebug = false; -export function enableSpacingDebug() { - spacingDebug = true; - console.clear(); -} export function getStats() { let ret = { @@ -54,23 +20,23 @@ export function getStats() { wpmHistory, rawHistory, burstHistory, - keypressPerSecond, - currentKeypress, - lastKeypress, - currentBurstStart, + keypressPerSecond: TestInput.keypressPerSecond, + currentKeypress: TestInput.currentKeypress, + lastKeypress: TestInput.lastKeypress, + currentBurstStart: TestInput.currentBurstStart, lastSecondNotRound, - missedWords, - accuracy, - keypressTimings, + missedWords: TestInput.missedWords, + accuracy: TestInput.accuracy, + keypressTimings: TestInput.keypressTimings, }; try { ret.keySpacingStats = { average: - keypressTimings.spacing.array.reduce( + TestInput.keypressTimings.spacing.array.reduce( (previous, current) => (current += previous) - ) / keypressTimings.spacing.array.length, - sd: Misc.stdDev(keypressTimings.spacing.array), + ) / TestInput.keypressTimings.spacing.array.length, + sd: Misc.stdDev(TestInput.keypressTimings.spacing.array), }; } catch (e) { // @@ -78,10 +44,10 @@ export function getStats() { try { ret.keyDurationStats = { average: - keypressTimings.duration.array.reduce( + TestInput.keypressTimings.duration.array.reduce( (previous, current) => (current += previous) - ) / keypressTimings.duration.array.length, - sd: Misc.stdDev(keypressTimings.duration.array), + ) / TestInput.keypressTimings.duration.array.length, + sd: Misc.stdDev(TestInput.keypressTimings.duration.array), }; } catch (e) { // @@ -97,35 +63,7 @@ export function restart() { wpmHistory = []; rawHistory = []; burstHistory = []; - keypressPerSecond = []; - currentKeypress = { - count: 0, - errors: 0, - words: [], - afk: true, - }; - currentBurstStart = 0; - // errorsPerSecond = []; - // currentError = { - // count: 0, - // words: [], - // }; lastSecondNotRound = false; - missedWords = {}; - accuracy = { - correct: 0, - incorrect: 0, - }; - keypressTimings = { - spacing: { - current: -1, - array: [], - }, - duration: { - current: -1, - array: [], - }, - }; } export let restartCount = 0; @@ -150,9 +88,9 @@ export function setInvalid() { export function calculateTestSeconds(now) { if (now === undefined) { - let endAfkSeconds = (end - lastKeypress) / 1000; + let endAfkSeconds = (end - TestInput.lastKeypress) / 1000; if ((Config.mode == "zen" || TestLogic.bailout) && endAfkSeconds < 7) { - return (lastKeypress - start) / 1000; + return (TestInput.lastKeypress - start) / 1000; } else { return (end - start) / 1000; } @@ -171,10 +109,6 @@ export function setStart(s) { start2 = Date.now(); } -export function updateLastKeypress() { - lastKeypress = performance.now(); -} - export function pushToWpmHistory(word) { wpmHistory.push(word); } @@ -183,39 +117,13 @@ export function pushToRawHistory(word) { rawHistory.push(word); } -export function incrementKeypressCount() { - currentKeypress.count++; -} - -export function setKeypressNotAfk() { - currentKeypress.afk = false; -} - -export function incrementKeypressErrors() { - currentKeypress.errors++; -} - -export function pushKeypressWord(word) { - currentKeypress.words.push(word); -} - -export function pushKeypressesToHistory() { - keypressPerSecond.push(currentKeypress); - currentKeypress = { - count: 0, - errors: 0, - words: [], - afk: true, - }; -} - export function calculateAfkSeconds(testSeconds) { let extraAfk = 0; if (testSeconds !== undefined) { if (Config.mode === "time") { - extraAfk = Math.round(testSeconds) - keypressPerSecond.length; + extraAfk = Math.round(testSeconds) - TestInput.keypressPerSecond.length; } else { - extraAfk = Math.ceil(testSeconds) - keypressPerSecond.length; + extraAfk = Math.ceil(testSeconds) - TestInput.keypressPerSecond.length; } if (extraAfk < 0) extraAfk = 0; // console.log("-- extra afk debug"); @@ -225,7 +133,7 @@ export function calculateAfkSeconds(testSeconds) { // `gonna add extra ${extraAfk} seconds of afk because of no keypress data` // ); } - let ret = keypressPerSecond.filter((x) => x.afk).length; + let ret = TestInput.keypressPerSecond.filter((x) => x.afk).length; return ret + extraAfk; } @@ -233,127 +141,43 @@ export function setLastSecondNotRound() { lastSecondNotRound = true; } -export function setBurstStart(time) { - currentBurstStart = time; -} - export function calculateBurst() { - let timeToWrite = (performance.now() - currentBurstStart) / 1000; + let timeToWrite = (performance.now() - TestInput.currentBurstStart) / 1000; let wordLength; if (Config.mode === "zen") { - wordLength = TestLogic.input.current.length; + wordLength = TestInput.input.current.length; if (wordLength == 0) { - wordLength = TestLogic.input.getHistoryLast().length; + wordLength = TestInput.input.getHistoryLast().length; } } else { - wordLength = TestLogic.words.getCurrent().length; + wordLength = TestWords.words.getCurrent().length; } let speed = Misc.roundTo2((wordLength * (60 / timeToWrite)) / 5); return Math.round(speed); } export function pushBurstToHistory(speed) { - if (burstHistory[TestLogic.words.currentIndex] === undefined) { + if (burstHistory[TestWords.words.currentIndex] === undefined) { burstHistory.push(speed); } else { //repeated word - override - burstHistory[TestLogic.words.currentIndex] = speed; + burstHistory[TestWords.words.currentIndex] = speed; } } export function calculateAccuracy() { - let acc = (accuracy.correct / (accuracy.correct + accuracy.incorrect)) * 100; + let acc = + (TestInput.accuracy.correct / + (TestInput.accuracy.correct + TestInput.accuracy.incorrect)) * + 100; return isNaN(acc) ? 100 : acc; } -export function incrementAccuracy(correctincorrect) { - if (correctincorrect) { - accuracy.correct++; - } else { - accuracy.incorrect++; - } -} - -export function setKeypressTimingsTooLong() { - keypressTimings.spacing.array = "toolong"; - keypressTimings.duration.array = "toolong"; -} - -export function pushKeypressDuration(val) { - keypressTimings.duration.array.push(val); -} - -export function setKeypressDuration(val) { - keypressTimings.duration.current = val; -} - -export function pushKeypressSpacing(val) { - keypressTimings.spacing.array.push(val); -} - -export function setKeypressSpacing(val) { - keypressTimings.spacing.current = val; -} - -export function recordKeypressSpacing() { - let now = performance.now(); - let diff = Math.abs(keypressTimings.spacing.current - now); - if (keypressTimings.spacing.current !== -1) { - pushKeypressSpacing(diff); - if (spacingDebug) - console.log( - "spacing debug", - "push", - diff, - "length", - keypressTimings.spacing.array.length - ); - } - setKeypressSpacing(now); - if (spacingDebug) - console.log( - "spacing debug", - "set", - now, - "length", - keypressTimings.spacing.array.length - ); - if (spacingDebug) - console.log( - "spacing debug", - "recorded", - "length", - keypressTimings.spacing.array.length - ); -} - -export function resetKeypressTimings() { - keypressTimings = { - spacing: { - current: performance.now(), - array: [], - }, - duration: { - current: performance.now(), - array: [], - }, - }; - if (spacingDebug) console.clear(); -} - -export function pushMissedWord(word) { - if (!Object.keys(missedWords).includes(word)) { - missedWords[word] = 1; - } else { - missedWords[word]++; - } -} - export function removeAfkData() { let testSeconds = calculateTestSeconds(); - keypressPerSecond.splice(testSeconds); - keypressTimings.duration.array.splice(testSeconds); - keypressTimings.spacing.array.splice(testSeconds); + TestInput.keypressPerSecond.splice(testSeconds); + TestInput.keypressTimings.duration.array.splice(testSeconds); + TestInput.keypressTimings.spacing.array.splice(testSeconds); wpmHistory.splice(testSeconds); } @@ -365,31 +189,31 @@ function countChars() { let missedChars = 0; let spaces = 0; let correctspaces = 0; - for (let i = 0; i < TestLogic.input.history.length; i++) { + for (let i = 0; i < TestInput.input.history.length; i++) { let word = Config.mode == "zen" - ? TestLogic.input.getHistory(i) - : TestLogic.words.get(i); - if (TestLogic.input.getHistory(i) === "") { + ? TestInput.input.getHistory(i) + : TestWords.words.get(i); + if (TestInput.input.getHistory(i) === "") { //last word that was not started continue; } - if (TestLogic.input.getHistory(i) == word) { + if (TestInput.input.getHistory(i) == word) { //the word is correct correctWordChars += word.length; correctChars += word.length; if ( - i < TestLogic.input.history.length - 1 && - Misc.getLastChar(TestLogic.input.getHistory(i)) !== "\n" + i < TestInput.input.history.length - 1 && + Misc.getLastChar(TestInput.input.getHistory(i)) !== "\n" ) { correctspaces++; } - } else if (TestLogic.input.getHistory(i).length >= word.length) { + } else if (TestInput.input.getHistory(i).length >= word.length) { //too many chars - for (let c = 0; c < TestLogic.input.getHistory(i).length; c++) { + for (let c = 0; c < TestInput.input.getHistory(i).length; c++) { if (c < word.length) { //on char that still has a word list pair - if (TestLogic.input.getHistory(i)[c] == word[c]) { + if (TestInput.input.getHistory(i)[c] == word[c]) { correctChars++; } else { incorrectChars++; @@ -407,9 +231,9 @@ function countChars() { missed: 0, }; for (let c = 0; c < word.length; c++) { - if (c < TestLogic.input.getHistory(i).length) { + if (c < TestInput.input.getHistory(i).length) { //on char that still has a word list pair - if (TestLogic.input.getHistory(i)[c] == word[c]) { + if (TestInput.input.getHistory(i)[c] == word[c]) { toAdd.correct++; } else { toAdd.incorrect++; @@ -421,14 +245,14 @@ function countChars() { } correctChars += toAdd.correct; incorrectChars += toAdd.incorrect; - if (i === TestLogic.input.history.length - 1 && Config.mode == "time") { + if (i === TestInput.input.history.length - 1 && Config.mode == "time") { //last word - check if it was all correct - add to correct word chars if (toAdd.incorrect === 0) correctWordChars += toAdd.correct; } else { missedChars += toAdd.missed; } } - if (i < TestLogic.input.history.length - 1) { + if (i < TestInput.input.history.length - 1) { spaces++; } } @@ -440,7 +264,8 @@ function countChars() { spaces: spaces, correctWordChars: correctWordChars, allCorrectChars: correctChars, - incorrectChars: Config.mode == "zen" ? accuracy.incorrect : incorrectChars, + incorrectChars: + Config.mode == "zen" ? TestInput.accuracy.incorrect : incorrectChars, extraChars: extraChars, missedChars: missedChars, correctSpaces: correctspaces, diff --git a/frontend/src/js/test/test-timer.js b/frontend/src/js/test/test-timer.js index 8916de1b2..9b4057147 100644 --- a/frontend/src/js/test/test-timer.js +++ b/frontend/src/js/test/test-timer.js @@ -6,6 +6,9 @@ import * as CustomText from "./custom-text"; import * as TimerProgress from "./timer-progress"; import * as LiveWpm from "./live-wpm"; import * as TestStats from "./test-stats"; +import * as TestInput from "./test-input"; +import * as TestWords from "./test-words"; + import * as Monkey from "./monkey"; import * as Misc from "../misc"; import * as Notifications from "../elements/notifications"; @@ -116,11 +119,11 @@ function layoutfluid() { function checkIfFailed(wpmAndRaw, acc) { if (timerDebug) console.time("fail conditions"); - TestStats.pushKeypressesToHistory(); + TestInput.pushKeypressesToHistory(); if ( Config.minWpm === "custom" && wpmAndRaw.wpm < parseInt(Config.minWpmCustomSpeed) && - TestLogic.words.currentIndex > 3 + TestWords.words.currentIndex > 3 ) { clearTimeout(timer); TestLogic.fail("min wpm"); @@ -131,7 +134,7 @@ function checkIfFailed(wpmAndRaw, acc) { if ( Config.minAcc === "custom" && acc < parseInt(Config.minAccCustom) && - TestLogic.words.currentIndex > 3 + TestWords.words.currentIndex > 3 ) { clearTimeout(timer); TestLogic.fail("min accuracy"); @@ -157,8 +160,8 @@ function checkIfTimeIsUp() { //times up clearTimeout(timer); Caret.hide(); - TestLogic.input.pushHistory(); - TestLogic.corrected.pushHistory(); + TestInput.input.pushHistory(); + TestInput.corrected.pushHistory(); TestLogic.finish(); SlowTimer.clear(); slowTimerCount = 0; diff --git a/frontend/src/js/test/test-ui.js b/frontend/src/js/test/test-ui.js index 6bf9e3f63..b3abde468 100644 --- a/frontend/src/js/test/test-ui.js +++ b/frontend/src/js/test/test-ui.js @@ -3,6 +3,8 @@ import * as ThemeColors from "../elements/theme-colors"; import Config, * as UpdateConfig from "../config"; import * as DB from "../db"; import * as TestLogic from "./test-logic"; +import * as TestWords from "./test-words"; +import * as TestInput from "./test-input"; import * as Funbox from "./funbox"; import * as PaceCaret from "./pace-caret"; import * as CustomText from "./custom-text"; @@ -159,8 +161,8 @@ export function showWords() { let wordsHTML = ""; if (Config.mode !== "zen") { - for (let i = 0; i < TestLogic.words.length; i++) { - wordsHTML += getWordHTML(TestLogic.words.get(i)); + for (let i = 0; i < TestWords.words.length; i++) { + wordsHTML += getWordHTML(TestWords.words.get(i)); } } else { wordsHTML = @@ -204,11 +206,11 @@ export function showWords() { } else { if (Config.keymapMode === "next") { Keymap.highlightKey( - TestLogic.words + TestWords.words .getCurrent() .substring( - TestLogic.input.current.length, - TestLogic.input.current.length + 1 + TestInput.input.current.length, + TestInput.input.current.length + 1 ) .toString() .toUpperCase() @@ -217,7 +219,7 @@ export function showWords() { } updateActiveElement(); - Funbox.toggleScript(TestLogic.words.getCurrent()); + Funbox.toggleScript(TestWords.words.getCurrent()); Caret.updatePosition(); } @@ -334,11 +336,11 @@ export async function screenshot() { } export function updateWordElement(showError = !Config.blindMode) { - let input = TestLogic.input.current; + let input = TestInput.input.current; let wordAtIndex; let currentWord; wordAtIndex = document.querySelector("#words .word.active"); - currentWord = TestLogic.words.getCurrent(); + currentWord = TestWords.words.getCurrent(); if (!currentWord) return; let ret = ""; @@ -346,14 +348,14 @@ export function updateWordElement(showError = !Config.blindMode) { let newlineafter = false; if (Config.mode === "zen") { - for (let i = 0; i < TestLogic.input.current.length; i++) { - if (TestLogic.input.current[i] === "\t") { + for (let i = 0; i < TestInput.input.current.length; i++) { + if (TestInput.input.current[i] === "\t") { ret += `