diff --git a/gulpfile.js b/gulpfile.js index b6bc131cd..2a34268d1 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -108,6 +108,7 @@ const refactoredSrc = [ "./src/js/manual-restart-tracker.js", "./src/js/config.js", "./src/js/config-set.js", + "./src/js/test/pace-caret.js", ]; //legacy files diff --git a/src/js/account.js b/src/js/account.js index 60828668f..e0fc1d282 100644 --- a/src/js/account.js +++ b/src/js/account.js @@ -416,7 +416,7 @@ function getAccountDataAndInit() { } if (Config.paceCaret === "pb" || Config.paceCaret === "average") { if (!testActive) { - initPaceCaret(true); + PaceCaret.init(); } } // try { diff --git a/src/js/commandline.js b/src/js/commandline.js index f5a70c10d..7c0e2cf23 100644 --- a/src/js/commandline.js +++ b/src/js/commandline.js @@ -1537,7 +1537,7 @@ function updateCommandsTagsList() { DB.getSnapshot().tags.forEach((tag) => { tag.active = false; }); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); saveActiveTagsToCookie(); }, }); @@ -1557,12 +1557,7 @@ function updateCommandsTagsList() { sticky: true, exec: () => { toggleTag(tag.id); - updateTestModesNotice( - sameWordset, - textHasTab, - paceCaret, - activeFunbox - ); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); let txt = tag.name; if (tag.active === true) { diff --git a/src/js/dom-util.js b/src/js/dom-util.js index 303373897..d510632c6 100644 --- a/src/js/dom-util.js +++ b/src/js/dom-util.js @@ -1,5 +1,6 @@ import * as DB from "./db"; import Config from "./config"; +import * as PaceCaret from "./pace-caret"; export function showBackgroundLoader() { $("#backgroundLoader").stop(true, true).fadeIn(125); @@ -81,12 +82,7 @@ export function swapElements( } } -export function updateTestModesNotice( - sameWordset, - textHasTab, - paceCaret, - activeFunbox -) { +export function updateTestModesNotice(sameWordset, textHasTab, activeFunbox) { let anim = false; if ($(".pageTest #testModesNotice").text() === "") anim = true; @@ -140,7 +136,7 @@ export function updateTestModesNotice( if (Config.paceCaret !== "off") { let speed = ""; try { - speed = ` (${Math.round(paceCaret.wpm)} wpm)`; + speed = ` (${Math.round(PaceCaret.caret.wpm)} wpm)`; } catch {} $(".pageTest #testModesNotice").append( `
${ diff --git a/src/js/global-dependencies.js b/src/js/global-dependencies.js index 4887816e8..b892d1a97 100644 --- a/src/js/global-dependencies.js +++ b/src/js/global-dependencies.js @@ -36,3 +36,4 @@ import * as CustomTextPopup from "./custom-text-popup"; import * as ManualRestart from "./manual-restart-tracker"; import Config from "./config"; import * as ConfigSet from "./config-set"; +import * as PaceCaret from "./test/pace-caret"; diff --git a/src/js/script.js b/src/js/script.js index 5e8e0b0e2..c5114407a 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -30,9 +30,6 @@ let activeFunbox = "none"; let memoryFunboxTimer = null; let memoryFunboxInterval = null; -//pace caret -let paceCaret = null; - //ui let pageTransition = false; let focusState = false; @@ -213,7 +210,7 @@ async function activateFunbox(funbox, mode) { settingsGroups.layout.updateButton(); } } - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); return true; } @@ -2559,7 +2556,8 @@ function startTest() { try { if (Config.paceCaret !== "off") - movePaceCaret(performance.now() + paceCaret.spc * 1000); + PaceCaret.updatePosition(performance.now() + PaceCaret.caret.spc * 1000); + // movePaceCaret(); } catch (e) {} //use a recursive self-adjusting timer to avoid time drift const stepIntervalMS = 1000; @@ -2757,8 +2755,7 @@ function restartTest(withSameWordset = false, nosave = false, event) { hideLiveAcc(); hideTimer(); bailout = false; - paceCaret = null; - if (paceCaret !== null) clearTimeout(paceCaret.timeout); + PaceCaret.reset(); $("#showWordHistoryButton").removeClass("loaded"); focusWords(); @@ -2799,7 +2796,7 @@ function restartTest(withSameWordset = false, nosave = false, event) { sameWordset = false; textHasTab = false; await initWords(); - initPaceCaret(nosave); + PaceCaret.init(); } else { sameWordset = true; testActive = false; @@ -2807,7 +2804,7 @@ function restartTest(withSameWordset = false, nosave = false, event) { currentWordElementIndex = 0; inputHistory = []; currentInput = ""; - initPaceCaret(); + PaceCaret.init(); showWords(); } if (Config.mode === "quote") { @@ -2876,7 +2873,6 @@ function restartTest(withSameWordset = false, nosave = false, event) { $("#testModesNotice").removeClass("hidden").css({ opacity: 1, }); - resetPaceCaret(); $("#typingTest") .css("opacity", 0) .removeClass("hidden") @@ -2888,17 +2884,12 @@ function restartTest(withSameWordset = false, nosave = false, event) { 125, () => { testRestarting = false; - resetPaceCaret(); + PaceCaret.resetPosition(); hideCrown(); clearTimeout(timer); if ($("#commandLineWrapper").hasClass("hidden")) focusWords(); ChartController.result.update(); - updateTestModesNotice( - sameWordset, - textHasTab, - paceCaret, - activeFunbox - ); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); pageTransition = false; // console.log(TestStats.incompleteSeconds); // console.log(TestStats.restartCount); @@ -3024,7 +3015,7 @@ function setMode(mode, nosave) { activeFunbox === "ascii" ) { activeFunbox = "none"; - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); } $("#top .config .wordCount").addClass("hidden"); $("#top .config .time").addClass("hidden"); @@ -3687,220 +3678,6 @@ function hideQuoteSearchPopup() { } } -async function initPaceCaret() { - let mode2 = ""; - if (Config.mode === "time") { - mode2 = Config.time; - } else if (Config.mode === "words") { - mode2 = Config.words; - } else if (Config.mode === "custom") { - mode2 = "custom"; - } else if (Config.mode === "quote") { - mode2 = randomQuote.id; - } - let wpm; - if (Config.paceCaret === "pb") { - wpm = await DB.getLocalPB( - Config.mode, - mode2, - Config.punctuation, - Config.language, - Config.difficulty - ); - } else if (Config.paceCaret === "average") { - let mode2 = ""; - if (Config.mode === "time") { - mode2 = Config.time; - } else if (Config.mode === "words") { - mode2 = Config.words; - } else if (Config.mode === "custom") { - mode2 = "custom"; - } else if (Config.mode === "quote") { - mode2 = randomQuote.id; - } - wpm = await DB.getUserAverageWpm10( - Config.mode, - mode2, - Config.punctuation, - Config.language, - Config.difficulty - ); - console.log("avg pace " + wpm); - } else if (Config.paceCaret === "custom") { - wpm = Config.paceCaretCustomSpeed; - } - - if (wpm < 1 || wpm == false || wpm == undefined || Number.isNaN(wpm)) { - paceCaret = null; - return; - } - - let characters = wpm * 5; - let cps = characters / 60; //characters per step - let spc = 60 / characters; //seconds per character - - paceCaret = { - wpm: wpm, - cps: cps, - spc: spc, - correction: 0, - currentWordIndex: 0, - currentLetterIndex: -1, - wordsStatus: {}, - timeout: null, - }; - - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); -} - -function movePaceCaret(expectedStepEnd) { - if (paceCaret === null || !testActive || resultVisible) { - return; - } - if ($("#paceCaret").hasClass("hidden")) { - $("#paceCaret").removeClass("hidden"); - } - if ($("#paceCaret").hasClass("off")) { - return; - } - try { - paceCaret.currentLetterIndex++; - if ( - paceCaret.currentLetterIndex >= - wordsList[paceCaret.currentWordIndex].length - ) { - //go to the next word - paceCaret.currentLetterIndex = -1; - paceCaret.currentWordIndex++; - } - if (!Config.blindMode) { - if (paceCaret.correction < 0) { - while (paceCaret.correction < 0) { - paceCaret.currentLetterIndex--; - if (paceCaret.currentLetterIndex <= -2) { - //go to the previous word - paceCaret.currentLetterIndex = - wordsList[paceCaret.currentWordIndex - 1].length - 1; - paceCaret.currentWordIndex--; - } - paceCaret.correction++; - } - } else if (paceCaret.correction > 0) { - while (paceCaret.correction > 0) { - paceCaret.currentLetterIndex++; - if ( - paceCaret.currentLetterIndex >= - wordsList[paceCaret.currentWordIndex].length - ) { - //go to the next word - paceCaret.currentLetterIndex = -1; - paceCaret.currentWordIndex++; - } - paceCaret.correction--; - } - } - } - } catch (e) { - //out of words - paceCaret = null; - $("#paceCaret").addClass("hidden"); - return; - } - - try { - let caret = $("#paceCaret"); - let currentLetter; - let newTop; - let newLeft; - try { - let newIndex = - paceCaret.currentWordIndex - - (currentWordIndex - currentWordElementIndex); - if (paceCaret.currentLetterIndex === -1) { - currentLetter = document - .querySelectorAll("#words .word") - [newIndex].querySelectorAll("letter")[0]; - } else { - currentLetter = document - .querySelectorAll("#words .word") - [newIndex].querySelectorAll("letter")[paceCaret.currentLetterIndex]; - } - newTop = currentLetter.offsetTop - $(currentLetter).height() / 20; - newLeft; - if (paceCaret.currentLetterIndex === -1) { - newLeft = currentLetter.offsetLeft; - } else { - newLeft = - currentLetter.offsetLeft + - $(currentLetter).width() - - caret.width() / 2; - } - caret.removeClass("hidden"); - } catch (e) { - caret.addClass("hidden"); - } - - let smoothlinescroll = $("#words .smoothScroller").height(); - if (smoothlinescroll === undefined) smoothlinescroll = 0; - - $("#paceCaret").css({ - top: newTop - smoothlinescroll, - }); - - let duration = expectedStepEnd - performance.now(); - - if (Config.smoothCaret) { - caret.stop(true, true).animate( - { - left: newLeft, - }, - duration, - "linear" - ); - } else { - caret.stop(true, true).animate( - { - left: newLeft, - }, - 0, - "linear" - ); - } - paceCaret.timeout = setTimeout(() => { - try { - movePaceCaret(expectedStepEnd + paceCaret.spc * 1000); - } catch (e) { - paceCaret = null; - } - }, duration); - } catch (e) { - console.error(e); - $("#paceCaret").addClass("hidden"); - } -} - -function resetPaceCaret() { - if (Config.paceCaret === "off") return; - if (!$("#paceCaret").hasClass("hidden")) { - $("#paceCaret").addClass("hidden"); - } - if (Config.mode === "zen") return; - - let caret = $("#paceCaret"); - let firstLetter = document - .querySelector("#words .word") - .querySelector("letter"); - - caret.stop(true, true).animate( - { - top: firstLetter.offsetTop - $(firstLetter).height() / 4, - left: firstLetter.offsetLeft, - }, - 0, - "linear" - ); -} - $("#customMode2PopupWrapper").click((e) => { if ($(e.target).attr("id") === "customMode2PopupWrapper") { hideCustomMode2Popup(); @@ -4753,12 +4530,12 @@ function handleSpace(event, isEnter) { if (currentWord == currentInput || Config.mode == "zen") { //correct word or in zen mode if ( - paceCaret !== null && - paceCaret.wordsStatus[currentWordIndex] === true && + PaceCaret.caret !== null && + PaceCaret.caret.wordsStatus[currentWordIndex] === true && !Config.blindMode ) { - paceCaret.wordsStatus[currentWordIndex] = undefined; - paceCaret.correction -= currentWord.length + 1; + PaceCaret.caret.wordsStatus[currentWordIndex] = undefined; + PaceCaret.caret.correction -= currentWord.length + 1; } TestStats.incrementAccuracy(true); inputHistory.push(currentInput); @@ -4777,12 +4554,12 @@ function handleSpace(event, isEnter) { } else { //incorrect word if ( - paceCaret !== null && - paceCaret.wordsStatus[currentWordIndex] === undefined && + PaceCaret.caret !== null && + PaceCaret.caret.wordsStatus[currentWordIndex] === undefined && !Config.blindMode ) { - paceCaret.wordsStatus[currentWordIndex] = true; - paceCaret.correction += currentWord.length + 1; + PaceCaret.caret.wordsStatus[currentWordIndex] = true; + PaceCaret.caret.correction += currentWord.length + 1; } if (activeFunbox !== "nospace") { if (!Config.playSoundOnError || Config.blindMode) { diff --git a/src/js/settings.js b/src/js/settings.js index df828e131..0b59f9f5c 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -757,7 +757,7 @@ function toggleTag(tagid, nosave = false) { } } }); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveActiveTagsToCookie(); } diff --git a/src/js/test/pace-caret.js b/src/js/test/pace-caret.js new file mode 100644 index 000000000..57bc24cf9 --- /dev/null +++ b/src/js/test/pace-caret.js @@ -0,0 +1,223 @@ +import Config from "./config"; +import * as DB from "./db"; +import { updateTestModesNotice } from "./dom-util"; + +export let caret = null; + +export async function init() { + let mode2 = ""; + if (Config.mode === "time") { + mode2 = Config.time; + } else if (Config.mode === "words") { + mode2 = Config.words; + } else if (Config.mode === "custom") { + mode2 = "custom"; + } else if (Config.mode === "quote") { + mode2 = randomQuote.id; + } + let wpm; + if (Config.paceCaret === "pb") { + wpm = await DB.getLocalPB( + Config.mode, + mode2, + Config.punctuation, + Config.language, + Config.difficulty + ); + } else if (Config.paceCaret === "average") { + let mode2 = ""; + if (Config.mode === "time") { + mode2 = Config.time; + } else if (Config.mode === "words") { + mode2 = Config.words; + } else if (Config.mode === "custom") { + mode2 = "custom"; + } else if (Config.mode === "quote") { + mode2 = randomQuote.id; + } + wpm = await DB.getUserAverageWpm10( + Config.mode, + mode2, + Config.punctuation, + Config.language, + Config.difficulty + ); + console.log("avg pace " + wpm); + } else if (Config.paceCaret === "custom") { + wpm = Config.paceCaretCustomSpeed; + } + + if (wpm < 1 || wpm == false || wpm == undefined || Number.isNaN(wpm)) { + caret = null; + return; + } + + let characters = wpm * 5; + let cps = characters / 60; //characters per step + let spc = 60 / characters; //seconds per character + + caret = { + wpm: wpm, + cps: cps, + spc: spc, + correction: 0, + currentWordIndex: 0, + currentLetterIndex: -1, + wordsStatus: {}, + timeout: null, + }; + + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); +} + +export function updatePosition(expectedStepEnd) { + if (caret === null || !testActive || resultVisible) { + return; + } + if ($("#paceCaret").hasClass("hidden")) { + $("#paceCaret").removeClass("hidden"); + } + if ($("#paceCaret").hasClass("off")) { + return; + } + try { + caret.currentLetterIndex++; + if (caret.currentLetterIndex >= wordsList[caret.currentWordIndex].length) { + //go to the next word + caret.currentLetterIndex = -1; + caret.currentWordIndex++; + } + if (!Config.blindMode) { + if (caret.correction < 0) { + while (caret.correction < 0) { + caret.currentLetterIndex--; + if (caret.currentLetterIndex <= -2) { + //go to the previous word + caret.currentLetterIndex = + wordsList[caret.currentWordIndex - 1].length - 1; + caret.currentWordIndex--; + } + caret.correction++; + } + } else if (caret.correction > 0) { + while (caret.correction > 0) { + caret.currentLetterIndex++; + if ( + caret.currentLetterIndex >= wordsList[caret.currentWordIndex].length + ) { + //go to the next word + caret.currentLetterIndex = -1; + caret.currentWordIndex++; + } + caret.correction--; + } + } + } + } catch (e) { + //out of words + caret = null; + $("#paceCaret").addClass("hidden"); + return; + } + + try { + let caretEl = $("#paceCaret"); + let currentLetter; + let newTop; + let newLeft; + try { + let newIndex = + caret.currentWordIndex - (currentWordIndex - currentWordElementIndex); + if (caret.currentLetterIndex === -1) { + currentLetter = document + .querySelectorAll("#words .word") + [newIndex].querySelectorAll("letter")[0]; + } else { + currentLetter = document + .querySelectorAll("#words .word") + [newIndex].querySelectorAll("letter")[caret.currentLetterIndex]; + } + newTop = currentLetter.offsetTop - $(currentLetter).height() / 20; + newLeft; + if (caret.currentLetterIndex === -1) { + newLeft = currentLetter.offsetLeft; + } else { + newLeft = + currentLetter.offsetLeft + + $(currentLetter).width() - + caretEl.width() / 2; + } + caretEl.removeClass("hidden"); + } catch (e) { + caretEl.addClass("hidden"); + } + + let smoothlinescroll = $("#words .smoothScroller").height(); + if (smoothlinescroll === undefined) smoothlinescroll = 0; + + $("#paceCaret").css({ + top: newTop - smoothlinescroll, + }); + + let duration = expectedStepEnd - performance.now(); + + if (Config.smoothCaret) { + caretEl.stop(true, true).animate( + { + left: newLeft, + }, + duration, + "linear" + ); + } else { + caretEl.stop(true, true).animate( + { + left: newLeft, + }, + 0, + "linear" + ); + } + caret.timeout = setTimeout(() => { + try { + updatePosition(expectedStepEnd + caret.spc * 1000); + } catch (e) { + caret = null; + } + }, duration); + } catch (e) { + console.error(e); + $("#paceCaret").addClass("hidden"); + } +} + +export function reset() { + resetPosition(); + caret = null; + if (caret !== null) clearTimeout(caret.timeout); +} + +export function resetPosition() { + if (Config.paceCaret === "off") return; + if (!$("#paceCaret").hasClass("hidden")) { + $("#paceCaret").addClass("hidden"); + } + if (Config.mode === "zen") return; + + let caretEl = $("#paceCaret"); + let firstLetter = document + .querySelector("#words .word") + .querySelector("letter"); + + caretEl.stop(true, true).animate( + { + top: firstLetter.offsetTop - $(firstLetter).height() / 4, + left: firstLetter.offsetLeft, + }, + 0, + "linear" + ); + + caret = null; + if (caret !== null) clearTimeout(caret.timeout); +} diff --git a/src/js/test/test-logic.js b/src/js/test/test-logic.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/js/userconfig.js b/src/js/userconfig.js index 2a2d4bdc3..223bbcbba 100644 --- a/src/js/userconfig.js +++ b/src/js/userconfig.js @@ -140,7 +140,7 @@ function setDifficulty(diff, nosave) { } ConfigSet.difficulty(diff); if (!nosave) restartTest(false, nosave); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -160,7 +160,7 @@ function toggleBlindMode() { blind = false; } ConfigSet.blindMode(blind); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); saveConfigToCookie(); } @@ -169,7 +169,7 @@ function setBlindMode(blind, nosave) { blind = false; } ConfigSet.blindMode(blind); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -237,7 +237,7 @@ function setStopOnError(soe, nosave) { if (Config.stopOnError !== "off") { ConfigSet.confidenceMode("off"); } - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -314,8 +314,8 @@ function setPaceCaret(val, nosave) { // val = "off"; // } ConfigSet.paceCaret(val); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); - initPaceCaret(nosave); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); + PaceCaret.init(); if (!nosave) saveConfigToCookie(); } @@ -333,7 +333,7 @@ function setMinWpm(minwpm, nosave) { minwpm = "off"; } ConfigSet.minWpm(minwpm); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -351,7 +351,7 @@ function setMinAcc(min, nosave) { min = "off"; } ConfigSet.minAcc(min); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -953,7 +953,7 @@ function setConfidenceMode(cm, nosave) { ConfigSet.stopOnError("off"); } - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (!nosave) saveConfigToCookie(); } @@ -1085,7 +1085,7 @@ function setLayout(layout, nosave) { layout = "qwerty"; } ConfigSet.layout(layout); - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); if (Config.keymapLayout === "overrideSync") { refreshKeymapKeys(Config.keymapLayout); } @@ -1529,5 +1529,5 @@ function applyConfig(configObj) { $("#nitropay_ad_about").remove(); } } - updateTestModesNotice(sameWordset, textHasTab, paceCaret, activeFunbox); + updateTestModesNotice(sameWordset, textHasTab, activeFunbox); }