`;
}
if (i === inputHistory.length - 1) {
//last word
let wordstats = {
correct: 0,
incorrect: 0,
missed: 0,
};
for (let c = 0; c < word.length; c++) {
if (c < inputHistory[i].length) {
//on char that still has a word list pair
if (inputHistory[i][c] == word[c]) {
wordstats.correct++;
} else {
wordstats.incorrect++;
}
} else {
//on char that is extra
wordstats.missed++;
}
}
if (wordstats.incorrect !== 0 || config.mode !== "time") {
if (input !== word) {
wordEl = `
`;
}
}
} else {
if (input !== word) {
wordEl = `
`;
}
}
let loop;
if (input.length > word.length) {
//input is longer - extra characters possible (loop over input)
loop = input.length;
} else {
//input is shorter or equal (loop over word list)
loop = word.length;
}
for (let c = 0; c < loop; c++) {
let correctedChar;
try {
correctedChar = correctedHistory[i][c];
} catch (e) {
correctedChar = undefined;
}
let extraCorrected = "";
if (
c + 1 === loop &&
correctedHistory[i] !== undefined &&
correctedHistory[i].length > input.length
) {
extraCorrected = "extraCorrected";
}
if (word[c] !== undefined) {
if (input[c] === word[c]) {
if (correctedChar === input[c] || correctedChar === undefined) {
wordEl += ``;
} else {
wordEl +=
`";
}
} else {
if (input[c] === currentInput) {
wordEl +=
`";
} else if (input[c] === undefined) {
wordEl += "" + word[c] + "";
} else {
wordEl +=
`";
}
}
} else {
wordEl += '";
}
}
wordEl += "
";
} catch (e) {
try {
wordEl = "
";
for (let c = 0; c < word.length; c++) {
wordEl += "" + word[c] + "";
}
wordEl += "
";
} catch {}
}
wordsHTML += wordEl;
}
$("#resultWordsHistory .words").html(wordsHTML);
$("#showWordHistoryButton").addClass("loaded");
return true;
}
function flipTestColors(tf) {
if (tf) {
$("#words").addClass("flipped");
} else {
$("#words").removeClass("flipped");
}
}
function applyColorfulMode(tc) {
if (tc) {
$("#words").addClass("colorfulMode");
} else {
$("#words").removeClass("colorfulMode");
}
}
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");
}
);
}
}
function updateTestModesNotice() {
let anim = false;
if ($(".pageTest #testModesNotice").text() === "") anim = true;
$(".pageTest #testModesNotice").empty();
if (sameWordset) {
$(".pageTest #testModesNotice").append(
`
repeated
`
);
}
if (textHasTab) {
$(".pageTest #testModesNotice").append(
`
shift + tab to restart
`
);
}
if (config.language === "english_1k" || config.language === "english_10k") {
$(".pageTest #testModesNotice").append(
`
${config.language.replace(
"_",
" "
)}
`
);
}
if (config.difficulty === "expert") {
$(".pageTest #testModesNotice").append(
`
expert
`
);
} else if (config.difficulty === "master") {
$(".pageTest #testModesNotice").append(
`
master
`
);
}
if (config.blindMode) {
$(".pageTest #testModesNotice").append(
`
blind
`
);
}
if (config.paceCaret !== "off") {
let speed = "";
try {
speed = ` (${Math.round(paceCaret.wpm)} wpm)`;
} catch {}
$(".pageTest #testModesNotice").append(
`
${
config.paceCaret === "average"
? "average"
: config.paceCaret === "pb"
? "pb"
: "custom"
} pace${speed}
`
);
}
if (config.minWpm !== "off") {
$(".pageTest #testModesNotice").append(
`
min ${config.minWpmCustomSpeed} wpm
`
);
}
if (config.minAcc !== "off") {
$(".pageTest #testModesNotice").append(
`
min ${config.minAccCustom}% acc
`
);
}
if (activeFunBox !== "none") {
$(".pageTest #testModesNotice").append(
`
${activeFunBox.replace(
/_/g,
" "
)}
`
);
}
if (config.confidenceMode === "on") {
$(".pageTest #testModesNotice").append(
`
confidence
`
);
}
if (config.confidenceMode === "max") {
$(".pageTest #testModesNotice").append(
`
max confidence
`
);
}
if (config.stopOnError != "off") {
$(".pageTest #testModesNotice").append(
`
stop on ${config.stopOnError}
`
);
}
if (config.layout !== "default") {
$(".pageTest #testModesNotice").append(
`
${config.layout}
`
);
}
let tagsString = "";
try {
db_getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
tagsString += tag.name + ", ";
}
});
if (tagsString !== "") {
$(".pageTest #testModesNotice").append(
`
${tagsString.substring(
0,
tagsString.length - 2
)}
`
);
}
} catch {}
if (anim) {
$(".pageTest #testModesNotice")
.css("transition", "none")
.css("opacity", 0)
.animate(
{
opacity: 1,
},
125,
() => {
$(".pageTest #testModesNotice").css("transition", ".125s");
}
);
}
}
$("#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) {
Misc.showNotification("Tag added", 2000);
db_getSnapshot().tags.push({
name: inputVal,
id: e.data.id,
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
Misc.showNotification("Invalid tag name", 3000);
} else if (status < -1) {
Misc.showNotification("Unknown error", 3000);
}
});
} 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) {
Misc.showNotification("Tag updated", 2000);
db_getSnapshot().tags.forEach((tag) => {
if (tag.id === tagid) {
tag.name = inputVal;
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
Misc.showNotification("Invalid tag name", 3000);
} else if (status < -1) {
Misc.showNotification("Unknown error", 3000);
}
});
} 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) {
Misc.showNotification("Tag removed", 2000);
db_getSnapshot().tags.forEach((tag, index) => {
if (tag.id === tagid) {
db_getSnapshot().tags.splice(index, 1);
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status < -1) {
Misc.showNotification("Unknown error", 3000);
}
});
}
}
function showCapsWarning() {
if ($("#capsWarning").hasClass("hidden")) {
$("#capsWarning").removeClass("hidden");
}
}
function hideCapsWarning() {
if (!$("#capsWarning").hasClass("hidden")) {
$("#capsWarning").addClass("hidden");
}
}
function showCustomTextPopup() {
if ($("#customTextPopupWrapper").hasClass("hidden")) {
if ($("#customTextPopup .check input").prop("checked")) {
$("#customTextPopup .inputs .wordcount").removeClass("hidden");
} else {
$("#customTextPopup .inputs .wordcount").addClass("hidden");
}
$("#customTextPopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, () => {
let newtext = customText.join(" ");
newtext = newtext.replace(/\n /g, "\n");
$("#customTextPopup textarea").val(newtext);
$("#customTextPopup .wordcount input").val(customTextWordCount);
$("#customTextPopup textarea").focus();
});
}
}
function hideCustomTextPopup() {
if (!$("#customTextPopupWrapper").hasClass("hidden")) {
$("#customTextPopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#customTextPopupWrapper").addClass("hidden");
}
);
}
}
$("#customTextPopupWrapper").mousedown((e) => {
if ($(e.target).attr("id") === "customTextPopupWrapper") {
hideCustomTextPopup();
}
});
$("#customTextPopup .inputs .check input").change(() => {
if ($("#customTextPopup .check input").prop("checked")) {
$("#customTextPopup .inputs .wordcount").removeClass("hidden");
} else {
$("#customTextPopup .inputs .wordcount").addClass("hidden");
}
});
$("#customTextPopup textarea").keypress((e) => {
if (e.code === "Enter" && e.ctrlKey) {
$("#customTextPopup .button").click();
}
});
$("#customTextPopup .button").click(() => {
let text = $("#customTextPopup textarea").val();
text = text.trim();
// text = text.replace(/[\r]/gm, " ");
text = text.replace(/\t/gm, "\t");
text = text.replace(/ +/gm, " ");
// text = text.replace(/(\r\n)+/g, "\r\n");
// text = text.replace(/(\n)+/g, "\n");
// text = text.replace(/(\r)+/g, "\r");
text = text.replace(/( *(\r\n|\r|\n) *)/g, "\n ");
if ($("#customTextPopup .typographyCheck input").prop("checked")) {
text = Misc.cleanTypographySymbols(text);
}
// text = Misc.remove_non_ascii(text);
text = text.replace(/[\u2060]/g, "");
text = text.split(" ");
customText = text;
customTextIsRandom = $("#customTextPopup .check input").prop("checked");
customTextWordCount = $("#customTextPopup .wordcount input").val();
manualRestart = true;
restartTest();
hideCustomTextPopup();
});
function showCustomMode2Popup(mode) {
if ($("#customMode2PopupWrapper").hasClass("hidden")) {
$("#customMode2PopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
if (mode == "time") {
$("#customMode2Popup .text").text("Test length");
$("#customMode2Popup").attr("mode", "time");
} else if (mode == "words") {
$("#customMode2Popup .text").text("Word amount");
$("#customMode2Popup").attr("mode", "words");
}
$("#customMode2Popup input").focus().select();
});
}
}
function hideCustomMode2Popup() {
if (!$("#customMode2PopupWrapper").hasClass("hidden")) {
$("#customMode2PopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#customMode2PopupWrapper").addClass("hidden");
}
);
}
}
function playClickSound() {
if (config.playSoundOnClick === "off") return;
if (clickSounds === null) initClickSounds();
let rand = Math.floor(
Math.random() * clickSounds[config.playSoundOnClick].length
);
let randomSound = clickSounds[config.playSoundOnClick][rand];
randomSound.counter++;
if (randomSound.counter === 2) randomSound.counter = 0;
randomSound.sounds[randomSound.counter].currentTime = 0;
randomSound.sounds[randomSound.counter].play();
}
function playErrorSound() {
if (!config.playSoundOnError) return;
errorSound.currentTime = 0;
errorSound.play();
}
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();
}
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 {
if (paceCaret.currentLetterIndex === -1) {
currentLetter = document
.querySelectorAll("#words .word")
[
paceCaret.currentWordIndex -
(currentWordIndex - currentWordElementIndex)
].querySelectorAll("letter")[0];
} else {
currentLetter = document
.querySelectorAll("#words .word")
[
paceCaret.currentWordIndex -
(currentWordIndex - currentWordElementIndex)
].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");
}
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();
}
});
$("#customMode2Popup input").keypress((e) => {
if (e.keyCode == 13) {
applyMode2Popup();
}
});
$("#customMode2Popup .button").click(() => {
applyMode2Popup();
});
function updateKeytips() {
if (config.swapEscAndTab) {
$(".pageSettings .tip").html(`
tip: You can also change all these settings quickly using the
command line (
tab
)`);
$("#bottom .keyTips").html(`
esc - restart test
tab - command line`);
} else {
$(".pageSettings .tip").html(`
tip: You can also change all these settings quickly using the
command line (
esc
)`);
$("#bottom .keyTips").html(`
tab - restart test
esc - command line`);
}
}
function applyMode2Popup() {
let mode = $("#customMode2Popup").attr("mode");
let val = parseInt($("#customMode2Popup input").val());
if (mode == "time") {
if (val !== null && !isNaN(val) && val >= 0) {
setTimeConfig(val);
manualRestart = true;
restartTest();
if (val >= 1800) {
Misc.showNotification("Stay safe and take breaks!", 3000);
} else if (val == 0) {
Misc.showNotification(
"Infinite time! Make sure to use Bail Out from the command line to save your result.",
5000
);
}
} else {
Misc.showNotification("Custom time must be at least 1", 3000);
}
} else if (mode == "words") {
if (val !== null && !isNaN(val) && val >= 0) {
setWordCount(val);
manualRestart = true;
restartTest();
if (val > 2000) {
Misc.showNotification("Stay safe and take breaks!", 3000);
} else if (val == 0) {
Misc.showNotification(
"Infinite words! Make sure to use Bail Out from the command line to save your result.",
5000
);
}
} else {
Misc.showNotification("Custom word amount must be at least 1", 3000);
}
}
hideCustomMode2Popup();
}
$(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") {
showCustomMode2Popup("words");
} else {
setWordCount(wrd);
manualRestart = true;
restartTest();
}
});
$(document).on("click", "#top .config .time .text-button", (e) => {
let mode = $(e.currentTarget).attr("timeConfig");
if (mode == "custom") {
showCustomMode2Popup("time");
} else {
setTimeConfig(mode);
manualRestart = true;
restartTest();
}
});
$(document).on("click", "#top .config .quoteLength .text-button", (e) => {
let len = $(e.currentTarget).attr("quoteLength");
setQuoteLength(len);
manualRestart = true;
restartTest();
});
$(document).on("click", "#top .config .customText .text-button", () => {
showCustomTextPopup();
});
$(document).on("click", "#top .config .punctuationMode .text-button", () => {
togglePunctuation();
manualRestart = true;
restartTest();
});
$(document).on("click", "#top .config .numbersMode .text-button", () => {
toggleNumbers();
manualRestart = true;
restartTest();
});
$("#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");
setMode(mode);
manualRestart = true;
restartTest();
});
$(document).on("click", "#top #menu .icon-button", (e) => {
if ($(e.currentTarget).hasClass("discord")) return;
if ($(e.currentTarget).hasClass("leaderboards")) {
showLeaderboards();
} else {
const href = $(e.currentTarget).attr("href");
manualRestart = true;
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 (
(config.mode === "words" && config.words < 1000) ||
(config.mode === "time" && config.time < 3600) ||
config.mode === "quote" ||
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
if (testActive) {
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++;
}
if (resultCalculating) return;
restartTest();
} else {
Misc.showNotification("Quick restart disabled for long tests", 2000);
}
}
});
$(document.body).on("click", "#restartTestButton", () => {
manualRestart = true;
if (resultCalculating) return;
restartTest();
});
function initPractiseMissedWords() {
let mode = modeBeforePractise === null ? config.mode : modeBeforePractise;
let punctuation =
punctuationBeforePractise === null
? config.punctuation
: punctuationBeforePractise;
let numbers =
numbersBeforePractise === null ? config.numbers : numbersBeforePractise;
setMode("custom");
let newCustomText = [];
Object.keys(missedWords).forEach((missedWord) => {
for (let i = 0; i < missedWords[missedWord]; i++) {
newCustomText.push(missedWord);
}
});
customText = newCustomText;
customTextIsRandom = true;
customTextWordCount = 50;
modeBeforePractise = null;
punctuationBeforePractise = null;
numbersBeforePractise = null;
restartTest();
modeBeforePractise = mode;
punctuationBeforePractise = punctuation;
numbersBeforePractise = numbers;
}
$(document).on("keypress", "#practiseMissedWordsButton", (event) => {
if (event.keyCode == 13) {
if (Object.keys(missedWords).length > 0) {
initPractiseMissedWords();
} else {
Misc.showNotification("You haven't missed any words.", 2000);
}
}
});
$(document.body).on("click", "#practiseMissedWordsButton", () => {
if (Object.keys(missedWords).length > 0) {
initPractiseMissedWords();
} else {
Misc.showNotification("You haven't missed any words.", 2000);
}
});
$(document).on("keypress", "#nextTestButton", (event) => {
if (event.keyCode == 13) {
restartTest();
}
});
$(document.body).on("click", "#nextTestButton", () => {
manualRestart = true;
restartTest();
});
$(document).on("keypress", "#showWordHistoryButton", (event) => {
if (event.keyCode == 13) {
toggleResultWordsDisplay();
}
});
$(document.body).on("click", "#showWordHistoryButton", () => {
toggleResultWordsDisplay();
});
$(document.body).on("click", "#restartTestButtonWithSameWordset", () => {
manualRestart = true;
restartTest(true);
});
$(document).on("keypress", "#restartTestButtonWithSameWordset", (event) => {
if (event.keyCode == 13) {
restartTest(true);
}
});
$(document.body).on("click", "#copyResultToClipboardButton", () => {
copyResultToClipboard();
});
$(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", () => {
currentCommands.push(commandsEnableAds);
showCommandLine();
$("#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", () => {
currentCommands.push(commandsEnableAds);
showCommandLine();
});
$("#wordsInput").keypress((event) => {
event.preventDefault();
});
let outOfFocusTimeouts = [];
function clearTimeouts(timeouts) {
timeouts.forEach((to) => {
clearTimeout(to);
to = null;
});
}
$("#wordsInput").on("focus", () => {
if (!resultVisible && config.showOutOfFocusWarning) {
$("#words").css("transition", "none").removeClass("blurred");
$(".outOfFocusWarning").addClass("hidden");
clearTimeouts(outOfFocusTimeouts);
}
showCaret();
});
$("#wordsInput").on("focusout", () => {
if (!resultVisible && config.showOutOfFocusWarning) {
outOfFocusTimeouts.push(
setTimeout(() => {
$("#words").css("transition", "0.25s").addClass("blurred");
$(".outOfFocusWarning").removeClass("hidden");
}, 1000)
);
}
hideCaret();
});
$(window).resize(() => {
updateCaretPosition();
});
$(document).mousemove(function (event) {
if (
$("#top").hasClass("focus") &&
(event.originalEvent.movementX > 0 || event.originalEvent.movementY > 0)
) {
setFocus(false);
}
});
$(document).on("click", "#testModesNotice .text-button", (event) => {
let commands = eval($(event.currentTarget).attr("commands"));
if (commands !== undefined) {
if ($(event.currentTarget).attr("commands") === "commandsTags") {
updateCommandsTagsList();
}
currentCommands.push(commands);
showCommandLine();
}
});
$(document).on("click", "#commandLineMobileButton", () => {
showCommandLine();
});
let dontInsertSpace = false;
$(document).keyup(() => {
if (resultVisible) return;
let now = performance.now();
let diff = Math.abs(keypressStats.duration.current - now);
if (keypressStats.duration.current !== -1) {
keypressStats.duration.array.push(diff);
}
keypressStats.duration.current = now;
Monkey.stop();
});
$(document).keydown(function (event) {
if (!resultVisible) {
let now = performance.now();
let diff = Math.abs(keypressStats.spacing.current - now);
if (keypressStats.spacing.current !== -1) {
keypressStats.spacing.array.push(diff);
}
keypressStats.spacing.current = now;
}
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");
if (
pageTestActive &&
!commandLineVisible &&
!modePopupVisible &&
!resultVisible &&
!wordsFocused &&
event.key !== "Enter"
) {
focusWords();
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();
try {
if (
!config.capsLockBackspace &&
event.originalEvent.getModifierState("CapsLock")
) {
showCapsWarning();
} else {
hideCapsWarning();
}
} catch {}
//backspace
const isBackspace =
event.key === "Backspace" ||
(config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace && wordsFocused) {
handleBackspace(event);
}
if (event.key === "Enter" && activeFunBox === "58008" && wordsFocused) {
event.key = " ";
}
//space or enter
if (event.key === " " && wordsFocused) {
handleSpace(event, false);
}
if (wordsFocused && !commandLineVisible) {
handleAlpha(event);
}
let acc = Misc.roundTo2(
(accuracyStats.correct /
(accuracyStats.correct + accuracyStats.incorrect)) *
100
);
updateLiveAcc(acc);
});
function handleTab(event) {
if (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 (
!event.ctrlKey &&
((!event.shiftKey && !textHasTab) ||
(event.shiftKey && textHasTab) ||
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" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
if (testActive) {
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++;
}
restartTest();
} else {
Misc.showNotification("Quick restart disabled for long tests", 2000);
}
} else {
changePage("test");
}
} else if (
!config.quickTab &&
textHasTab &&
event.shiftKey &&
!resultVisible
) {
event.preventDefault();
$("#restartTestButton").focus();
}
}
function handleBackspace(event) {
event.preventDefault();
if (!testActive) return;
if (
currentInput == "" &&
inputHistory.length > 0 &&
currentWordElementIndex > 0
) {
//if nothing is inputted and its not the first word
if (
(inputHistory[currentWordIndex - 1] == wordsList[currentWordIndex - 1] &&
!config.freedomMode) ||
$($(".word")[currentWordIndex - 1]).hasClass("hidden")
) {
return;
} else {
if (config.confidenceMode === "on" || config.confidenceMode === "max")
return;
if (event["ctrlKey"] || event["altKey"]) {
currentInput = "";
inputHistory.pop();
correctedHistory.pop();
} else {
currentInput = inputHistory.pop();
currentCorrected = correctedHistory.pop();
if (activeFunBox === "nospace") {
currentInput = currentInput.substring(0, currentInput.length - 1);
}
}
currentWordIndex--;
currentWordElementIndex--;
updateActiveElement();
updateWordElement(!config.blindMode);
}
} else {
if (config.confidenceMode === "max") return;
if (event["ctrlKey"] || event["altKey"]) {
let split = currentInput.replace(/ +/g, " ").split(" ");
if (split[split.length - 1] == "") {
split.pop();
}
let addspace = false;
if (split.length > 1) {
addspace = true;
}
split.pop();
currentInput = split.join(" ");
if (addspace) {
currentInput += " ";
}
} else if (event.metaKey) {
currentInput = "";
} else {
currentInput = currentInput.substring(0, currentInput.length - 1);
}
updateWordElement(!config.blindMode);
}
playClickSound();
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
updateCaretPosition();
}
function handleSpace(event, isEnter) {
if (!testActive) return;
if (currentInput === "") return;
let nextWord = wordsList[currentWordIndex + 1];
// if ((isEnter && nextWord !== "\n") && (isEnter && activeFunBox !== "58008")) return;
// if (!isEnter && nextWord === "\n") return;
event.preventDefault();
let currentWord = wordsList[currentWordIndex];
if (activeFunBox === "layoutfluid" && config.mode !== "time") {
const layouts = ["qwerty", "dvorak", "colemak"];
let index = 0;
let outof = wordsList.length;
index = Math.floor((inputHistory.length + 1) / (outof / 3));
if (config.layout !== layouts[index] && layouts[index] !== undefined) {
Misc.showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
}
setLayout(layouts[index]);
setKeymapLayout(layouts[index]);
updateHighlightedKeymapKey();
settingsGroups.layout.updateButton();
}
if (config.blindMode) $("#words .word.active letter").addClass("correct");
dontInsertSpace = true;
if (currentWord == currentInput) {
//correct word
if (
paceCaret !== null &&
paceCaret.wordsStatus[currentWordIndex] === true &&
!config.blindMode
) {
paceCaret.wordsStatus[currentWordIndex] = undefined;
paceCaret.correction -= currentWord.length + 1;
}
accuracyStats.correct++;
inputHistory.push(currentInput);
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
updateActiveElement();
updateCaretPosition();
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
if (activeFunBox !== "nospace") {
playClickSound();
}
} else {
//incorrect word
if (
paceCaret !== null &&
paceCaret.wordsStatus[currentWordIndex] === undefined &&
!config.blindMode
) {
paceCaret.wordsStatus[currentWordIndex] = true;
paceCaret.correction += currentWord.length + 1;
}
if (activeFunBox !== "nospace") {
if (!config.playSoundOnError || config.blindMode) {
playClickSound();
} else {
playErrorSound();
}
}
accuracyStats.incorrect++;
let cil = currentInput.length;
if (cil <= wordsList[currentWordIndex].length) {
if (cil >= currentCorrected.length) {
currentCorrected += "_";
} else {
currentCorrected =
currentCorrected.substring(0, cil) +
"_" +
currentCorrected.substring(cil + 1);
}
}
if (config.stopOnError != "off") {
if (config.difficulty == "expert" || config.difficulty == "master") {
//failed due to diff when pressing space
failTest();
return;
}
if (config.stopOnError == "word") {
currentInput += " ";
updateWordElement(true);
updateCaretPosition();
}
return;
}
inputHistory.push(currentInput);
highlightBadWord(currentWordElementIndex, !config.blindMode);
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
updateActiveElement();
updateCaretPosition();
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
if (config.difficulty == "expert" || config.difficulty == "master") {
failTest();
return;
} else if (currentWordIndex == wordsList.length) {
//submitted last word that is incorrect
lastSecondNotRound = true;
showResult();
return;
}
}
correctedHistory.push(currentCorrected);
currentCorrected = "";
if (!config.showAllLines || config.mode == "time") {
let currentTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordElementIndex - 1]
.offsetTop
);
let nextTop;
try {
nextTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordElementIndex]
.offsetTop
);
} catch (e) {
nextTop = 0;
}
if ((nextTop > currentTop || activeWordJumped) && !lineTransition) {
//last word of the line
if (currentTestLine > 0) {
let hideBound = currentTop;
if (activeWordJumped) {
hideBound = activeWordTopBeforeJump;
}
activeWordJumped = false;
let toHide = [];
let wordElements = $("#words .word");
for (let i = 0; i < currentWordElementIndex; i++) {
if ($(wordElements[i]).hasClass("hidden")) continue;
let forWordTop = Math.floor(wordElements[i].offsetTop);
if (forWordTop < hideBound - 10) {
toHide.push($($("#words .word")[i]));
}
}
const wordHeight = $(document.querySelector(".word")).outerHeight(true);
if (config.smoothLineScroll && toHide.length > 0) {
lineTransition = true;
$("#words").prepend(
`
`
);
$("#words .smoothScroller").animate(
{
height: 0,
},
125,
() => {
$("#words .smoothScroller").remove();
}
);
$("#paceCaret").animate(
{
top: document.querySelector("#paceCaret").offsetTop - wordHeight,
},
125
);
$("#words").animate(
{
marginTop: `-${wordHeight}px`,
},
125,
() => {
activeWordTop = document.querySelector("#words .active")
.offsetTop;
currentWordElementIndex -= toHide.length;
lineTransition = false;
toHide.forEach((el) => el.remove());
$("#words").css("marginTop", "0");
}
);
} else {
toHide.forEach((el) => el.remove());
currentWordElementIndex -= toHide.length;
$("#paceCaret").css({
top: document.querySelector("#paceCaret").offsetTop - wordHeight,
});
}
}
currentTestLine++;
}
} //end of line wrap
updateCaretPosition();
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
if (
config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote"
) {
updateTimer();
}
if (
config.mode == "time" ||
config.mode == "words" ||
config.mode == "custom"
) {
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",
undefined,
].includes(event.key)
) {
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 (!textHasTab || (textHasTab && event.shiftKey)) {
return;
}
event.key = "\t";
event.preventDefault();
}
if (event.key === "Enter") {
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 (
event.ctrlKey != event.altKey &&
(event.ctrlKey || /Linux/.test(window.navigator.platform))
)
return;
if (event.metaKey) return;
event = emulateLayout(event);
//start the test
if (currentInput == "" && inputHistory.length == 0 && !testActive) {
startTest();
} else {
if (!testActive) return;
}
setFocus(true);
stopCaretAnimation();
//show dead keys
if (event.key === "Dead") {
playClickSound();
$(
document.querySelector("#words .word.active").querySelectorAll("letter")[
currentInput.length
]
).toggleClass("dead");
return;
}
//check if the char typed was correct
let thisCharCorrect;
let nextCharInWord = wordsList[currentWordIndex].substring(
currentInput.length,
currentInput.length + 1
);
if (
config.language === "russian" &&
(event["key"].toLowerCase() == "e" || event["key"].toLowerCase() == "ё")
) {
if (
nextCharInWord.toLowerCase() == "e" ||
nextCharInWord.toLowerCase() == "ё"
) {
thisCharCorrect = true;
} else {
thisCharCorrect = false;
}
} else {
if (nextCharInWord == event["key"]) {
thisCharCorrect = true;
} else {
thisCharCorrect = false;
}
}
if (!thisCharCorrect) {
accuracyStats.incorrect++;
currentError.count++;
currentError.words.push(currentWordIndex);
thisCharCorrect = false;
if (!Object.keys(missedWords).includes(wordsList[currentWordIndex])) {
missedWords[wordsList[currentWordIndex]] = 1;
} else {
missedWords[wordsList[currentWordIndex]]++;
}
} else {
accuracyStats.correct++;
thisCharCorrect = true;
}
if (thisCharCorrect) {
playClickSound();
} else {
if (!config.playSoundOnError || config.blindMode) {
playClickSound();
} else {
playErrorSound();
}
}
//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 (currentCorrected === "") {
currentCorrected = currentInput + event["key"];
} else {
let cil = currentInput.length;
if (cil >= currentCorrected.length) {
currentCorrected += event["key"];
} else if (!thisCharCorrect) {
currentCorrected =
currentCorrected.substring(0, cil) +
event["key"] +
currentCorrected.substring(cil + 1);
}
}
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
if (config.stopOnError == "letter" && !thisCharCorrect) {
return;
}
//update the active word top, but only once
if (currentInput.length === 1 && currentWordIndex === 0) {
activeWordTop = document.querySelector("#words .active").offsetTop;
}
//max length of the input is 20
if (currentInput.length < wordsList[currentWordIndex].length + 20) {
currentInput += event["key"];
}
if (!thisCharCorrect && config.difficulty == "master") {
failTest();
return;
}
//keymap
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.key, thisCharCorrect);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
activeWordTopBeforeJump = activeWordTop;
updateWordElement(!config.blindMode);
//auto stop the test if the last word is correct
let currentWord = wordsList[currentWordIndex];
let lastindex = currentWordIndex;
if (
(currentWord == currentInput ||
(config.quickEnd &&
currentWord.length == currentInput.length &&
config.stopOnError == "off")) &&
lastindex == wordsList.length - 1
) {
inputHistory.push(currentInput);
currentInput = "";
correctedHistory.push(currentCorrected);
currentCorrected = "";
lastSecondNotRound = true;
showResult();
}
//simulate space press in nospace funbox
if (
(activeFunBox === "nospace" &&
currentInput.length === wordsList[currentWordIndex].length) ||
(event.key === "\n" && thisCharCorrect)
) {
$.event.trigger({
type: "keydown",
which: " ".charCodeAt(0),
key: " ",
});
}
//check if the word jumped
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
if (activeWordTopBeforeJump < newActiveTop && !lineTransition) {
activeWordJumped = true;
} else {
activeWordJumped = false;
}
//stop the word jump by slicing off the last character, update word again
if (activeWordJumped && currentInput.length > 1) {
currentInput = currentInput.slice(0, -1);
updateWordElement(!config.blindMode);
activeWordJumped = false;
}
updateCaretPosition();
}
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" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
} else {
if (testActive) {
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) {
Misc.showNotification(error, 3000);
};
$("#top .logo .top").text("localhost");
$("head title").text($("head title").text() + " (localhost)");
firebase.functions().useFunctionsEmulator("http://localhost:5001");
$("body").append(
`
local
local
`
);
}
manualRestart = true;
loadConfigFromCookie();
Misc.getReleasesFromGitHub();
// getPatreonNames();
$(document).on("mouseenter", "#resultWordsHistory .words .word", (e) => {
if (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) {
togglePresetCustomTheme();
} else {
// if (config.customTheme) {
// togglePresetCustomTheme();
// }
currentCommands.push(commandsThemes);
showCommandLine();
}
});
$(document).on("click", ".keymap .r5 #KeySpace", (e) => {
currentCommands.push(commandsKeymapLayouts);
showCommandLine();
});
$(document).on("mouseleave", "#resultWordsHistory .words .word", (e) => {
$(".wordInputAfter").remove();
});
$("#wpmChart").on("mouseleave", (e) => {
$(".wordInputAfter").remove();
});
$(document).ready(() => {
updateFavicon(32, 14);
$("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);
}
});
});
$(".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);
Misc.showNotification(
"Won't remind you anymore :) Thanks for continued support <3",
2500
);
});
$(".pageTest #copyWordsListButton").click(async (event) => {
try {
await navigator.clipboard.writeText(
wordsList.slice(0, inputHistory.length).join(" ")
);
Misc.showNotification("Copied to clipboard", 1000);
} catch (e) {
Misc.showNotification("Could not copy to clipboard: " + e, 5000);
}
});
//stop space scrolling
window.addEventListener("keydown", function (e) {
if (e.keyCode == 32 && e.target == document.body) {
e.preventDefault();
}
});
async function setupChallenge(challengeName) {
let list = await Misc.getChallengeList();
let challenge = list.filter((c) => c.name === challengeName)[0];
let notitext;
try {
if (challenge === undefined) {
throw "Challenge not found";
}
if (challenge.type === "customTime") {
setTimeConfig(challenge.parameters[0], true);
setMode("time", true);
setDifficulty("normal", true);
if (challenge.name === "englishMaster") {
setLanguage("english_10k", true);
setNumbers(true, true);
setPunctuation(true, true);
}
}
if (challenge.type === "customWords") {
setWordCount(challenge.parameters[0], true);
setMode("words", true);
setDifficulty("normal", true);
} else if (challenge.type === "customText") {
customText = challenge.parameters[0].split(" ");
customTextIsRandom = challenge.parameters[1];
customTextWordCount = challenge.parameters[2];
setMode("custom", true);
setDifficulty("normal", true);
} else if (challenge.type === "script") {
let scriptdata = await fetch("/challenges/" + challenge.parameters[0]);
scriptdata = await scriptdata.text();
let text = scriptdata.trim();
text = text.replace(/[\n\r\t ]/gm, " ");
text = text.replace(/ +/gm, " ");
customText = text.split(" ");
customTextIsRandom = false;
setMode("custom", true);
setDifficulty("normal", true);
if (challenge.parameters[1] != null) {
setTheme(challenge.parameters[1]);
}
if (challenge.parameters[2] != null) {
activateFunbox(challenge.parameters[2]);
}
} else if (challenge.type === "accuracy") {
setTimeConfig(0, true);
setMode("time", true);
setDifficulty("master", true);
} else if (challenge.type === "funbox") {
activateFunbox(challenge.parameters[0]);
setDifficulty("normal", true);
if (challenge.parameters[1] === "words") {
setWordCount(challenge.parameters[2], true);
} else if (challenge.parameters[1] === "time") {
setTimeConfig(challenge.parameters[2], true);
}
setMode(challenge.parameters[1], true);
if (challenge.parameters[3] !== undefined) {
setDifficulty(challenge.parameters[3], true);
}
}
manualRestart = true;
restartTest(false, true);
notitext = challenge.message;
if (notitext === undefined) {
Misc.showNotification(`Challenge '${challengeName}' loaded.`, 3000);
} else {
Misc.showNotification("Challenge loaded. " + notitext, 5000);
}
} catch (e) {
Misc.showNotification("Something went wrong: " + e, 5000);
console.log(e);
}
// Misc.showNotification("Challenge loaded", 2000);
}
let ctx = $("#wpmChart");
let wpmOverTimeChart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "wpm",
data: [],
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "wpm",
order: 2,
radius: 2,
},
{
label: "raw",
data: [],
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "raw",
order: 3,
radius: 2,
},
{
label: "errors",
data: [],
borderColor: "rgba(255, 125, 125, 1)",
pointBackgroundColor: "rgba(255, 125, 125, 1)",
borderWidth: 2,
order: 1,
yAxisID: "error",
maxBarThickness: 10,
type: "scatter",
pointStyle: "crossRot",
radius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value <= 0 ? 0 : 3;
},
pointHoverRadius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value <= 0 ? 0 : 5;
},
},
],
},
options: {
tooltips: {
titleFontFamily: "Roboto Mono",
bodyFontFamily: "Roboto Mono",
mode: "index",
intersect: false,
callbacks: {
afterLabel: function (ti, data) {
try {
$(".wordInputAfter").remove();
let wordsToHighlight =
keypressPerSecond[parseInt(ti.xLabel) - 1].words;
let unique = [...new Set(wordsToHighlight)];
unique.forEach((wordIndex) => {
let wordEl = $($("#resultWordsHistory .words .word")[wordIndex]);
let input = wordEl.attr("input");
if (input != undefined)
wordEl.append(`
${input}
`);
});
} catch (e) {}
},
},
},
legend: {
display: false,
labels: {
defaultFontFamily: "Roboto Mono",
},
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
ticks: {
fontFamily: "Roboto Mono",
autoSkip: true,
autoSkipPadding: 40,
},
display: true,
scaleLabel: {
display: false,
labelString: "Seconds",
fontFamily: "Roboto Mono",
},
},
],
yAxes: [
{
id: "wpm",
display: true,
scaleLabel: {
display: true,
labelString: "Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: true,
},
},
{
id: "raw",
display: false,
scaleLabel: {
display: true,
labelString: "Raw Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
{
id: "error",
display: true,
position: "right",
scaleLabel: {
display: true,
labelString: "Errors",
fontFamily: "Roboto Mono",
},
ticks: {
precision: 0,
fontFamily: "Roboto Mono",
beginAtZero: true,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
],
},
annotation: {
annotations: [],
},
},
});