//test timer //ui let verifyUserWhenLoggedIn = null; /// // let CustomText = "The quick brown fox jumps over the lazy dog".split(" "); // let CustomText.isWordRandom = false; // let CustomText.word = 1; function getuid() { console.error("Only share this uid with Miodec and nobody else!"); console.log(firebase.auth().currentUser.uid); console.error("Only share this uid with Miodec and nobody else!"); } function emulateLayout(event) { function emulatedLayoutShouldShiftKey(event, newKeyPreview) { if (Config.capsLockBackspace) return event.shiftKey; const isCapsLockHeld = event.originalEvent.getModifierState("CapsLock"); if (isCapsLockHeld) return Misc.isASCIILetter(newKeyPreview) !== event.shiftKey; return event.shiftKey; } function replaceEventKey(event, keyCode) { const newKey = String.fromCharCode(keyCode); event.keyCode = keyCode; event.charCode = keyCode; event.which = keyCode; event.key = newKey; event.code = "Key" + newKey.toUpperCase(); } let newEvent = event; try { if (Config.layout === "default") { //override the caps lock modifier for the default layout if needed if (Config.capsLockBackspace && Misc.isASCIILetter(newEvent.key)) { replaceEventKey( newEvent, newEvent.shiftKey ? newEvent.key.toUpperCase().charCodeAt(0) : newEvent.key.toLowerCase().charCodeAt(0) ); } return newEvent; } const keyEventCodes = [ "Backquote", "Digit1", "Digit2", "Digit3", "Digit4", "Digit5", "Digit6", "Digit7", "Digit8", "Digit9", "Digit0", "Minus", "Equal", "KeyQ", "KeyW", "KeyE", "KeyR", "KeyT", "KeyY", "KeyU", "KeyI", "KeyO", "KeyP", "BracketLeft", "BracketRight", "Backslash", "KeyA", "KeyS", "KeyD", "KeyF", "KeyG", "KeyH", "KeyJ", "KeyK", "KeyL", "Semicolon", "Quote", "IntlBackslash", "KeyZ", "KeyX", "KeyC", "KeyV", "KeyB", "KeyN", "KeyM", "Comma", "Period", "Slash", "Space", ]; const layoutMap = layouts[Config.layout].keys; let mapIndex; for (let i = 0; i < keyEventCodes.length; i++) { if (newEvent.code == keyEventCodes[i]) { mapIndex = i; } } const newKeyPreview = layoutMap[mapIndex][0]; const shift = emulatedLayoutShouldShiftKey(newEvent, newKeyPreview) ? 1 : 0; const newKey = layoutMap[mapIndex][shift]; replaceEventKey(newEvent, newKey.charCodeAt(0)); } catch (e) { return event; } return newEvent; } (function (history) { var pushState = history.pushState; history.pushState = function (state) { if (Funbox.active === "memory" && state !== "/") { Funbox.resetMemoryTimer(); } return pushState.apply(history, arguments); }; })(window.history); function highlightBadWord(index, showError) { if (!showError) return; $($("#words .word")[index]).addClass("error"); } function showTestConfig() { $("#top .config").removeClass("hidden").css("opacity", 1); } function hideTestConfig() { $("#top .config").css("opacity", 0).addClass("hidden"); } function startTest() { if (UI.pageTransition) { return false; } if (!Config.dbConfigLoaded) { UpdateConfig.setChangedBeforeDb(true); } try { if (firebase.auth().currentUser != null) { firebase.analytics().logEvent("testStarted"); } else { firebase.analytics().logEvent("testStartedNoLogin"); } } catch (e) { console.log("Analytics unavailable"); } TestLogic.setActive(true); TestStats.resetKeypressTimings(); TimerProgress.restart(); TimerProgress.show(); $("#liveWpm").text("0"); LiveWpm.show(); LiveAcc.show(); TimerProgress.update(TestTimer.time); TestTimer.clear(); if (Funbox.active === "memory") { Funbox.resetMemoryTimer(); $("#wordsWrapper").addClass("hidden"); } try { if (Config.paceCaret !== "off") PaceCaret.start(); } catch (e) {} //use a recursive self-adjusting timer to avoid time drift TestStats.setStart(performance.now()); TestTimer.start(); return true; } function changePage(page) { if (UI.pageTransition) { return; } let activePage = $(".page.active"); $(".page").removeClass("active"); $("#wordsInput").focusout(); if (page == "test" || page == "") { UI.setPageTransition(true); swapElements(activePage, $(".page.pageTest"), 250, () => { UI.setPageTransition(false); focusWords(); $(".page.pageTest").addClass("active"); history.pushState("/", null, "/"); }); showTestConfig(); hideSignOutButton(); // restartCount = 0; // incompleteTestSeconds = 0; TestStats.resetIncomplete(); ManualRestart.set(); TestLogic.restart(); } else if (page == "about") { UI.setPageTransition(true); TestLogic.restart(); swapElements(activePage, $(".page.pageAbout"), 250, () => { UI.setPageTransition(false); history.pushState("about", null, "about"); $(".page.pageAbout").addClass("active"); }); hideTestConfig(); hideSignOutButton(); } else if (page == "settings") { UI.setPageTransition(true); TestLogic.restart(); swapElements(activePage, $(".page.pageSettings"), 250, () => { UI.setPageTransition(false); history.pushState("settings", null, "settings"); $(".page.pageSettings").addClass("active"); }); updateSettingsPage(); hideTestConfig(); hideSignOutButton(); } else if (page == "account") { if (!firebase.auth().currentUser) { changePage("login"); } else { UI.setPageTransition(true); TestLogic.restart(); swapElements(activePage, $(".page.pageAccount"), 250, () => { UI.setPageTransition(false); history.pushState("account", null, "account"); $(".page.pageAccount").addClass("active"); }); refreshAccountPage(); hideTestConfig(); showSignOutButton(); } } else if (page == "login") { if (firebase.auth().currentUser != null) { changePage("account"); } else { UI.setPageTransition(true); TestLogic.restart(); swapElements(activePage, $(".page.pageLogin"), 250, () => { UI.setPageTransition(false); history.pushState("login", null, "login"); $(".page.pageLogin").addClass("active"); }); hideTestConfig(); hideSignOutButton(); } } } function showEditTags(action, id, name) { if (action === "add") { $("#tagsWrapper #tagsEdit").attr("action", "add"); $("#tagsWrapper #tagsEdit .title").html("Add new tag"); $("#tagsWrapper #tagsEdit .button").html(``); $("#tagsWrapper #tagsEdit input").val(""); $("#tagsWrapper #tagsEdit input").removeClass("hidden"); } else if (action === "edit") { $("#tagsWrapper #tagsEdit").attr("action", "edit"); $("#tagsWrapper #tagsEdit").attr("tagid", id); $("#tagsWrapper #tagsEdit .title").html("Edit tag name"); $("#tagsWrapper #tagsEdit .button").html(``); $("#tagsWrapper #tagsEdit input").val(name); $("#tagsWrapper #tagsEdit input").removeClass("hidden"); } else if (action === "remove") { $("#tagsWrapper #tagsEdit").attr("action", "remove"); $("#tagsWrapper #tagsEdit").attr("tagid", id); $("#tagsWrapper #tagsEdit .title").html("Remove tag " + name); $("#tagsWrapper #tagsEdit .button").html(``); $("#tagsWrapper #tagsEdit input").addClass("hidden"); } if ($("#tagsWrapper").hasClass("hidden")) { $("#tagsWrapper") .stop(true, true) .css("opacity", 0) .removeClass("hidden") .animate({ opacity: 1 }, 100, () => { $("#tagsWrapper #tagsEdit input").focus(); }); } } function hideEditTags() { if (!$("#tagsWrapper").hasClass("hidden")) { $("#tagsWrapper #tagsEdit").attr("action", ""); $("#tagsWrapper #tagsEdit").attr("tagid", ""); $("#tagsWrapper") .stop(true, true) .css("opacity", 1) .animate( { opacity: 0, }, 100, () => { $("#tagsWrapper").addClass("hidden"); } ); } } $("#tagsWrapper").click((e) => { if ($(e.target).attr("id") === "tagsWrapper") { hideEditTags(); } }); $("#tagsWrapper #tagsEdit .button").click(() => { tagsEdit(); }); $("#tagsWrapper #tagsEdit input").keypress((e) => { if (e.keyCode == 13) { tagsEdit(); } }); function tagsEdit() { let action = $("#tagsWrapper #tagsEdit").attr("action"); let inputVal = $("#tagsWrapper #tagsEdit input").val(); let tagid = $("#tagsWrapper #tagsEdit").attr("tagid"); hideEditTags(); if (action === "add") { showBackgroundLoader(); CloudFunctions.addTag({ uid: firebase.auth().currentUser.uid, name: inputVal, }).then((e) => { hideBackgroundLoader(); let status = e.data.resultCode; if (status === 1) { Notifications.add("Tag added", 1, 2); DB.getSnapshot().tags.push({ name: inputVal, id: e.data.id, }); updateResultEditTagsPanelButtons(); updateSettingsPage(); updateFilterTags(); } else if (status === -1) { Notifications.add("Invalid tag name", 0); } else if (status < -1) { Notifications.add("Unknown error: " + e.data.message, -1); } }); } else if (action === "edit") { showBackgroundLoader(); CloudFunctions.editTag({ uid: firebase.auth().currentUser.uid, name: inputVal, tagid: tagid, }).then((e) => { hideBackgroundLoader(); let status = e.data.resultCode; if (status === 1) { Notifications.add("Tag updated", 1); DB.getSnapshot().tags.forEach((tag) => { if (tag.id === tagid) { tag.name = inputVal; } }); updateResultEditTagsPanelButtons(); updateSettingsPage(); updateFilterTags(); } else if (status === -1) { Notifications.add("Invalid tag name", 0); } else if (status < -1) { Notifications.add("Unknown error: " + e.data.message, -1); } }); } else if (action === "remove") { showBackgroundLoader(); CloudFunctions.removeTag({ uid: firebase.auth().currentUser.uid, tagid: tagid, }).then((e) => { hideBackgroundLoader(); let status = e.data.resultCode; if (status === 1) { Notifications.add("Tag removed", 1); DB.getSnapshot().tags.forEach((tag, index) => { if (tag.id === tagid) { DB.getSnapshot().tags.splice(index, 1); } }); updateResultEditTagsPanelButtons(); updateSettingsPage(); updateFilterTags(); } else if (status < -1) { Notifications.add("Unknown error: " + e.data.message, -1); } }); } } $(document).on("click", "#top .logo", (e) => { changePage("test"); }); $(document).on("click", "#top .config .wordCount .text-button", (e) => { const wrd = $(e.currentTarget).attr("wordCount"); if (wrd == "custom") { CustomMode2Popup.show("words"); } else { UpdateConfig.setWordCount(wrd); ManualRestart.set(); TestLogic.restart(); } }); $(document).on("click", "#top .config .time .text-button", (e) => { let mode = $(e.currentTarget).attr("timeConfig"); if (mode == "custom") { CustomMode2Popup.show("time"); } else { UpdateConfig.setTimeConfig(mode); ManualRestart.set(); TestLogic.restart(); } }); $(document).on("click", "#top .config .quoteLength .text-button", (e) => { let len = $(e.currentTarget).attr("quoteLength"); if (len == -2) { UpdateConfig.setQuoteLength(-2, false, e.shiftKey); QuoteSearchPopup.show(); } else { if (len == -1) { len = [0, 1, 2, 3]; } UpdateConfig.setQuoteLength(len, false, e.shiftKey); ManualRestart.set(); TestLogic.restart(); } }); $(document).on("click", "#top .config .customText .text-button", () => { CustomTextPopup.show(); }); $(document).on("click", "#top .config .punctuationMode .text-button", () => { UpdateConfig.togglePunctuation(); ManualRestart.set(); TestLogic.restart(); }); $(document).on("click", "#top .config .numbersMode .text-button", () => { UpdateConfig.toggleNumbers(); ManualRestart.set(); TestLogic.restart(); }); $("#wordsWrapper").on("click", () => { focusWords(); }); $(document).on("click", "#top .config .mode .text-button", (e) => { if ($(e.currentTarget).hasClass("active")) return; const mode = $(e.currentTarget).attr("mode"); UpdateConfig.setMode(mode); ManualRestart.set(); TestLogic.restart(); }); $(document).on("click", "#top #menu .icon-button", (e) => { if ($(e.currentTarget).hasClass("discord")) return; if ($(e.currentTarget).hasClass("leaderboards")) { Leaderboards.show(); } else { const href = $(e.currentTarget).attr("href"); ManualRestart.set(); 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 == 13) { if ( TestLogic.active && Config.repeatQuotes === "typing" && Config.mode === "quote" ) { TestLogic.restart(true); } else { TestLogic.restart(); } } }); $(document.body).on("click", "#restartTestButton", () => { ManualRestart.set(); if (TestUI.resultCalculating) return; if ( TestLogic.active && Config.repeatQuotes === "typing" && Config.mode === "quote" ) { TestLogic.restart(true); } else { TestLogic.restart(); } }); $(document).on("keypress", "#practiseMissedWordsButton", (event) => { if (event.keyCode == 13) { PractiseMissed.init(); } }); $(document.body).on("click", "#practiseMissedWordsButton", () => { PractiseMissed.init(); }); $(document).on("keypress", "#nextTestButton", (event) => { if (event.keyCode == 13) { TestLogic.restart(); } }); $(document.body).on("click", "#nextTestButton", () => { ManualRestart.set(); TestLogic.restart(); }); $(document).on("keypress", "#showWordHistoryButton", (event) => { if (event.keyCode == 13) { TestUI.toggleResultWords(); } }); $(document.body).on("click", "#showWordHistoryButton", () => { TestUI.toggleResultWords(); }); $(document.body).on("click", "#restartTestButtonWithSameWordset", () => { if (Config.mode == "zen") { Notifications.add("Repeat test disabled in zen mode"); return; } ManualRestart.set(); TestLogic.restart(true); }); $(document).on("keypress", "#restartTestButtonWithSameWordset", (event) => { if (Config.mode == "zen") { Notifications.add("Repeat test disabled in zen mode"); return; } if (event.keyCode == 13) { TestLogic.restart(true); } }); $(document.body).on("click", ".version", () => { $("#versionHistoryWrapper") .css("opacity", 0) .removeClass("hidden") .animate({ opacity: 1 }, 125); }); $(document.body).on("click", "#versionHistoryWrapper", () => { $("#versionHistoryWrapper") .css("opacity", 1) .animate({ opacity: 0 }, 125, () => { $("#versionHistoryWrapper").addClass("hidden"); }); }); $(document.body).on("click", "#supportMeButton", () => { $("#supportMeWrapper") .css("opacity", 0) .removeClass("hidden") .animate({ opacity: 1 }, 125); }); $(document.body).on("click", "#supportMeWrapper", () => { $("#supportMeWrapper") .css("opacity", 1) .animate({ opacity: 0 }, 125, () => { $("#supportMeWrapper").addClass("hidden"); }); }); $(document.body).on("click", "#supportMeWrapper .button.ads", () => { CommandlineLists.pushCurrent(CommandlineLists.commandsEnableAds); Commandline.show(); $("#supportMeWrapper") .css("opacity", 1) .animate({ opacity: 0 }, 125, () => { $("#supportMeWrapper").addClass("hidden"); }); }); $(document.body).on("click", "#supportMeWrapper a.button", () => { $("#supportMeWrapper") .css("opacity", 1) .animate({ opacity: 0 }, 125, () => { $("#supportMeWrapper").addClass("hidden"); }); }); $(document.body).on("click", ".pageAbout .aboutEnableAds", () => { CommandlineLists.pushCurrent(CommandlineLists.commandsEnableAds); Commandline.show(); }); $("#wordsInput").keypress((event) => { event.preventDefault(); }); $("#wordsInput").on("focus", () => { if (!TestUI.resultVisible && Config.showOutOfFocusWarning) { OutOfFocus.hide(); } Caret.show(TestLogic.input.current); }); $("#wordsInput").on("focusout", () => { if (!TestUI.resultVisible && Config.showOutOfFocusWarning) { OutOfFocus.show(); } Caret.hide(); }); $(window).resize(() => { Caret.updatePosition(); }); $(document).mousemove(function (event) { if ( $("#top").hasClass("focus") && (event.originalEvent.movementX > 0 || event.originalEvent.movementY > 0) ) { Focus.set(false); } }); $(document).on("click", "#testModesNotice .text-button", (event) => { // console.log("CommandlineLists."+$(event.currentTarget).attr("commands")); let commands = CommandlineLists.getList( $(event.currentTarget).attr("commands") ); let func = $(event.currentTarget).attr("function"); if (commands !== undefined) { if ($(event.currentTarget).attr("commands") === "commandsTags") { CommandlineLists.updateTagCommands(); } CommandlineLists.pushCurrent(commands); Commandline.show(); } else if (func != undefined) { eval(func); } }); $(document).on("click", "#commandLineMobileButton", () => { CommandlineLists.setCurrent(CommandlineLists.defaultCommands); Commandline.show(); }); let dontInsertSpace = false; $(document).keyup((event) => { if (!event.originalEvent.isTrusted) return; if (TestUI.resultVisible) return; let now = performance.now(); let diff = Math.abs(TestStats.keypressTimings.duration.current - now); if (TestStats.keypressTimings.duration.current !== -1) { TestStats.pushKeypressDuration(diff); // keypressStats.duration.array.push(diff); } TestStats.setKeypressDuration(now); // keypressStats.duration.current = now; Monkey.stop(); }); $(document).keydown(function (event) { if (!(event.key == " ") && !event.originalEvent.isTrusted) return; if (!TestUI.resultVisible) { TestStats.recordKeypressSpacing(); } Monkey.type(); //autofocus let pageTestActive = !$(".pageTest").hasClass("hidden"); let commandLineVisible = !$("#commandLineWrapper").hasClass("hidden"); let wordsFocused = $("#wordsInput").is(":focus"); let modePopupVisible = !$("#customTextPopupWrapper").hasClass("hidden") || !$("#customMode2PopupWrapper").hasClass("hidden") || !$("#quoteSearchPopupWrapper").hasClass("hidden"); if ( pageTestActive && !commandLineVisible && !modePopupVisible && !TestUI.resultVisible && !wordsFocused && event.key !== "Enter" ) { focusWords(); wordsFocused = true; // if (Config.showOutOfFocusWarning) return; } //tab if ( (event.key == "Tab" && !Config.swapEscAndTab) || (event.key == "Escape" && Config.swapEscAndTab) ) { handleTab(event); // event.preventDefault(); } //blocking firefox from going back in history with backspace if (event.key === "Backspace" && wordsFocused) { let t = /INPUT|SELECT|TEXTAREA/i; if ( !t.test(event.target.tagName) || event.target.disabled || event.target.readOnly ) { event.preventDefault(); } } // keypressStats.duration.current = performance.now(); TestStats.setKeypressDuration(performance.now()); if (TestUI.testRestarting) { return; } //backspace const isBackspace = event.key === "Backspace" || (Config.capsLockBackspace && event.key === "CapsLock"); if (isBackspace && wordsFocused) { handleBackspace(event); } if (event.key === "Enter" && Funbox.active === "58008" && wordsFocused) { event.key = " "; } //space or enter if (event.key === " " && wordsFocused) { handleSpace(event, false); } if (wordsFocused && !commandLineVisible) { handleAlpha(event); } let acc = Misc.roundTo2(TestStats.calculateAccuracy()); LiveAcc.update(acc); }); function handleTab(event) { if (TestUI.resultCalculating) { event.preventDefault(); } if ($("#customTextPopup .textarea").is(":focus")) { event.preventDefault(); let area = $("#customTextPopup .textarea")[0]; var start = area.selectionStart; var end = area.selectionEnd; // set textarea value to: text before caret + tab + text after caret area.value = area.value.substring(0, start) + "\t" + area.value.substring(end); // put caret at right position again area.selectionStart = area.selectionEnd = start + 1; // event.preventDefault(); // $("#customTextPopup .textarea").val( // $("#customTextPopup .textarea").val() + "\t" // ); return; } else if ( $(".pageTest").hasClass("active") && !TestUI.resultCalculating && $("#commandLineWrapper").hasClass("hidden") && $("#simplePopupWrapper").hasClass("hidden") ) { if (Config.quickTab) { if (Config.mode == "zen" && !event.shiftKey) { //ignore } else { if (event.shiftKey) ManualRestart.set(); if ( TestLogic.active && Config.repeatQuotes === "typing" && Config.mode === "quote" ) { TestLogic.restart(true, false, event); } else { TestLogic.restart(false, false, event); } } } else { if ( !TestUI.resultVisible && ((TestLogic.hasTab && event.shiftKey) || (!TestLogic.hasTab && Config.mode !== "zen") || (Config.mode === "zen" && event.shiftKey)) ) { event.preventDefault(); $("#restartTestButton").focus(); } } } else if (Config.quickTab) { changePage("test"); } // } else if ( // !event.ctrlKey && // ( // (!event.shiftKey && !TestLogic.hasTab) || // (event.shiftKey && TestLogic.hasTab) || // TestUI.resultVisible // ) && // Config.quickTab && // !$(".pageLogin").hasClass("active") && // !resultCalculating && // $("#commandLineWrapper").hasClass("hidden") && // $("#simplePopupWrapper").hasClass("hidden") // ) { // event.preventDefault(); // if ($(".pageTest").hasClass("active")) { // if ( // (Config.mode === "words" && Config.words < 1000) || // (Config.mode === "time" && Config.time < 3600) || // Config.mode === "quote" || // (Config.mode === "custom" && // CustomText.isWordRandom && // CustomText.word < 1000) || // (Config.mode === "custom" && // CustomText.isTimeRandom && // CustomText.time < 3600) || // (Config.mode === "custom" && // !CustomText.isWordRandom && // CustomText.text.length < 1000) // ) { // if (TestLogic.active) { // let testNow = performance.now(); // let testSeconds = Misc.roundTo2((testNow - testStart) / 1000); // let afkseconds = keypressPerSecond.filter( // (x) => x.count == 0 && x.mod == 0 // ).length; // incompleteTestSeconds += testSeconds - afkseconds; // restartCount++; // } // TestLogic.restart(); // } else { // Notifications.add("Quick restart disabled for long tests", 0); // } // } else { // changePage("test"); // } // } else if ( // !Config.quickTab && // TestLogic.hasTab && // event.shiftKey && // !TestUI.resultVisible // ) { // event.preventDefault(); // $("#restartTestButton").focus(); // } } function handleBackspace(event) { event.preventDefault(); if (!TestLogic.active) return; if ( TestLogic.input.current == "" && TestLogic.input.history.length > 0 && TestUI.currentWordElementIndex > 0 ) { //if nothing is inputted and its not the first word if ( (TestLogic.input.getHistory(TestLogic.words.currentIndex - 1) == TestLogic.words.get(TestLogic.words.currentIndex - 1) && !Config.freedomMode) || $($(".word")[TestLogic.words.currentIndex - 1]).hasClass("hidden") ) { return; } else { if (Config.confidenceMode === "on" || Config.confidenceMode === "max") return; if (event["ctrlKey"] || event["altKey"]) { TestLogic.input.resetCurrent(); TestLogic.input.popHistory(); TestLogic.corrected.popHistory(); } else { TestLogic.input.setCurrent(TestLogic.input.popHistory()); TestLogic.corrected.setCurrent(TestLogic.corrected.popHistory()); if (Funbox.active === "nospace") { TestLogic.input.setCurrent( TestLogic.input.current.substring( 0, TestLogic.input.current.length - 1 ) ); } } TestLogic.words.decreaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex - 1); TestUI.updateActiveElement(true); Funbox.toggleScript(TestLogic.words.getCurrent()); TestUI.updateWordElement(!Config.blindMode); } } else { if (Config.confidenceMode === "max") return; if (event["ctrlKey"] || event["altKey"]) { let limiter = " "; if ( TestLogic.input.current.lastIndexOf("-") > TestLogic.input.current.lastIndexOf(" ") ) limiter = "-"; let split = TestLogic.input.current.replace(/ +/g, " ").split(limiter); if (split[split.length - 1] == "") { split.pop(); } let addlimiter = false; if (split.length > 1) { addlimiter = true; } split.pop(); TestLogic.input.setCurrent(split.join(limiter)); if (addlimiter) { TestLogic.input.appendCurrent(limiter); } } else if (event.metaKey) { TestLogic.input.resetCurrent(); } else { TestLogic.input.setCurrent( TestLogic.input.current.substring(0, TestLogic.input.current.length - 1) ); } TestUI.updateWordElement(!Config.blindMode); } Sound.playClick(Config.playSoundOnClick); if (Config.keymapMode === "react") { Keymap.flashKey(event.code, true); } else if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); } Caret.updatePosition(); } function handleSpace(event, isEnter) { if (!TestLogic.active) return; if (TestLogic.input.current === "") return; // let nextWord = wordsList[TestLogic.words.currentIndex + 1]; // if ((isEnter && nextWord !== "\n") && (isEnter && Funbox.active !== "58008")) return; // if (!isEnter && nextWord === "\n") return; event.preventDefault(); if (Config.mode == "zen") { $("#words .word.active").removeClass("active"); $("#words").append("
"); } let currentWord = TestLogic.words.getCurrent(); if (Funbox.active === "layoutfluid" && Config.mode !== "time") { const layouts = ["qwerty", "dvorak", "colemak"]; let index = 0; let outof = TestLogic.words.length; index = Math.floor((TestLogic.input.history.length + 1) / (outof / 3)); if (Config.layout !== layouts[index] && layouts[index] !== undefined) { Notifications.add(`--- !!! ${layouts[index]} !!! ---`, 0); } UpdateConfig.setLayout(layouts[index]); UpdateConfig.setKeymapLayout(layouts[index]); Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); settingsGroups.layout.updateButton(); } dontInsertSpace = true; if (currentWord == TestLogic.input.current || Config.mode == "zen") { //correct word or in zen mode PaceCaret.handleSpace(true, currentWord); TestStats.incrementAccuracy(true); TestLogic.input.pushHistory(); TestLogic.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); Funbox.toggleScript(TestLogic.words.getCurrent()); Caret.updatePosition(); TestStats.incrementKeypressCount(); TestStats.pushKeypressWord(TestLogic.words.currentIndex); // currentKeypress.count++; // currentKeypress.words.push(TestLogic.words.currentIndex); if (Funbox.active !== "nospace") { Sound.playClick(Config.playSoundOnClick); } } else { //incorrect word PaceCaret.handleSpace(false, currentWord); if (Funbox.active !== "nospace") { if (!Config.playSoundOnError || Config.blindMode) { Sound.playClick(Config.playSoundOnClick); } else { Sound.playError(Config.playSoundOnError); } } TestStats.incrementAccuracy(false); TestStats.incrementKeypressErrors(); let cil = TestLogic.input.current.length; if (cil <= TestLogic.words.getCurrent().length) { if (cil >= TestLogic.corrected.current.length) { TestLogic.corrected.appendCurrent("_"); } else { TestLogic.corrected.setCurrent( TestLogic.corrected.current.substring(0, cil) + "_" + TestLogic.corrected.current.substring(cil + 1) ); } } if (Config.stopOnError != "off") { if (Config.difficulty == "expert" || Config.difficulty == "master") { //failed due to diff when pressing space TestLogic.fail(); return; } if (Config.stopOnError == "word") { TestLogic.input.appendCurrent(" "); TestUI.updateWordElement(true); Caret.updatePosition(); } return; } if (Config.blindMode) $("#words .word.active letter").addClass("correct"); TestLogic.input.pushHistory(); highlightBadWord(TestUI.currentWordElementIndex, !Config.blindMode); TestLogic.words.increaseCurrentIndex(); TestUI.setCurrentWordElementIndex(TestUI.currentWordElementIndex + 1); TestUI.updateActiveElement(); Funbox.toggleScript(TestLogic.words.getCurrent()); Caret.updatePosition(); // currentKeypress.count++; // currentKeypress.words.push(TestLogic.words.currentIndex); TestStats.incrementKeypressCount(); TestStats.pushKeypressWord(TestLogic.words.currentIndex); if (Config.difficulty == "expert" || Config.difficulty == "master") { TestLogic.fail(); return; } else if (TestLogic.words.currentIndex == TestLogic.words.length) { //submitted last word that is incorrect TestStats.setLastSecondNotRound(); TestLogic.finish(); return; } } TestLogic.corrected.pushHistory(); if ( !Config.showAllLines || Config.mode == "time" || (CustomText.isWordRandom && CustomText.word == 0) || CustomText.isTimeRandom ) { let currentTop = Math.floor( document.querySelectorAll("#words .word")[ TestUI.currentWordElementIndex - 1 ].offsetTop ); let nextTop; try { nextTop = Math.floor( document.querySelectorAll("#words .word")[ TestUI.currentWordElementIndex ].offsetTop ); } catch (e) { nextTop = 0; } if (nextTop > currentTop && !TestUI.lineTransition) { TestUI.lineJump(currentTop); } } //end of line wrap Caret.updatePosition(); if (Config.keymapMode === "react") { Keymap.flashKey(event.code, true); } else if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); } if ( Config.mode === "words" || Config.mode === "custom" || Config.mode === "quote" || Config.mode === "zen" ) { TimerProgress.update(TestTimer.time); } if ( Config.mode == "time" || Config.mode == "words" || Config.mode == "custom" ) { TestLogic.addWord(); } } function handleAlpha(event) { if ( [ "ContextMenu", "Escape", "Shift", "Control", "Meta", "Alt", "AltGraph", "CapsLock", "Backspace", "PageUp", "PageDown", "Home", "ArrowUp", "ArrowLeft", "ArrowRight", "ArrowDown", "OS", "Insert", "Home", "Undefined", "Control", "Fn", "FnLock", "Hyper", "NumLock", "ScrollLock", "Symbol", "SymbolLock", "Super", "Unidentified", "Process", "Delete", "KanjiMode", "Pause", "PrintScreen", "Clear", "End", undefined, ].includes(event.key) ) { TestStats.incrementKeypressMod(); // currentKeypress.mod++; return; } //insert space for expert and master or strict space, //otherwise dont do anything if (event.key === " ") { if (Config.difficulty !== "normal" || Config.strictSpace) { if (dontInsertSpace) { dontInsertSpace = false; return; } } else { return; } } if (event.key === "Tab") { if ( Config.mode !== "zen" && (!TestLogic.hasTab || (TestLogic.hasTab && event.shiftKey)) ) { return; } event.key = "\t"; event.preventDefault(); } if (event.key === "Enter") { if (event.shiftKey && Config.mode == "zen") { TestLogic.finish(); } if ( event.shiftKey && ((Config.mode == "time" && Config.time === 0) || (Config.mode == "words" && Config.words === 0)) ) { TestLogic.setBailout(true); TestLogic.finish(); } event.key = "\n"; } // if (event.key.length > 1) return; if (/F\d+/.test(event.key)) return; if (/Numpad/.test(event.key)) return; if (/Volume/.test(event.key)) return; if (/Media/.test(event.key)) return; if ( event.ctrlKey != event.altKey && (event.ctrlKey || /Linux/.test(window.navigator.platform)) ) return; if (event.metaKey) return; let originalEvent = event; event = emulateLayout(event); //start the test if ( TestLogic.input.current == "" && TestLogic.input.history.length == 0 && !TestLogic.active ) { if (!startTest()) return; } else { if (!TestLogic.active) return; } Focus.set(true); Caret.stopAnimation(); //show dead keys if (event.key === "Dead") { Sound.playClick(Config.playSoundOnClick); $( document.querySelector("#words .word.active").querySelectorAll("letter")[ TestLogic.input.current.length ] ).toggleClass("dead"); return; } //check if the char typed was correct let thisCharCorrect; let nextCharInWord; if (Config.mode != "zen") { nextCharInWord = TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ); } if (nextCharInWord == event["key"]) { thisCharCorrect = true; } else { thisCharCorrect = false; } if (Config.language.split("_")[0] == "russian") { if ((event.key === "е" || event.key === "e") && nextCharInWord == "ё") { event.key = nextCharInWord; thisCharCorrect = true; } if ( event.key === "ё" && (nextCharInWord == "е" || nextCharInWord === "e") ) { event.key = nextCharInWord; thisCharCorrect = true; } } if (Config.mode == "zen") { thisCharCorrect = true; } if (event.key === "’" && nextCharInWord == "'") { event.key = "'"; thisCharCorrect = true; } if (event.key === "'" && nextCharInWord == "’") { event.key = "’"; thisCharCorrect = true; } if (event.key === "”" && nextCharInWord == '"') { event.key = '"'; thisCharCorrect = true; } if (event.key === '"' && nextCharInWord == "”") { event.key = "”"; thisCharCorrect = true; } if ((event.key === "–" || event.key === "—") && nextCharInWord == "-") { event.key = "-"; thisCharCorrect = true; } if ( Config.oppositeShiftMode === "on" && ShiftTracker.isUsingOppositeShift(originalEvent) === false ) { thisCharCorrect = false; } if (!thisCharCorrect) { TestStats.incrementAccuracy(false); TestStats.incrementKeypressErrors(); // currentError.count++; // currentError.words.push(TestLogic.words.currentIndex); thisCharCorrect = false; TestStats.pushMissedWord(TestLogic.words.getCurrent()); } else { TestStats.incrementAccuracy(true); thisCharCorrect = true; if (Config.mode == "zen") { //making the input visible to the user $("#words .active").append( `${event.key}` ); } } if (thisCharCorrect) { Sound.playClick(Config.playSoundOnClick); } else { if (!Config.playSoundOnError || Config.blindMode) { Sound.playClick(Config.playSoundOnClick); } else { Sound.playError(Config.playSoundOnError); } } if ( Config.oppositeShiftMode === "on" && ShiftTracker.isUsingOppositeShift(originalEvent) === false ) return; //update current corrected verison. if its empty then add the current key. if its not then replace the last character with the currently pressed one / add it if (TestLogic.corrected.current === "") { TestLogic.corrected.setCurrent(TestLogic.input.current + event["key"]); } else { let cil = TestLogic.input.current.length; if (cil >= TestLogic.corrected.current.length) { TestLogic.corrected.appendCurrent(event["key"]); } else if (!thisCharCorrect) { TestLogic.corrected.setCurrent( TestLogic.corrected.current.substring(0, cil) + event["key"] + TestLogic.corrected.current.substring(cil + 1) ); } } TestStats.incrementKeypressCount(); TestStats.pushKeypressWord(TestLogic.words.currentIndex); // currentKeypress.count++; // currentKeypress.words.push(TestLogic.words.currentIndex); if (Config.stopOnError == "letter" && !thisCharCorrect) { return; } //update the active word top, but only once if ( TestLogic.input.current.length === 1 && TestLogic.words.currentIndex === 0 ) { TestUI.setActiveWordTop(document.querySelector("#words .active").offsetTop); } //max length of the input is 20 unless in zen mode if ( Config.mode == "zen" || TestLogic.input.current.length < TestLogic.words.getCurrent().length + 20 ) { TestLogic.input.appendCurrent(event["key"]); } if (!thisCharCorrect && Config.difficulty == "master") { TestLogic.fail(); return; } //keymap if (Config.keymapMode === "react") { Keymap.flashKey(event.key, thisCharCorrect); } else if (Config.keymapMode === "next" && Config.mode !== "zen") { Keymap.highlightKey( TestLogic.words .getCurrent() .substring( TestLogic.input.current.length, TestLogic.input.current.length + 1 ) .toString() .toUpperCase() ); } let activeWordTopBeforeJump = TestUI.activeWordTop; TestUI.updateWordElement(!Config.blindMode); 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; if ( (currentWord == TestLogic.input.current || (Config.quickEnd && currentWord.length == TestLogic.input.current.length && Config.stopOnError == "off")) && lastindex == TestLogic.words.length - 1 ) { TestLogic.input.pushHistory(); TestLogic.corrected.pushHistory(); TestStats.setLastSecondNotRound(); TestLogic.finish(); } } //simulate space press in nospace funbox if ( (Funbox.active === "nospace" && TestLogic.input.current.length === TestLogic.words.getCurrent().length) || (event.key === "\n" && thisCharCorrect) ) { $.event.trigger({ type: "keydown", which: " ".charCodeAt(0), key: " ", }); } let newActiveTop = document.querySelector("#words .word.active").offsetTop; //stop the word jump by slicing off the last character, update word again if ( activeWordTopBeforeJump < newActiveTop && !TestUI.lineTransition && TestLogic.input.current.length > 1 ) { if (Config.mode == "zen") { let currentTop = Math.floor( document.querySelectorAll("#words .word")[ TestUI.currentWordElementIndex - 1 ].offsetTop ); if (!Config.showAllLines) TestUI.lineJump(currentTop); } else { TestLogic.input.setCurrent(TestLogic.input.current.slice(0, -1)); TestUI.updateWordElement(!Config.blindMode); } } Caret.updatePosition(); } window.addEventListener("beforeunload", (event) => { // Cancel the event as stated by the standard. if ( (Config.mode === "words" && Config.words < 1000) || (Config.mode === "time" && Config.time < 3600) || Config.mode === "quote" || (Config.mode === "custom" && CustomText.isWordRandom && CustomText.word < 1000) || (Config.mode === "custom" && CustomText.isTimeRandom && CustomText.time < 1000) || (Config.mode === "custom" && !CustomText.isWordRandom && CustomText.text.length < 1000) ) { //ignore } else { if (TestLogic.active) { event.preventDefault(); // Chrome requires returnValue to be set. event.returnValue = ""; } } }); if (firebase.app().options.projectId === "monkey-type-dev-67af4") { $("#top .logo .bottom").text("monkey-dev"); $("head title").text("Monkey Dev"); $("body").append( `
DEV
DEV
` ); } if (window.location.hostname === "localhost") { window.onerror = function (error) { Notifications.add(error, -1); }; $("#top .logo .top").text("localhost"); $("head title").text($("head title").text() + " (localhost)"); firebase.functions().useFunctionsEmulator("http://localhost:5001"); $("body").append( `
local
local
` ); } ManualRestart.set(); let configLoadDone; let configLoadPromise = new Promise((v) => { configLoadDone = v; }); UpdateConfig.loadFromCookie(); configLoadDone(); Misc.getReleasesFromGitHub(); // getPatreonNames(); $(document).on("mouseenter", "#resultWordsHistory .words .word", (e) => { if (TestUI.resultVisible) { let input = $(e.currentTarget).attr("input"); if (input != undefined) $(e.currentTarget).append( `
${input .replace(/\t/g, "_") .replace(/\n/g, "_")}
` ); } }); $(document).on("click", "#bottom .leftright .right .current-theme", (e) => { if (e.shiftKey) { UpdateConfig.toggleCustomTheme(); } else { // if (Config.customTheme) { // toggleCustomTheme(); // } CommandlineLists.setCurrent(CommandlineLists.themeCommands); Commandline.show(); } }); $(document).on("click", ".keymap .r5 #KeySpace", (e) => { CommandlineLists.setCurrent(CommandlineLists.commandsKeymapLayouts); Commandline.show(); }); $(document).on("mouseleave", "#resultWordsHistory .words .word", (e) => { $(".wordInputAfter").remove(); }); $("#wpmChart").on("mouseleave", (e) => { $(".wordInputAfter").remove(); }); let mappedRoutes = { "/": "pageTest", "/login": "pageLogin", "/settings": "pageSettings", "/about": "pageAbout", "/account": "pageAccount", "/verify": "pageTest", }; function handleInitialPageClasses(el) { $(el).removeClass("hidden"); $(el).addClass("active"); } $(document).ready(() => { handleInitialPageClasses( $(".page." + mappedRoutes[window.location.pathname]) ); if (window.location.pathname === "/") { $("#top .config").removeClass("hidden"); } $("body").css("transition", ".25s"); if (Config.quickTab) { $("#restartTestButton").addClass("hidden"); } if (!Misc.getCookie("merchbannerclosed")) { $(".merchBanner").removeClass("hidden"); } else { $(".merchBanner").remove(); } $("#centerContent") .css("opacity", "0") .removeClass("hidden") .stop(true, true) .animate({ opacity: 1 }, 250, () => { if (window.location.pathname === "/verify") { const fragment = new URLSearchParams(window.location.hash.slice(1)); if (fragment.has("access_token")) { const accessToken = fragment.get("access_token"); const tokenType = fragment.get("token_type"); verifyUserWhenLoggedIn = { accessToken: accessToken, tokenType: tokenType, }; history.replaceState("/", null, "/"); } } else if (window.location.pathname === "/account") { // history.replaceState("/", null, "/"); } else if (/challenge_.+/g.test(window.location.pathname)) { //do nothing // } } else if (window.location.pathname !== "/") { let page = window.location.pathname.replace("/", ""); changePage(page); } }); settingsFillPromise.then(updateSettingsPage); }); $(".scrollToTopButton").click((event) => { window.scrollTo(0, 0); }); $(".merchBanner a").click((event) => { $(".merchBanner").remove(); Misc.setCookie("merchbannerclosed", true, 365); }); $(".merchBanner .fas").click((event) => { $(".merchBanner").remove(); Misc.setCookie("merchbannerclosed", true, 365); Notifications.add( "Won't remind you anymore. Thanks for continued support <3", 0, 5 ); }); $(".pageTest #copyWordsListButton").click(async (event) => { try { let words; if (Config.mode == "zen") { words = TestLogic.input.history.join(" "); } else { words = TestLogic.words .get() .slice(0, TestLogic.input.history.length) .join(" "); } await navigator.clipboard.writeText(words); Notifications.add("Copied to clipboard", 0, 2); } catch (e) { Notifications.add("Could not copy to clipboard: " + e, -1); } }); //stop space scrolling window.addEventListener("keydown", function (e) { if (e.keyCode == 32 && e.target == document.body) { e.preventDefault(); } });