monkeytype/public/js/script.js

3687 lines
101 KiB
JavaScript
Raw Normal View History

2020-05-09 08:29:47 +08:00
let wordsList = [];
let currentWordIndex = 0;
let currentWordElementIndex = 0;
2020-05-09 08:29:47 +08:00
let inputHistory = [];
let currentInput = "";
let time = 0;
let timers = [];
2020-05-09 08:29:47 +08:00
let testActive = false;
let testStart, testEnd;
let wpmHistory = [];
let rawHistory = [];
let restartCount = 0;
let incompleteTestSeconds = 0;
let currentTestLine = 0;
let pageTransition = false;
2020-05-23 23:29:36 +08:00
let keypressPerSecond = [];
let currentKeypressCount = 0;
let afkDetected = false;
let errorsPerSecond = [];
let currentErrorCount = 0;
let resultVisible = false;
let activeWordTopBeforeJump = 0;
let activeWordTop = 0;
let activeWordJumped = false;
let sameWordset = false;
2020-07-03 07:01:46 +08:00
let quotes = [];
2020-07-13 06:53:15 +08:00
let focusState = false;
2020-07-31 08:33:17 +08:00
let activeFunBox = "none";
2020-05-09 08:29:47 +08:00
let themeColors = {
bg: "#323437",
main: "#e2b714",
caret: "#e2b714",
sub: "#646669",
text: "#d1d0c5",
error: "#ca4754",
errorExtra: "#7e2a33",
colorfulError: "#ca4754",
colorfulErrorExtra: "#7e2a33",
};
let accuracyStats = {
correct: 0,
2020-07-03 08:35:45 +08:00
incorrect: 0,
};
2020-07-06 07:05:42 +08:00
let keypressStats = {
spacing: {
current: -1,
array: [],
},
duration: {
current: -1,
array: [],
},
};
2020-07-03 08:35:45 +08:00
let customText = "The quick brown fox jumps over the lazy dog".split(" ");
let customTextIsRandom = false;
let customTextWordCount = 1;
2020-07-03 07:01:46 +08:00
let randomQuote = null;
2020-05-09 08:29:47 +08:00
2020-07-03 08:35:45 +08:00
const testCompleted = firebase.functions().httpsCallable("testCompleted");
const addTag = firebase.functions().httpsCallable("addTag");
const editTag = firebase.functions().httpsCallable("editTag");
const removeTag = firebase.functions().httpsCallable("removeTag");
const updateResultTags = firebase.functions().httpsCallable("updateResultTags");
const saveConfig = firebase.functions().httpsCallable("saveConfig");
const generatePairingCode = firebase
.functions()
.httpsCallable("generatePairingCode");
2020-07-03 07:01:46 +08:00
function smooth(arr, windowSize, getter = (value) => value, setter) {
2020-07-03 08:35:45 +08:00
const get = getter;
const result = [];
2020-07-03 07:01:46 +08:00
for (let i = 0; i < arr.length; i += 1) {
2020-07-03 08:35:45 +08:00
const leftOffeset = i - windowSize;
const from = leftOffeset >= 0 ? leftOffeset : 0;
const to = i + windowSize + 1;
2020-07-03 07:01:46 +08:00
2020-07-03 08:35:45 +08:00
let count = 0;
let sum = 0;
2020-07-03 07:01:46 +08:00
for (let j = from; j < to && j < arr.length; j += 1) {
2020-07-03 08:35:45 +08:00
sum += get(arr[j]);
count += 1;
2020-06-25 08:30:58 +08:00
}
2020-07-03 07:01:46 +08:00
2020-07-03 08:35:45 +08:00
result[i] = setter ? setter(arr[i], sum / count) : sum / count;
2020-06-25 08:30:58 +08:00
}
2020-07-03 08:35:45 +08:00
return result;
2020-07-03 07:01:46 +08:00
}
function stdDev(array) {
try {
const n = array.length;
const mean = array.reduce((a, b) => a + b) / n;
return Math.sqrt(
array.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
);
} catch (e) {
return 0;
}
}
function mean(array) {
try {
return (
array.reduce((previous, current) => (current += previous)) / array.length
);
} catch (e) {
return 0;
}
}
function refreshThemeColorObject() {
let st = getComputedStyle(document.body);
themeColors.bg = st.getPropertyValue("--bg-color").replace(" ", "");
themeColors.main = st.getPropertyValue("--main-color").replace(" ", "");
themeColors.caret = st.getPropertyValue("--caret-color").replace(" ", "");
themeColors.sub = st.getPropertyValue("--sub-color").replace(" ", "");
themeColors.text = st.getPropertyValue("--text-color").replace(" ", "");
themeColors.error = st.getPropertyValue("--error-color").replace(" ", "");
themeColors.errorExtra = st
.getPropertyValue("--error-extra-color")
.replace(" ", "");
themeColors.colorfulError = st
.getPropertyValue("--colorful-error-color")
.replace(" ", "");
themeColors.colorfulErrorExtra = st
.getPropertyValue("--colorful-error-extra-color")
.replace(" ", "");
}
function showNotification(text, time) {
let noti = $(".notification");
noti.text(text);
2020-07-03 08:35:45 +08:00
noti.css("top", `-${noti.outerHeight()}px`);
noti.stop(true, true).animate(
{
top: "1rem",
},
250,
"swing",
() => {
noti.stop(true, true).animate(
{
opacity: 1,
},
time,
() => {
noti.stop(true, true).animate(
{
top: `-${noti.outerHeight()}px`,
},
250,
"swing"
);
}
);
}
);
}
function copyResultToClipboard() {
2020-07-03 08:35:45 +08:00
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
showNotification("Sorry, this feature is not supported in Firefox", 4000);
2020-07-03 07:01:46 +08:00
} else {
2020-07-29 01:44:36 +08:00
$(".pageTest .ssWatermark").removeClass("hidden");
$(".pageTest .buttons").addClass("hidden");
2020-07-03 08:35:45 +08:00
let src = $("#middle");
var sourceX = src.position().left; /*X position from div#target*/
var sourceY = src.position().top; /*Y position from div#target*/
var sourceWidth = src.width(); /*clientWidth/offsetWidth from div#target*/
var sourceHeight = src.height(); /*clientHeight/offsetHeight from div#target*/
2020-07-03 07:01:46 +08:00
try {
html2canvas(document.body, {
backgroundColor: themeColors.bg,
2020-06-15 08:45:05 +08:00
height: sourceHeight + 50,
width: sourceWidth + 50,
x: sourceX - 25,
2020-07-03 08:35:45 +08:00
y: sourceY - 25,
2020-07-03 07:01:46 +08:00
}).then(function (canvas) {
2020-06-15 08:45:05 +08:00
// document.body.appendChild(canvas);
2020-07-03 07:01:46 +08:00
canvas.toBlob(function (blob) {
2020-07-03 08:35:45 +08:00
navigator.clipboard
.write([
new ClipboardItem(
Object.defineProperty({}, blob.type, {
value: blob,
enumerable: true,
})
),
])
.then((f) => {
showNotification("Copied to clipboard", 1000);
2020-07-29 01:44:36 +08:00
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
2020-07-03 08:35:45 +08:00
})
.catch((f) => {
showNotification("Error saving image to clipboard", 2000);
2020-07-29 01:44:36 +08:00
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
2020-07-03 08:35:45 +08:00
});
2020-06-15 08:45:05 +08:00
});
});
2020-07-03 07:01:46 +08:00
} catch (e) {
2020-07-03 08:35:45 +08:00
showNotification("Error creating image", 2000);
2020-07-29 01:44:36 +08:00
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
}
2020-06-15 08:45:05 +08:00
}
2020-05-09 08:29:47 +08:00
}
2020-07-31 08:33:17 +08:00
function activateFunbox(funbox, mode) {
2020-07-31 08:46:00 +08:00
if (funbox === "none") {
$("#funBoxTheme").attr("href", ``);
activeFunBox = "none";
}
2020-07-31 08:33:17 +08:00
if (mode === "style") {
if (funbox == undefined) {
$("#funBoxTheme").attr("href", ``);
activeFunBox = "none";
} else {
$("#funBoxTheme").attr("href", `funbox/${funbox}.css`);
activeFunBox = funbox;
}
if (funbox === "simon_says") {
setActiveKeymapModeButton();
restartTest();
}
} else if (mode === "script") {
if (funbox === "tts") {
$("#funBoxTheme").attr("href", `funbox/simon_says.css`);
config.keymapMode = "off";
setActiveKeymapModeButton();
restartTest();
}
activeFunBox = funbox;
}
}
function toggleScriptFunbox(...params) {
if (activeFunBox === "tts") {
var msg = new SpeechSynthesisUtterance();
2020-08-02 00:22:49 +08:00
// var voices = window.speechSynthesis.getVoices();
// msg.voice = voices[0];
// msg.volume = 1; // From 0 to 1
// msg.rate = 1; // From 0.1 to 10
2020-07-31 08:33:17 +08:00
msg.text = params[0];
2020-08-02 00:22:49 +08:00
msg.lang = "en-US";
window.speechSynthesis.cancel();
window.speechSynthesis.speak(msg);
2020-07-31 08:33:17 +08:00
}
}
function getReleasesFromGitHub() {
2020-07-03 08:35:45 +08:00
$.getJSON(
"https://api.github.com/repos/Miodec/monkey-type/releases",
(data) => {
$("#bottom .version").text(data[0].name).css("opacity", 1);
$("#versionHistory .releases").empty();
data.forEach((release) => {
if (!release.draft && !release.prerelease) {
$("#versionHistory .releases").append(`
<div class="release">
<div class="title">${release.name}</div>
2020-07-03 08:35:45 +08:00
<div class="date">${moment(release.published_at).format(
"DD MMM YYYY"
)}</div>
<div class="body">${release.body.replace(/\r\n/g, "<br>")}</div>
</div>
`);
2020-07-03 08:35:45 +08:00
}
});
}
);
}
2020-07-03 07:01:46 +08:00
function verifyUsername() {
// test = firebase.functions().httpsCallable('moveResults')
// test2 = firebase.functions().httpsCallable('getNames')
// test3 = firebase.functions().httpsCallable('checkNameAvailability')
2020-07-03 08:35:45 +08:00
const check = firebase.functions().httpsCallable("checkIfNeedsToChangeName");
check({ uid: firebase.auth().currentUser.uid }).then((data) => {
2020-07-03 07:01:46 +08:00
if (data.data === 1) {
2020-07-03 08:35:45 +08:00
$(".nameChangeMessage").slideDown();
2020-07-03 07:01:46 +08:00
} else if (data.data === 2) {
2020-07-03 08:35:45 +08:00
$(".nameChangeMessage").slideDown();
}
2020-07-03 08:35:45 +08:00
});
2020-07-03 08:35:45 +08:00
$(".nameChangeMessage").click((e) => {
alert(`Im currently preparing the system to be ready for leaderboards and other awesome features - it looks like you need to change your display name.
2020-08-01 09:53:04 +08:00
It either contains special characters, or your display name is the same as someone elses and your account was made later.
2020-08-01 09:53:04 +08:00
Sorry for this inconvenience.
`);
2020-07-03 08:35:45 +08:00
let newName = prompt(
"Please provide a new username - you can use lowercase and uppercase characters, numbers and one of these special characters ( . _ - ). The new name cannot be longer than 12 characters.",
firebase.auth().currentUser.displayName
);
2020-07-03 07:01:46 +08:00
if (newName) {
2020-07-03 08:35:45 +08:00
cn = firebase.functions().httpsCallable("changeName");
cn({ uid: firebase.auth().currentUser.uid, name: newName }).then((d) => {
2020-07-03 07:01:46 +08:00
if (d.data === 1) {
//all good
2020-07-03 08:35:45 +08:00
alert("Thanks! All good.");
location.reload();
2020-07-03 08:35:45 +08:00
$(".nameChangeMessage").slideUp();
2020-07-03 07:01:46 +08:00
} else if (d.data === 0) {
//invalid or unavailable
2020-07-03 08:35:45 +08:00
alert("Name invalid or taken. Try again.");
2020-07-03 07:01:46 +08:00
} else if (d.data === -1) {
//error
2020-07-03 08:35:45 +08:00
alert("Unknown error. Contact Miodec on Discord.");
}
});
}
2020-07-03 08:35:45 +08:00
});
}
2020-07-12 00:03:25 +08:00
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!");
}
2020-05-11 07:32:10 +08:00
function getLastChar(word) {
return word.charAt(word.length - 1);
}
2020-05-09 08:29:47 +08:00
function setFocus(foc) {
2020-07-13 06:53:15 +08:00
if (foc && !focusState) {
focusState = true;
stopCaretAnimation();
2020-05-09 08:29:47 +08:00
$("#top").addClass("focus");
$("#bottom").addClass("focus");
$("body").css("cursor", "none");
$("#middle").addClass("focus");
2020-07-13 06:53:15 +08:00
} else if (!foc && focusState) {
focusState = false;
2020-05-09 08:29:47 +08:00
startCaretAnimation();
$("#top").removeClass("focus");
$("#bottom").removeClass("focus");
$("body").css("cursor", "default");
$("#middle").removeClass("focus");
2020-05-09 08:29:47 +08:00
}
}
function capitalizeFirstLetter(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
2020-07-03 07:01:46 +08:00
function roundedToFixed(float, digits) {
let rounded = Math.pow(10, digits);
return (Math.round(float * rounded) / rounded).toFixed(digits);
}
2020-05-09 08:29:47 +08:00
function initWords() {
testActive = false;
wordsList = [];
currentWordIndex = 0;
currentWordElementIndex = 0;
accuracyStats = {
correct: 0,
2020-07-03 08:35:45 +08:00
incorrect: 0,
};
2020-05-09 08:29:47 +08:00
inputHistory = [];
currentInput = "";
2020-05-16 21:57:01 +08:00
let language = words[config.language];
2020-07-03 07:01:46 +08:00
if (language === undefined && config.language === "english_10k") {
2020-06-29 06:16:28 +08:00
showBackgroundLoader();
$.ajax({
url: "js/english_10k.json",
async: false,
success: function (data) {
hideBackgroundLoader();
2020-07-03 08:35:45 +08:00
words["english_10k"] = data;
language = words[config.language];
2020-07-03 08:35:45 +08:00
},
});
2020-06-29 06:16:28 +08:00
}
2020-05-16 21:57:01 +08:00
2020-07-03 07:01:46 +08:00
if (config.mode === "quote") {
showBackgroundLoader();
$.ajax({
url: "js/english_quotes.json",
async: false,
success: function (data) {
hideBackgroundLoader();
quotes = data;
2020-07-03 08:35:45 +08:00
},
});
2020-07-03 07:01:46 +08:00
}
2020-05-16 21:57:01 +08:00
if (language == undefined || language == []) {
config.language = "english";
language = words[config.language];
2020-05-16 21:57:01 +08:00
}
if (
config.mode == "time" ||
config.mode == "words" ||
(config.mode == "custom" && customTextIsRandom)
) {
// let wordsBound = config.mode == "time" ? 60 : config.words;
let wordsBound = 60;
if (config.showAllLines) {
if (config.mode === "custom") {
wordsBound = customTextWordCount;
} else if (config.mode != "time") {
wordsBound = config.words;
}
} else {
if (config.mode === "words" && config.words < wordsBound) {
wordsBound = config.words;
}
if (config.mode == "custom" && customTextWordCount < wordsBound) {
wordsBound = customTextWordCount;
}
}
let wordset = language;
if (config.mode == "custom") {
wordset = customText;
}
for (let i = 0; i < wordsBound; i++) {
randomWord = wordset[Math.floor(Math.random() * wordset.length)];
2020-05-09 08:29:47 +08:00
previousWord = wordsList[i - 1];
previousWord2 = wordsList[i - 2];
2020-07-25 22:32:21 +08:00
if (config.mode == "custom" && wordset.length < 3) {
randomWord = wordset[Math.floor(Math.random() * wordset.length)];
2020-07-25 22:32:21 +08:00
} else {
while (
randomWord == previousWord ||
randomWord == previousWord2 ||
(!config.punctuation && randomWord == "I") ||
randomWord.indexOf(" ") > -1
) {
randomWord = wordset[Math.floor(Math.random() * wordset.length)];
}
2020-05-09 08:29:47 +08:00
}
2020-07-03 07:01:46 +08:00
if (config.punctuation && config.mode != "custom") {
randomWord = punctuateWord(previousWord, randomWord, i, wordsBound);
}
wordsList.push(randomWord);
2020-05-09 08:29:47 +08:00
}
} else if (config.mode == "custom") {
2020-07-01 05:23:50 +08:00
// let w = customText.split(" ");
for (let i = 0; i < customText.length; i++) {
wordsList.push(customText[i]);
2020-05-09 08:29:47 +08:00
}
2020-07-03 07:01:46 +08:00
} else if (config.mode == "quote") {
2020-07-22 07:24:39 +08:00
randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
let w = randomQuote.text.trim().split(" ");
2020-07-03 07:01:46 +08:00
for (let i = 0; i < w.length; i++) {
wordsList.push(w[i]);
}
2020-05-09 08:29:47 +08:00
}
showWords();
}
2020-07-03 07:01:46 +08:00
function emulateLayout(event) {
2020-07-03 08:35:45 +08:00
if (config.layout == "default" || event.key === " ") return event;
const qwertyMasterLayout = {
Backquote: "`~",
Digit1: "1!",
Digit2: "2@",
Digit3: "3#",
Digit4: "4$",
Digit5: "5%",
Digit6: "6^",
Digit7: "7&",
Digit8: "8*",
Digit9: "9(",
Digit0: "0)",
Minus: "-_",
Equal: "=+",
KeyQ: "qQ",
KeyW: "wW",
KeyE: "eE",
KeyR: "rR",
KeyT: "tT",
KeyY: "yY",
KeyU: "uU",
KeyI: "iI",
KeyO: "oO",
KeyP: "pP",
BracketLeft: "[{",
BracketRight: "]}",
KeyA: "aA",
KeyS: "sS",
KeyD: "dD",
KeyF: "fF",
KeyG: "gG",
KeyH: "hH",
KeyJ: "jJ",
KeyK: "kK",
KeyL: "lL",
Semicolon: ";:",
Quote: "'\"",
Backslash: "\\|",
KeyZ: "zZ",
KeyX: "xX",
KeyC: "cC",
KeyV: "vV",
KeyB: "bB",
KeyN: "nN",
KeyM: "mM",
Comma: ",<",
Period: ".>",
Slash: "/?",
Space: " ",
};
2020-06-04 00:10:14 +08:00
let layoutMap = layouts[config.layout];
let qwertyMap = layouts["qwerty"];
let qwertyKey = qwertyMasterLayout[event.code];
2020-06-04 00:10:14 +08:00
let mapIndex;
let newKey;
let shift = event.shiftKey ? 1 : 0;
2020-06-04 00:10:14 +08:00
for (let i = 0; i < qwertyMap.length; i++) {
const key = qwertyMap[i];
let keyIndex = key.indexOf(qwertyKey);
2020-07-03 07:01:46 +08:00
if (keyIndex != -1) {
2020-06-04 00:10:14 +08:00
mapIndex = i;
}
}
2020-07-03 07:01:46 +08:00
if (!shift && /[A-Z]/gm.test(event.key)) {
shift = 1;
}
2020-06-04 00:10:14 +08:00
newKey = layoutMap[mapIndex][shift];
event.keyCode = newKey.charCodeAt(0);
event.charCode = newKey.charCodeAt(0);
event.which = newKey.charCodeAt(0);
event.key = newKey;
event.code = "Key" + newKey.toUpperCase();
2020-06-04 00:10:14 +08:00
return event;
}
2020-07-03 07:01:46 +08:00
function punctuateWord(previousWord, currentWord, index, maxindex) {
let word = currentWord;
2020-07-03 08:35:45 +08:00
if (
index == 0 ||
getLastChar(previousWord) == "." ||
getLastChar(previousWord) == "?" ||
getLastChar(previousWord) == "!"
) {
//always capitalise the first word or if there was a dot
word = capitalizeFirstLetter(word);
} else if (
//10% chance to end a sentence
2020-07-03 08:35:45 +08:00
(Math.random() < 0.1 &&
getLastChar(previousWord) != "." &&
index != maxindex - 2) ||
index == maxindex - 1
) {
let rand = Math.random();
if (rand <= 0.8) {
word += ".";
2020-07-03 08:35:45 +08:00
} else if (rand > 0.8 && rand < 0.9) {
word += "?";
} else {
word += "!";
}
2020-07-03 08:35:45 +08:00
} else if (
Math.random() < 0.01 &&
getLastChar(previousWord) != "," &&
2020-07-03 08:35:45 +08:00
getLastChar(previousWord) != "."
) {
//1% chance to add quotes
word = `"${word}"`;
} else if (Math.random() < 0.01) {
//1% chance to add a colon
word = word + ":";
} else if (
Math.random() < 0.01 &&
getLastChar(previousWord) != "," &&
getLastChar(previousWord) != "." &&
previousWord != "-"
) {
//1% chance to add a dash
word = "-";
2020-07-03 08:35:45 +08:00
} else if (Math.random() < 0.2 && getLastChar(previousWord) != ",") {
//2% chance to add a comma
word += ",";
}
return word;
}
2020-05-09 08:29:47 +08:00
function addWord() {
if (
!config.showAllLines &&
(wordsList.length - inputHistory.length > 60 ||
(config.mode === "words" && wordsList.length >= config.words) ||
(config.mode === "custom" && wordsList.length >= customTextWordCount))
)
return;
let language = words[config.language];
if (config.mode == "custom") {
language = customText;
}
let randomWord = language[Math.floor(Math.random() * language.length)];
previousWord = wordsList[wordsList.length - 1];
2020-07-03 08:35:45 +08:00
previousWordStripped = previousWord.replace(/[.?!":\-,]/g, "").toLowerCase();
previousWord2Stripped = wordsList[wordsList.length - 2]
.replace(/[.?!":\-,]/g, "")
.toLowerCase();
if (config.mode == "custom" && language.length < 3) {
randomWord = language[Math.floor(Math.random() * language.length)];
} else {
while (
previousWordStripped == randomWord ||
previousWord2Stripped == randomWord ||
randomWord.indexOf(" ") > -1 ||
(!config.punctuation && randomWord == "I")
) {
randomWord = language[Math.floor(Math.random() * language.length)];
}
}
2020-07-03 07:01:46 +08:00
if (config.punctuation && config.mode != "custom") {
2020-07-03 08:35:45 +08:00
randomWord = punctuateWord(previousWord, randomWord, wordsList.length, 0);
}
2020-05-09 08:29:47 +08:00
wordsList.push(randomWord);
2020-05-09 08:29:47 +08:00
let w = "<div class='word'>";
for (let c = 0; c < randomWord.length; c++) {
w += "<letter>" + randomWord.charAt(c) + "</letter>";
}
w += "</div>";
$("#words").append(w);
}
function showWords() {
$("#words").empty();
for (let i = 0; i < wordsList.length; i++) {
let w = "<div class='word'>";
for (let c = 0; c < wordsList[i].length; c++) {
w += "<letter>" + wordsList[i].charAt(c) + "</letter>";
2020-05-09 08:29:47 +08:00
}
w += "</div>";
$("#words").append(w);
}
$("#words").removeClass("hidden");
if (config.showAllLines && config.mode != "time") {
$("#words").css("height", "auto");
} else {
const wordHeight = $($(".word")[0]).outerHeight(true);
$("#words")
.css("height", wordHeight * 3 + "px")
.css("overflow", "hidden");
}
// if ($(".active-key") != undefined) {
// $(".active-key").removeClass("active-key");
// }
var currentKey = wordsList[currentWordIndex]
.substring(currentInput.length, currentInput.length + 1)
.toString()
.toUpperCase();
// var highlightKey = `#Key${currentKey}`;
// $(highlightKey).addClass("active-key");
if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
2020-05-09 08:29:47 +08:00
updateActiveElement();
updateCaretPosition();
// if (config.keymap !== "off") {
// changeKeymapLayout(config.keymapLayout);
// }
2020-05-09 08:29:47 +08:00
}
function updateActiveElement() {
2020-07-13 06:53:15 +08:00
let active = document.querySelector("#words .active");
if (active !== null) {
active.classList.remove("active");
}
// $("#words .word").removeClass("active");
// $($("#words .word")[currentWordIndex]).addClass("active").removeClass("error");
// document.querySelectorAll("#words .word")[currentWordIndex].classList.add("active");
try {
let activeWord = document.querySelectorAll("#words .word")[
currentWordElementIndex
2020-07-13 06:53:15 +08:00
];
activeWord.classList.add("active");
activeWord.classList.remove("error");
// activeWordTop = $("#words .word.active").position().top;
activeWordTop = document.querySelector("#words .active").offsetTop;
// updateHighlightedKeymapKey();
2020-07-13 06:53:15 +08:00
} catch (e) {}
2020-07-31 08:33:17 +08:00
toggleScriptFunbox(wordsList[currentWordIndex]);
2020-05-09 08:29:47 +08:00
}
function compareInput(showError) {
2020-07-13 06:53:15 +08:00
// let wrdAtIndex = $("#words .word")[wrdIndex];
let input = currentInput;
2020-07-13 06:53:15 +08:00
let wordAtIndex;
let currentWord;
wordAtIndex = document.querySelector("#words .word.active");
currentWord = wordsList[currentWordIndex];
2020-07-13 06:53:15 +08:00
// while (wordAtIndex.firstChild) {
// wordAtIndex.removeChild(wordAtIndex.firstChild);
// }
2020-05-11 07:32:10 +08:00
let ret = "";
2020-07-13 06:53:15 +08:00
for (let i = 0; i < input.length; i++) {
if (currentWord[i] == input[i]) {
2020-05-11 07:32:10 +08:00
ret += '<letter class="correct">' + currentWord[i] + "</letter>";
// $(letterElems[i]).removeClass('incorrect').addClass('correct');
} else {
2020-07-03 07:01:46 +08:00
if (config.difficulty == "master") {
2020-07-23 20:48:04 +08:00
if (!resultVisible) {
inputHistory.push(currentInput);
document
.querySelector("#words .word.active")
.setAttribute("input", currentInput);
showResult(true);
}
2020-07-03 07:01:46 +08:00
if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
}
2020-07-03 07:01:46 +08:00
if (!showError) {
2020-05-30 20:15:00 +08:00
if (currentWord[i] == undefined) {
// ret += '<letter class="correct">' + input[i] + "</letter>";
2020-05-30 20:15:00 +08:00
} else {
ret += '<letter class="correct">' + currentWord[i] + "</letter>";
}
2020-07-03 07:01:46 +08:00
} else {
2020-05-30 20:15:00 +08:00
if (currentWord[i] == undefined) {
ret += '<letter class="incorrect extra">' + input[i] + "</letter>";
2020-05-30 20:15:00 +08:00
} else {
ret += '<letter class="incorrect">' + currentWord[i] + "</letter>";
}
2020-05-11 07:32:10 +08:00
}
2020-05-09 08:29:47 +08:00
}
}
2020-07-13 06:53:15 +08:00
if (input.length < currentWord.length) {
for (let i = input.length; i < currentWord.length; i++) {
2020-05-11 07:32:10 +08:00
ret += "<letter>" + currentWord[i] + "</letter>";
}
}
2020-07-13 06:53:15 +08:00
wordAtIndex.innerHTML = ret;
let lastindex = currentWordIndex;
2020-07-03 08:35:45 +08:00
if (
(currentWord == input ||
(config.quickEnd && currentWord.length == input.length)) &&
lastindex == wordsList.length - 1
2020-07-03 08:35:45 +08:00
) {
inputHistory.push(input);
2020-05-11 07:32:10 +08:00
currentInput = "";
//last character typed, show result
if (!resultVisible) {
if (keypressPerSecond.length === 0) {
keypressPerSecond.push(currentKeypressCount);
}
showResult();
}
2020-05-11 07:32:10 +08:00
}
// liveWPM()
2020-05-09 08:29:47 +08:00
}
2020-07-03 07:01:46 +08:00
function highlightBadWord(index, showError) {
if (!showError) return;
$($("#words .word")[index]).addClass("error");
2020-05-09 08:29:47 +08:00
}
2020-05-11 07:32:10 +08:00
function showTimer() {
let op = config.showTimerBar ? config.timerOpacity : 0;
2020-07-03 07:01:46 +08:00
if (config.timerStyle === "bar") {
// let op = 0.25;
// if (
// $("#timerNumber").hasClass("timerSub") ||
// $("#timerNumber").hasClass("timerText") ||
// $("#timerNumber").hasClass("timerMain")
// ) {
// op = 1;
// }
2020-07-06 07:41:06 +08:00
$("#timerWrapper").stop(true, true).removeClass("hidden").animate(
2020-07-03 08:35:45 +08:00
{
opacity: op,
2020-07-03 08:35:45 +08:00
},
250
);
2020-07-23 20:53:24 +08:00
} else if (config.timerStyle === "text") {
// let op = 0.25;
// if (
// $("#timerNumber").hasClass("timerSub") ||
// $("#timerNumber").hasClass("timerText") ||
// $("#timerNumber").hasClass("timerMain")
// ) {
// op = 1;
// }
2020-07-06 07:41:06 +08:00
$("#timerNumber").stop(true, true).removeClass("hidden").animate(
2020-07-03 08:35:45 +08:00
{
opacity: op,
2020-07-03 08:35:45 +08:00
},
250
);
2020-06-16 06:13:40 +08:00
}
2020-05-11 07:32:10 +08:00
}
function hideTimer() {
2020-07-03 07:01:46 +08:00
if (config.timerStyle === "bar") {
2020-07-06 07:41:06 +08:00
$("#timerWrapper").stop(true, true).animate(
2020-07-03 08:35:45 +08:00
{
opacity: 0,
},
125
);
2020-07-03 07:01:46 +08:00
} else if (config.timerStyle === "text") {
2020-07-06 07:41:06 +08:00
$("#timerNumber").stop(true, true).animate(
2020-07-03 08:35:45 +08:00
{
opacity: 0,
},
125
);
2020-06-16 06:13:40 +08:00
}
2020-06-16 05:52:47 +08:00
}
2020-07-12 07:41:14 +08:00
function changeTimerColor(color) {
$("#timer").removeClass("timerSub");
$("#timer").removeClass("timerText");
$("#timer").removeClass("timerMain");
$("#timerNumber").removeClass("timerSub");
$("#timerNumber").removeClass("timerText");
$("#timerNumber").removeClass("timerMain");
$("#liveWpm").removeClass("timerSub");
$("#liveWpm").removeClass("timerText");
$("#liveWpm").removeClass("timerMain");
if (color === "main") {
$("#timer").addClass("timerMain");
$("#timerNumber").addClass("timerMain");
$("#liveWpm").addClass("timerMain");
} else if (color === "sub") {
$("#timer").addClass("timerSub");
$("#timerNumber").addClass("timerSub");
$("#liveWpm").addClass("timerSub");
} else if (color === "text") {
$("#timer").addClass("timerText");
$("#timerNumber").addClass("timerText");
$("#liveWpm").addClass("timerText");
}
}
2020-06-16 05:52:47 +08:00
function restartTimer() {
2020-07-03 07:01:46 +08:00
if (config.timerStyle === "bar") {
if (config.mode === "time") {
2020-07-03 08:35:45 +08:00
$("#timer").stop(true, true).animate(
{
width: "100vw",
},
0
);
2020-07-03 07:01:46 +08:00
} else if (config.mode === "words" || config.mode === "custom") {
2020-07-03 08:35:45 +08:00
$("#timer").stop(true, true).animate(
{
width: "0vw",
},
0
);
}
2020-06-16 06:13:40 +08:00
}
2020-05-11 07:32:10 +08:00
}
2020-06-16 06:13:40 +08:00
function updateTimer() {
if (!config.showTimerBar) return;
2020-07-03 07:01:46 +08:00
if (config.mode === "time") {
if (config.timerStyle === "bar") {
2020-07-03 08:35:45 +08:00
let percent = 100 - ((time + 1) / config.time) * 100;
$("#timer")
.stop(true, true)
.animate(
{
width: percent + "vw",
},
1000,
"linear"
);
2020-07-03 07:01:46 +08:00
} else if (config.timerStyle === "text") {
var displayTime = new Date(null);
displayTime.setSeconds(config.time - time);
displayTime = displayTime.toISOString().substr(11, 8);
while (
displayTime.substr(0, 2) == "00" ||
displayTime[0] == ":" ||
(displayTime.length == 2 && displayTime[0] == "0")
) {
if (displayTime.substr(0, 2) == "00") {
displayTime = displayTime.substr(3);
} else {
displayTime = displayTime.substr(1);
}
}
$("#timerNumber").html(displayTime);
// $("#timerNumber").html(config.time - time);
}
2020-07-03 08:35:45 +08:00
} else if (
config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote"
2020-07-03 08:35:45 +08:00
) {
if (config.timerStyle === "bar") {
2020-07-27 10:09:05 +08:00
let outof = wordsList.length;
if (config.mode === "words") {
outof = config.words;
}
if (config.mode === "custom") {
if (customTextIsRandom) {
outof = customTextWordCount;
} else {
outof = customText.length;
}
}
let percent = Math.floor(((currentWordIndex + 1) / outof) * 100);
$("#timer")
.stop(true, true)
.animate(
{
width: percent + "vw",
},
250
);
} else if (config.timerStyle === "text") {
let outof = wordsList.length;
if (config.mode === "words") {
outof = config.words;
}
if (config.mode === "custom") {
if (customTextIsRandom) {
outof = customTextWordCount;
} else {
outof = customText.length;
}
}
$("#timerNumber").html(`${inputHistory.length}/${outof}`);
// $("#timerNumber").html(config.time - time);
}
2020-06-16 06:13:40 +08:00
}
2020-05-11 07:32:10 +08:00
}
2020-05-09 08:29:47 +08:00
function hideCaret() {
$("#caret").addClass("hidden");
}
function showCaret() {
2020-07-03 08:35:45 +08:00
if ($("#result").hasClass("hidden")) {
updateCaretPosition();
$("#caret").removeClass("hidden");
startCaretAnimation();
}
2020-05-09 08:29:47 +08:00
}
function stopCaretAnimation() {
$("#caret").css("animation-name", "none");
$("#caret").css("opacity", "1");
2020-05-09 08:29:47 +08:00
}
function startCaretAnimation() {
$("#caret").css("animation-name", "caretFlash");
}
function hideKeymap() {
$(".keymap").addClass("hidden");
}
function showKeymap() {
$(".keymap").removeClass("hidden");
}
function flashPressedKeymapKey(key, correct) {
// return;
// $(`#${key}`).css("animation", "none").removeClass("flash").addClass("flash");
// setTimeout((f) => {
// $(`#${key}`).removeClass("flash");
// }, 1000);
// from {
// color: var(--bg-color);
// background-color: var(--main-color);
// border-color: var(--main-color);
// }
// to {
// color: var(--sub-color);
// background-color: var(--bg-color);
// border-color: var(--sub-color);
// }
let errorColor;
if (config.colorfulMode) {
errorColor = themeColors.colorfulError;
} else {
errorColor = themeColors.error;
}
switch (key) {
case "\\":
case "|":
key = "#KeyBackslash";
break;
case "}":
case "]":
key = "#KeyRightBracket";
break;
case "{":
case "[":
key = "#KeyLeftBracket";
break;
case '"':
case "'":
key = "#KeyQuote";
break;
case ":":
case ";":
key = "#KeySemicolon";
break;
case "<":
case ",":
key = "#KeyComma";
break;
case ">":
case ".":
key = "#KeyPeriod";
break;
case "?":
case "/":
key = "#KeySlash";
break;
case "" || "Space":
key = "#KeySpace";
break;
default:
key = `#Key${key.toUpperCase()}`;
}
if (correct) {
$(key)
.stop(true, true)
.css({
color: themeColors.bg,
backgroundColor: themeColors.main,
borderColor: themeColors.main,
})
.animate(
{
color: themeColors.sub,
backgroundColor: themeColors.bg,
borderColor: themeColors.sub,
},
500,
"easeOutExpo"
);
} else {
$(key)
.stop(true, true)
.css({
color: themeColors.bg,
backgroundColor: themeColors.error,
borderColor: themeColors.error,
})
.animate(
{
color: themeColors.sub,
backgroundColor: themeColors.bg,
borderColor: themeColors.sub,
},
500,
"easeOutExpo"
);
}
}
function updateHighlightedKeymapKey() {
// return;
if ($(".active-key") != undefined) {
$(".active-key").removeClass("active-key");
}
var currentKey = wordsList[currentWordIndex]
.substring(currentInput.length, currentInput.length + 1)
.toString()
.toUpperCase();
switch (currentKey) {
case "\\":
case "|":
var highlightKey = "#KeyBackslash";
break;
case "}":
case "]":
var highlightKey = "#KeyRightBracket";
break;
case "{":
case "[":
var highlightKey = "#KeyLeftBracket";
break;
case '"':
case "'":
var highlightKey = "#KeyQuote";
break;
case ":":
case ";":
var highlightKey = "#KeySemicolon";
break;
case "<":
case ",":
var highlightKey = "#KeyComma";
break;
case ">":
case ".":
var highlightKey = "#KeyPeriod";
break;
case "?":
case "/":
var highlightKey = "#KeySlash";
break;
case "":
var highlightKey = "#KeySpace";
break;
default:
var highlightKey = `#Key${currentKey}`;
}
$(highlightKey).addClass("active-key");
}
2020-05-09 08:29:47 +08:00
function updateCaretPosition() {
2020-07-13 06:53:15 +08:00
// return;
2020-07-03 08:35:45 +08:00
if ($("#words").hasClass("hidden")) return;
2020-07-13 06:53:15 +08:00
2020-05-09 08:29:47 +08:00
let caret = $("#caret");
2020-07-13 06:53:15 +08:00
// let activeWord = $("#words .word.active");
2020-05-09 08:29:47 +08:00
let inputLen = currentInput.length;
let currentLetterIndex = inputLen - 1;
if (currentLetterIndex == -1) {
currentLetterIndex = 0;
}
2020-07-13 06:53:15 +08:00
// let currentLetter = $("#words .word.active letter")[currentLetterIndex];
try {
let currentLetter = document
.querySelector("#words .active")
.querySelectorAll("letter")[currentLetterIndex];
if ($(currentLetter).length == 0) return;
let currentLetterPosLeft = currentLetter.offsetLeft;
let currentLetterPosTop = currentLetter.offsetTop;
let letterHeight = $(currentLetter).height();
let newTop = 0;
let newLeft = 0;
newTop = currentLetterPosTop - letterHeight / 4;
if (inputLen == 0) {
newLeft = currentLetterPosLeft - caret.width() / 2;
} else {
newLeft =
currentLetterPosLeft + $(currentLetter).width() - caret.width() / 2;
}
let duration = 0;
if (config.smoothCaret) {
duration = 100;
// if (Math.round(caret[0].offsetTop) != Math.round(newTop)) {
// caret.css("top", newTop);
// duration = 10;
// }
}
caret.stop(true, true).animate(
{
top: newTop,
left: newLeft,
},
duration
);
if (config.showAllLines) {
let browserHeight = window.innerHeight;
let middlePos = browserHeight / 2 - $("#caret").outerHeight() / 2;
let contentHeight = document.body.scrollHeight;
2020-07-03 07:01:46 +08:00
if (newTop >= middlePos && contentHeight > browserHeight) {
window.scrollTo({
left: 0,
top: newTop - middlePos,
behavior: "smooth",
});
}
}
} catch (e) {}
}
function countChars() {
let correctWordChars = 0;
2020-05-09 08:29:47 +08:00
let correctChars = 0;
let incorrectChars = 0;
let extraChars = 0;
let missedChars = 0;
let spaces = 0;
let correctspaces = 0;
2020-05-09 08:29:47 +08:00
for (let i = 0; i < inputHistory.length; i++) {
if (inputHistory[i] === currentInput) {
//last word that was not finished
continue;
}
if (inputHistory[i] == wordsList[i]) {
//the word is correct
correctWordChars += wordsList[i].length;
correctChars += wordsList[i].length;
if (i < inputHistory.length - 1) {
correctspaces++;
}
} else if (inputHistory[i].length >= wordsList[i].length) {
//too many chars
2020-05-11 07:32:10 +08:00
for (let c = 0; c < inputHistory[i].length; c++) {
if (c < wordsList[i].length) {
//on char that still has a word list pair
if (inputHistory[i][c] == wordsList[i][c]) {
correctChars++;
} else {
incorrectChars++;
}
2020-05-09 08:29:47 +08:00
} else {
//on char that is extra
extraChars++;
}
}
} else {
//not enough chars
2020-05-11 07:32:10 +08:00
for (let c = 0; c < wordsList[i].length; c++) {
if (c < inputHistory[i].length) {
//on char that still has a word list pair
if (inputHistory[i][c] == wordsList[i][c]) {
correctChars++;
} else {
incorrectChars++;
}
} else {
//on char that is extra
missedChars++;
2020-05-09 08:29:47 +08:00
}
}
}
2020-07-03 07:01:46 +08:00
if (i < inputHistory.length - 1) {
spaces++;
}
2020-05-09 08:29:47 +08:00
}
return {
spaces: spaces,
correctWordChars: correctWordChars,
allCorrectChars: correctChars,
incorrectChars: incorrectChars,
extraChars: extraChars,
2020-07-03 08:35:45 +08:00
missedChars: missedChars,
correctSpaces: correctspaces,
2020-07-03 08:35:45 +08:00
};
2020-05-09 08:29:47 +08:00
}
2020-07-03 07:01:46 +08:00
function roundTo2(num) {
2020-07-03 08:35:45 +08:00
return Math.round((num + Number.EPSILON) * 100) / 100;
}
2020-05-11 07:32:10 +08:00
function calculateStats() {
if (config.mode == "words" && config.difficulty == "normal") {
2020-05-11 07:32:10 +08:00
if (inputHistory.length != wordsList.length) return;
2020-05-09 08:29:47 +08:00
}
2020-05-11 07:32:10 +08:00
let chars = countChars();
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
2020-07-03 08:35:45 +08:00
let wpm = roundTo2(
((chars.correctWordChars + chars.correctSpaces) * (60 / testSeconds)) / 5
2020-07-03 08:35:45 +08:00
);
2020-07-23 01:29:55 +08:00
console.log(
`pre-spacegate ${roundTo2(
((chars.correctWordChars + chars.spaces) * (60 / testSeconds)) / 5
)} (current ${wpm})`
);
2020-07-03 08:35:45 +08:00
let wpmraw = roundTo2(
((chars.allCorrectChars +
chars.spaces +
chars.incorrectChars +
chars.extraChars) *
(60 / testSeconds)) /
5
);
let acc = roundTo2(
(accuracyStats.correct /
(accuracyStats.correct + accuracyStats.incorrect)) *
100
);
return {
2020-06-23 23:27:33 +08:00
wpm: isNaN(wpm) ? 0 : wpm,
wpmRaw: isNaN(wpmraw) ? 0 : wpmraw,
acc: acc,
correctChars: chars.correctWordChars,
incorrectChars: chars.incorrectChars + chars.extraChars + chars.missedChars,
2020-05-28 20:19:03 +08:00
time: testSeconds,
2020-07-03 08:35:45 +08:00
spaces: chars.spaces,
correctSpaces: chars.correctSpaces,
};
}
function hideCrown() {
2020-07-03 08:35:45 +08:00
$("#result .stats .wpm .crownWrapper").css("opacity", 0);
}
function showCrown() {
2020-07-03 08:35:45 +08:00
$("#result .stats .wpm .crownWrapper").animate(
{
opacity: 1,
},
250,
"easeOutCubic"
);
}
function showResult(difficultyFailed = false) {
2020-07-03 07:01:46 +08:00
resultVisible = true;
testEnd = Date.now();
testActive = false;
setFocus(false);
hideCaret();
hideLiveWpm();
2020-06-16 06:13:40 +08:00
hideTimer();
hideKeymap();
testInvalid = false;
let stats = calculateStats();
2020-07-03 07:01:46 +08:00
if (stats === undefined) {
stats = {
wpm: 0,
wpmRaw: 0,
acc: 0,
correctChars: 0,
incorrectChars: 0,
2020-05-28 20:19:03 +08:00
time: 0,
2020-07-03 08:35:45 +08:00
spaces: 0,
correctSpaces: 0,
2020-07-03 08:35:45 +08:00
};
}
clearIntervals();
2020-07-03 07:01:46 +08:00
let testtime = roundedToFixed(stats.time, 1);
$("#result .stats .wpm .bottom").text(Math.round(stats.wpm));
$("#result .stats .wpm .bottom").attr("aria-label", stats.wpm);
$("#result .stats .raw .bottom").text(Math.round(stats.wpmRaw));
$("#result .stats .raw .bottom").attr("aria-label", stats.wpmRaw);
$("#result .stats .acc .bottom").text(Math.floor(stats.acc) + "%");
$("#result .stats .acc .bottom").attr("aria-label", stats.acc + "%");
2020-07-03 08:35:45 +08:00
$("#result .stats .key .bottom").text(
stats.correctChars + stats.correctSpaces + "/" + stats.incorrectChars
2020-07-03 08:35:45 +08:00
);
$("#result .stats .time .bottom").text(testtime + "s");
2020-07-03 07:01:46 +08:00
setTimeout(function () {
2020-07-03 08:35:45 +08:00
$("#resultExtraButtons").removeClass("hidden").css("opacity", 0).animate(
{
opacity: 1,
},
125
);
}, 125);
2020-07-03 07:01:46 +08:00
2020-07-29 01:44:36 +08:00
$("#testModesNotice").addClass("hidden");
2020-07-07 02:40:52 +08:00
$("#result .stats .leaderboards .bottom").text("");
$("#result .stats .leaderboards").addClass("hidden");
let mode2 = "";
if (config.mode === "time") {
mode2 = config.time;
// $("#result .stats .time").addClass('hidden');
} else if (config.mode === "words") {
mode2 = config.words;
// $("#result .stats .time").removeClass('hidden');
// $("#result .stats .time .bottom").text(roundedToFixed(stats.time,1)+'s');
2020-07-03 07:01:46 +08:00
} else if (config.mode === "custom") {
mode2 = "custom";
2020-07-03 22:38:00 +08:00
} else if (config.mode === "quote") {
mode2 = randomQuote.id;
}
2020-06-25 06:25:12 +08:00
let labels = [];
for (let i = 1; i <= wpmHistory.length; i++) {
labels.push(i.toString());
}
2020-07-31 02:31:43 +08:00
if (themeColors.main == "") {
refreshThemeColorObject();
}
wpmOverTimeChart.options.scales.xAxes[0].ticks.minor.fontColor =
themeColors.sub;
wpmOverTimeChart.options.scales.xAxes[0].scaleLabel.fontColor =
themeColors.sub;
wpmOverTimeChart.options.scales.yAxes[0].ticks.minor.fontColor =
themeColors.sub;
wpmOverTimeChart.options.scales.yAxes[2].ticks.minor.fontColor =
themeColors.sub;
wpmOverTimeChart.options.scales.yAxes[0].scaleLabel.fontColor =
themeColors.sub;
wpmOverTimeChart.options.scales.yAxes[2].scaleLabel.fontColor =
themeColors.sub;
2020-05-31 21:54:54 +08:00
wpmOverTimeChart.data.labels = labels;
let rawWpmPerSecondRaw = keypressPerSecond.map((f) =>
Math.round((f / 5) * 60)
);
2020-07-03 07:01:46 +08:00
let rawWpmPerSecond = smooth(rawWpmPerSecondRaw, 1);
let stddev = stdDev(rawWpmPerSecondRaw);
let avg = mean(rawWpmPerSecondRaw);
function kogasa(cov) {
return (
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
);
}
let consistency = roundTo2(kogasa(stddev / avg));
2020-08-02 04:13:25 +08:00
let keyConsistency = roundTo2(
kogasa(
stdDev(keypressStats.spacing.array) / mean(keypressStats.spacing.array)
)
);
2020-07-31 01:00:22 +08:00
if (isNaN(consistency)) {
consistency = 0;
}
$("#result .stats .consistency .bottom").text(Math.round(consistency) + "%");
$("#result .stats .consistency .bottom").attr(
"aria-label",
2020-08-02 04:13:25 +08:00
`${consistency}% (${keyConsistency}% key)`
);
wpmOverTimeChart.data.datasets[0].borderColor = themeColors.main;
2020-05-10 09:04:05 +08:00
wpmOverTimeChart.data.datasets[0].data = wpmHistory;
wpmOverTimeChart.data.datasets[1].borderColor = themeColors.sub;
wpmOverTimeChart.data.datasets[1].data = rawWpmPerSecond;
2020-05-31 21:54:54 +08:00
wpmOverTimeChart.options.annotation.annotations[0].borderColor =
themeColors.sub;
wpmOverTimeChart.options.annotation.annotations[0].label.backgroundColor =
themeColors.sub;
wpmOverTimeChart.options.annotation.annotations[0].label.fontColor =
themeColors.bg;
2020-07-03 08:35:45 +08:00
let maxChartVal = Math.max(
...[Math.max(...rawWpmPerSecond), Math.max(...wpmHistory)]
);
let minChartVal = Math.min(
...[Math.min(...rawWpmPerSecond), Math.min(...wpmHistory)]
);
// wpmOverTimeChart.options.scales.yAxes[0].ticks.min = Math.round(minChartVal);
// wpmOverTimeChart.options.scales.yAxes[1].ticks.min = Math.round(minChartVal);
let errorsNoZero = [];
2020-07-03 07:01:46 +08:00
for (let i = 0; i < errorsPerSecond.length; i++) {
errorsNoZero.push({
x: i + 1,
2020-07-03 08:35:45 +08:00
y: errorsPerSecond[i],
2020-07-03 07:01:46 +08:00
});
}
2020-05-31 21:54:54 +08:00
wpmOverTimeChart.data.datasets[2].data = errorsNoZero;
2020-07-03 07:01:46 +08:00
if (difficultyFailed) {
showNotification("Test failed", 2000);
} else if (afkDetected) {
showNotification("Test invalid - AFK detected", 2000);
} else if (sameWordset) {
showNotification("Test invalid - repeated", 2000);
} else {
let activeTags = [];
2020-07-03 07:01:46 +08:00
try {
2020-07-03 08:35:45 +08:00
dbSnapshot.tags.forEach((tag) => {
2020-07-03 07:01:46 +08:00
if (tag.active === true) {
activeTags.push(tag.id);
}
2020-07-03 08:35:45 +08:00
});
} catch (e) {}
let completedEvent = {
wpm: stats.wpm,
rawWpm: stats.wpmRaw,
correctChars: stats.correctChars + stats.correctSpaces,
incorrectChars: stats.incorrectChars,
acc: stats.acc,
mode: config.mode,
mode2: mode2,
punctuation: config.punctuation,
timestamp: Date.now(),
language: config.language,
restartCount: restartCount,
incompleteTestSeconds: incompleteTestSeconds,
difficulty: config.difficulty,
testDuration: testtime,
blindMode: config.blindMode,
theme: config.theme,
2020-07-03 07:01:46 +08:00
tags: activeTags,
2020-07-07 02:40:52 +08:00
keySpacing: keypressStats.spacing.array,
keyDuration: keypressStats.duration.array,
consistency: consistency,
2020-08-02 04:15:07 +08:00
keyConsistency: keyConsistency,
2020-07-31 10:14:14 +08:00
funbox: activeFunBox,
};
2020-07-03 08:35:45 +08:00
if (
config.difficulty == "normal" ||
((config.difficulty == "master" || config.difficulty == "expert") &&
!difficultyFailed)
) {
// console.log(incompleteTestSeconds);
// console.log(restartCount);
restartCount = 0;
incompleteTestSeconds = 0;
}
2020-07-03 08:35:45 +08:00
if (
stats.wpm > 0 &&
stats.wpm < 350 &&
stats.acc > 50 &&
stats.acc <= 100
) {
if (firebase.auth().currentUser != null) {
completedEvent.uid = firebase.auth().currentUser.uid;
//check local pb
accountIconLoading(true);
let localPb = false;
let dontShowCrown = false;
2020-07-03 08:35:45 +08:00
db_getLocalPB(
config.mode,
mode2,
config.punctuation,
config.language,
config.difficulty
).then((lpb) => {
db_getUserHighestWpm(
config.mode,
mode2,
config.punctuation,
config.language,
config.difficulty
).then((highestwpm) => {
2020-07-03 07:01:46 +08:00
if (lpb < stats.wpm && stats.wpm < highestwpm) {
dontShowCrown = true;
}
2020-07-03 07:01:46 +08:00
if (lpb < stats.wpm) {
//new pb based on local
2020-07-03 07:01:46 +08:00
if (!dontShowCrown) {
hideCrown();
showCrown();
}
localPb = true;
}
2020-07-03 07:01:46 +08:00
if (highestwpm > 0) {
wpmOverTimeChart.options.annotation.annotations[0].value = highestwpm;
2020-07-03 08:35:45 +08:00
wpmOverTimeChart.options.annotation.annotations[0].label.content =
"PB: " + highestwpm;
if (
maxChartVal >= highestwpm - 15 &&
maxChartVal <= highestwpm + 15
) {
maxChartVal = highestwpm + 15;
}
2020-07-03 08:35:45 +08:00
wpmOverTimeChart.options.scales.yAxes[0].ticks.max = Math.round(
maxChartVal
);
wpmOverTimeChart.options.scales.yAxes[1].ticks.max = Math.round(
maxChartVal
);
wpmOverTimeChart.update({ duration: 0 });
}
$("#result .stats .leaderboards").removeClass("hidden");
$("#result .stats .leaderboards .bottom").html("checking...");
2020-07-03 08:35:45 +08:00
testCompleted({
uid: firebase.auth().currentUser.uid,
obj: completedEvent,
}).then((e) => {
// console.log(e.data);
accountIconLoading(false);
2020-07-12 07:41:14 +08:00
// console.log(JSON.stringify(e.data));
if (e.data == null) {
showNotification("Unexpected response from the server.", 4000);
return;
}
2020-07-04 02:19:20 +08:00
if (e.data.resultCode === -1) {
2020-07-03 08:35:45 +08:00
showNotification("Could not save result", 3000);
2020-07-07 02:40:52 +08:00
} else if (e.data.resultCode === -2) {
showNotification(
"Possible bot detected. Result not saved.",
4000
);
2020-07-10 00:01:40 +08:00
} else if (e.data.resultCode === -3) {
showNotification(
"Could not verify. Result not saved. Refresh or contact Miodec on Discord.",
4000
);
2020-07-07 02:40:52 +08:00
} else if (e.data.resultCode === -999) {
console.error("internal error: " + e.data.message);
2020-07-10 00:01:40 +08:00
showNotification(
"Internal error. Result might not be saved. " +
e.data.message,
2020-07-10 00:01:40 +08:00
6000
);
2020-07-04 02:19:20 +08:00
} else if (e.data.resultCode === 1 || e.data.resultCode === 2) {
completedEvent.id = e.data.createdId;
dbSnapshot.results.unshift(completedEvent);
2020-07-03 07:01:46 +08:00
try {
2020-07-03 08:35:45 +08:00
firebase
.analytics()
.logEvent("testCompleted", completedEvent);
2020-07-03 07:01:46 +08:00
} catch (e) {
console.log("Analytics unavailable");
}
2020-07-04 06:42:07 +08:00
//global
let globalLbString = "";
2020-07-06 07:05:42 +08:00
if (e.data.globalLeaderboard === null) {
2020-07-04 06:42:07 +08:00
globalLbString = "global: not found";
} else if (e.data.globalLeaderboard.insertedAt === -1) {
2020-07-04 06:42:07 +08:00
globalLbString = "global: not qualified";
} else if (e.data.globalLeaderboard.insertedAt >= 0) {
if (e.data.globalLeaderboard.newBest) {
2020-07-04 23:44:43 +08:00
let pos = e.data.globalLeaderboard.insertedAt + 1;
let numend = "th";
2020-07-18 06:55:53 +08:00
let t = pos % 10;
let h = pos % 100;
if (t == 1 && h != 11) {
2020-07-04 23:44:43 +08:00
numend = "st";
2020-07-18 06:55:53 +08:00
}
if (t == 2 && h != 12) {
2020-07-04 23:44:43 +08:00
numend = "nd";
2020-07-18 06:55:53 +08:00
}
if (t == 3 && h != 13) {
2020-07-04 23:44:43 +08:00
numend = "rd";
}
globalLbString = `global: ${pos}${numend} place`;
} else {
2020-07-04 23:44:43 +08:00
let pos = e.data.globalLeaderboard.foundAt + 1;
let numend = "th";
2020-07-18 06:55:53 +08:00
let t = pos % 10;
let h = pos % 100;
if (t == 1 && h != 11) {
2020-07-04 23:44:43 +08:00
numend = "st";
2020-07-18 06:55:53 +08:00
}
if (t == 2 && h != 12) {
2020-07-04 23:44:43 +08:00
numend = "nd";
2020-07-18 06:55:53 +08:00
}
if (t == 3 && h != 13) {
2020-07-04 23:44:43 +08:00
numend = "rd";
}
globalLbString = `global: already ${pos}${numend}`;
}
}
2020-07-04 06:42:07 +08:00
//daily
let dailyLbString = "";
2020-07-06 07:05:42 +08:00
if (e.data.dailyLeaderboard === null) {
2020-07-04 06:42:07 +08:00
dailyLbString = "daily: not found";
} else if (e.data.dailyLeaderboard.insertedAt === -1) {
2020-07-04 06:42:07 +08:00
dailyLbString = "daily: not qualified";
} else if (e.data.dailyLeaderboard.insertedAt >= 0) {
if (e.data.dailyLeaderboard.newBest) {
2020-07-04 23:44:43 +08:00
let pos = e.data.dailyLeaderboard.insertedAt + 1;
let numend = "th";
if (pos === 1) {
numend = "st";
} else if (pos === 2) {
numend = "nd";
} else if (pos === 3) {
numend = "rd";
}
dailyLbString = `daily: ${pos}${numend} place`;
} else {
2020-07-04 23:44:43 +08:00
let pos = e.data.dailyLeaderboard.foundAt + 1;
let numend = "th";
if (pos === 1) {
numend = "st";
} else if (pos === 2) {
numend = "nd";
} else if (pos === 3) {
numend = "rd";
}
dailyLbString = `daily: already ${pos}${numend}`;
}
2020-07-04 06:42:07 +08:00
}
2020-07-22 05:55:07 +08:00
$("#result .stats .leaderboards .bottom").html(
globalLbString + "<br>" + dailyLbString
);
if (
e.data.dailyLeaderboard === null &&
2020-07-22 05:55:07 +08:00
e.data.globalLeaderboard === null
) {
$("#result .stats .leaderboards").addClass("hidden");
2020-07-22 05:55:07 +08:00
}
if (e.data.needsToVerifyEmail === true) {
$("#result .stats .leaderboards").removeClass("hidden");
2020-07-22 05:55:07 +08:00
$("#result .stats .leaderboards .bottom").html(
`please verify your email to access leaderboards - <a onClick="sendVerificationEmail()">resend email</a>`
);
} else if (e.data.lbBanned) {
$("#result .stats .leaderboards").removeClass("hidden");
$("#result .stats .leaderboards .bottom").html("banned");
} else if (e.data.name === false) {
$("#result .stats .leaderboards").removeClass("hidden");
$("#result .stats .leaderboards .bottom").html(
"update your name to access leaderboards"
);
} else if (e.data.needsToVerify === true) {
$("#result .stats .leaderboards").removeClass("hidden");
$("#result .stats .leaderboards .bottom").html(
"verification needed to access leaderboards"
);
}
2020-07-04 06:42:07 +08:00
2020-07-04 02:19:20 +08:00
if (e.data.resultCode === 2) {
//new pb
2020-07-03 07:01:46 +08:00
if (!localPb) {
2020-07-03 08:35:45 +08:00
showNotification(
"Local PB data is out of sync! Resyncing.",
5000
);
}
2020-07-03 08:35:45 +08:00
db_saveLocalPB(
config.mode,
mode2,
config.punctuation,
config.language,
config.difficulty,
stats.wpm
);
2020-07-03 07:01:46 +08:00
} else {
if (localPb) {
2020-07-03 08:35:45 +08:00
showNotification(
"Local PB data is out of sync! Refresh the page to resync it or contact Miodec on Discord.",
15000
);
}
}
}
2020-07-03 08:35:45 +08:00
});
});
});
} else {
2020-07-03 07:01:46 +08:00
try {
2020-07-03 08:35:45 +08:00
firebase.analytics().logEvent("testCompletedNoLogin", completedEvent);
2020-07-03 07:01:46 +08:00
} catch (e) {
console.log("Analytics unavailable");
}
// showNotification("Sign in to save your result",3000);
}
} else {
showNotification("Test invalid", 3000);
testInvalid = true;
2020-07-03 07:01:46 +08:00
try {
2020-07-03 08:35:45 +08:00
firebase.analytics().logEvent("testCompletedInvalid", completedEvent);
2020-07-03 07:01:46 +08:00
} catch (e) {
console.log("Analytics unavailable");
}
}
}
if (firebase.auth().currentUser != null) {
2020-07-03 08:35:45 +08:00
$("#result .loginTip").addClass("hidden");
} else {
$("#result .stats .leaderboards").addClass("hidden");
2020-07-03 08:35:45 +08:00
$("#result .loginTip").removeClass("hidden");
}
let testType = "";
testType += config.mode;
if (config.mode == "time") {
2020-07-03 08:35:45 +08:00
testType += " " + config.time;
} else if (config.mode == "words") {
2020-07-03 08:35:45 +08:00
testType += " " + config.words;
}
if (config.mode != "custom") {
2020-07-23 04:23:25 +08:00
testType += "<br>" + config.language.replace(/_/g, " ");
}
if (config.punctuation) {
2020-07-03 08:35:45 +08:00
testType += "<br>punctuation";
}
if (config.blindMode) {
2020-07-03 08:35:45 +08:00
testType += "<br>blind";
}
if (config.difficulty == "expert") {
testType += "<br>expert";
} else if (config.difficulty == "master") {
testType += "<br>master";
}
$("#result .stats .testType .bottom").html(testType);
let otherText = "";
if (difficultyFailed) {
2020-07-03 08:35:45 +08:00
otherText += "<br>failed";
}
if (afkDetected) {
2020-07-03 08:35:45 +08:00
otherText += "<br>afk detected";
}
if (testInvalid) {
2020-07-03 08:35:45 +08:00
otherText += "<br>invalid";
}
if (sameWordset) {
2020-07-03 08:35:45 +08:00
otherText += "<br>repeated";
}
if (otherText == "") {
2020-07-03 08:35:45 +08:00
$("#result .stats .info").addClass("hidden");
} else {
2020-07-03 08:35:45 +08:00
$("#result .stats .info").removeClass("hidden");
otherText = otherText.substring(4);
$("#result .stats .info .bottom").html(otherText);
}
let tagsText = "";
try {
2020-07-03 08:35:45 +08:00
dbSnapshot.tags.forEach((tag) => {
if (tag.active === true) {
tagsText += "<br>" + tag.name;
}
2020-07-03 08:35:45 +08:00
});
} catch (e) {}
if (tagsText == "") {
2020-07-03 08:35:45 +08:00
$("#result .stats .tags").addClass("hidden");
} else {
2020-07-03 08:35:45 +08:00
$("#result .stats .tags").removeClass("hidden");
tagsText = tagsText.substring(4);
$("#result .stats .tags .bottom").html(tagsText);
}
if (
$("#result .stats .tags").hasClass("hidden") &&
$("#result .stats .info").hasClass("hidden")
) {
$("#result .stats .infoAndTags").addClass("hidden");
} else {
$("#result .stats .infoAndTags").removeClass("hidden");
}
2020-07-03 08:35:45 +08:00
if (config.mode === "quote") {
$("#result .stats .source").removeClass("hidden");
$("#result .stats .source .bottom").html(randomQuote.source);
} else {
$("#result .stats .source").addClass("hidden");
}
wpmOverTimeChart.options.scales.yAxes[0].ticks.max = maxChartVal;
wpmOverTimeChart.options.scales.yAxes[1].ticks.max = maxChartVal;
2020-05-10 09:04:05 +08:00
wpmOverTimeChart.update({ duration: 0 });
2020-08-01 21:01:06 +08:00
wpmOverTimeChart.resize();
2020-07-03 07:01:46 +08:00
swapElements($("#words"), $("#result"), 250, () => {
$("#words").empty();
2020-08-01 21:01:06 +08:00
wpmOverTimeChart.resize();
// if (config.blindMode) {
// $.each($("#words .word"), (i, word) => {
// let input = inputHistory[i];
// if (input == undefined) input = currentInput;
// compareInput(i, input, true);
// if (inputHistory[i] != wordsList[i]) {
// highlightBadWord(i, true);
// }
// });
// }
// let remove = false;
// $.each($("#words .word"), (i, obj) => {
// if (remove) {
// $(obj).remove();
// } else {
// $(obj).removeClass("hidden");
// if ($(obj).hasClass("active")) remove = true;
// }
// });
});
2020-05-09 08:29:47 +08:00
}
function restartTest(withSameWordset = false) {
clearIntervals();
time = 0;
2020-05-23 23:29:36 +08:00
afkDetected = false;
wpmHistory = [];
rawHistory = [];
2020-05-09 08:29:47 +08:00
setFocus(false);
hideCaret();
testActive = false;
hideLiveWpm();
2020-07-20 22:48:05 +08:00
hideTimer();
$("#showWordHistoryButton").removeClass("loaded");
keypressPerSecond = [];
currentKeypressCount = 0;
errorsPerSecond = [];
currentErrorCount = 0;
currentTestLine = 0;
activeWordJumped = false;
2020-07-06 07:05:42 +08:00
keypressStats = {
spacing: {
current: -1,
array: [],
},
duration: {
current: -1,
array: [],
},
};
2020-07-13 11:03:54 +08:00
$("#timerNumber").css("opacity", 0);
2020-06-16 05:52:47 +08:00
// restartTimer();
let el = null;
2020-07-03 07:01:46 +08:00
if (resultVisible) {
//results are being displayed
el = $("#result");
2020-07-03 07:01:46 +08:00
} else {
//words are being displayed
el = $("#words");
}
2020-07-03 07:01:46 +08:00
if (resultVisible) {
if (config.randomTheme) {
randomiseTheme();
2020-07-23 04:23:25 +08:00
showNotification(config.theme.replace(/_/g, " "), 1500);
}
2020-07-03 08:35:45 +08:00
$("#words").stop(true, true).animate(
{
opacity: 0,
},
125
);
$("#wordsTitle")
.stop(true, true)
.animate(
{
opacity: 0,
},
125,
() => {
$("#wordsTitle").slideUp(0);
}
);
$("#resultExtraButtons")
.stop(true, true)
.animate(
{
opacity: 0,
},
125,
() => {
$("#resultExtraButtons").addClass("hidden");
}
);
}
resultVisible = false;
2020-07-03 07:01:46 +08:00
// .css("transition", "1s linear");
2020-07-03 08:35:45 +08:00
el.stop(true, true).animate(
{
opacity: 0,
},
125,
() => {
if (!withSameWordset) {
sameWordset = false;
initWords();
} else {
sameWordset = true;
testActive = false;
currentWordIndex = 0;
currentWordElementIndex = 0;
2020-07-03 08:35:45 +08:00
accuracyStats = {
correct: 0,
incorrect: 0,
};
inputHistory = [];
currentInput = "";
showWords();
}
if (config.keymapMode !== "off") {
showKeymap();
}
2020-07-03 08:35:45 +08:00
$("#result").addClass("hidden");
2020-07-29 01:44:36 +08:00
$("#testModesNotice").removeClass("hidden").css({
2020-07-03 08:35:45 +08:00
opacity: 1,
// 'height': 'auto',
// 'margin-bottom': '1.25rem'
});
$("#words")
.css("opacity", 0)
.removeClass("hidden")
.stop(true, true)
.animate(
{
opacity: 1,
},
125,
() => {
hideCrown();
clearIntervals();
$("#restartTestButton").css("opacity", 1);
if ($("#commandLineWrapper").hasClass("hidden")) focusWords();
wpmOverTimeChart.options.annotation.annotations[0].value = "-30";
wpmOverTimeChart.update();
// let oldHeight = $("#words").height();
// let newHeight = $("#words")
// .css("height", "fit-content")
// .css("height", "-moz-fit-content")
// .height();
// if (testMode == "words" || testMode == "custom") {
// $("#words")
// .stop(true, true)
// .css("height", oldHeight)
// .animate({ height: newHeight }, 250, () => {
// $("#words")
// .css("height", "fit-content")
// .css("height", "-moz-fit-content");
// $("#wordsInput").focus();
// updateCaretPosition();
// });
// } else if (testMode == "time") {
// $("#words")
// .stop(true, true)
// .css("height", oldHeight)
// .animate({ height: 78 }, 250, () => {
// $("#wordsInput").focus();
// updateCaretPosition();
// });
// }
}
);
}
2020-07-03 08:35:45 +08:00
);
// $(".active-key").classList.remove("active-key");
2020-05-09 08:29:47 +08:00
}
2020-05-11 07:32:10 +08:00
function focusWords() {
2020-07-03 08:35:45 +08:00
if (!$("#words").hasClass("hidden")) $("#wordsInput").focus();
2020-05-11 07:32:10 +08:00
}
2020-05-09 08:29:47 +08:00
function changeCustomText() {
2020-06-16 04:43:16 +08:00
customText = prompt("Custom text").trim();
2020-07-03 08:35:45 +08:00
customText = customText.replace(/[\n\r\t ]/gm, " ");
customText = customText.replace(/ +/gm, " ");
customText = customText.split(" ");
2020-07-03 07:01:46 +08:00
if (customText.length >= 10000) {
2020-07-03 08:35:45 +08:00
showNotification("Custom text cannot be longer than 10000 words.", 4000);
changeMode("time");
customText = "The quick brown fox jumped over the lazy dog".split(" ");
2020-07-01 05:23:50 +08:00
}
// initWords();
2020-05-09 08:29:47 +08:00
}
2020-05-11 07:32:10 +08:00
function changePage(page) {
2020-07-03 07:01:46 +08:00
if (pageTransition) {
return;
}
if (page !== "test" && page !== "") restartTest();
let activePage = $(".page.active");
2020-07-03 08:35:45 +08:00
$(".page").removeClass("active");
2020-05-11 07:32:10 +08:00
$("#wordsInput").focusout();
if (page == "test" || page == "") {
pageTransition = true;
swapElements(activePage, $(".page.pageTest"), 250, () => {
pageTransition = false;
focusWords();
2020-07-03 08:35:45 +08:00
$(".page.pageTest").addClass("active");
history.pushState("/", null, "/");
});
showTestConfig();
hideSignOutButton();
restartCount = 0;
incompleteTestSeconds = 0;
restartTest();
2020-05-11 07:32:10 +08:00
} else if (page == "about") {
pageTransition = true;
2020-07-03 07:01:46 +08:00
swapElements(activePage, $(".page.pageAbout"), 250, () => {
pageTransition = false;
2020-07-03 08:35:45 +08:00
history.pushState("about", null, "about");
$(".page.pageAbout").addClass("active");
});
hideTestConfig();
hideSignOutButton();
2020-07-03 07:01:46 +08:00
} else if (page == "settings") {
pageTransition = true;
2020-07-03 07:01:46 +08:00
swapElements(activePage, $(".page.pageSettings"), 250, () => {
pageTransition = false;
2020-07-03 08:35:45 +08:00
history.pushState("settings", null, "settings");
$(".page.pageSettings").addClass("active");
});
updateSettingsPage();
hideTestConfig();
hideSignOutButton();
2020-05-11 07:32:10 +08:00
} else if (page == "account") {
if (!firebase.auth().currentUser) {
changePage("login");
} else {
pageTransition = true;
2020-07-03 07:01:46 +08:00
swapElements(activePage, $(".page.pageAccount"), 250, () => {
pageTransition = false;
2020-07-03 08:35:45 +08:00
history.pushState("account", null, "account");
$(".page.pageAccount").addClass("active");
});
2020-05-11 07:32:10 +08:00
refreshAccountPage();
hideTestConfig();
showSignOutButton();
2020-05-11 07:32:10 +08:00
}
} else if (page == "login") {
if (firebase.auth().currentUser != null) {
2020-07-03 08:35:45 +08:00
changePage("account");
} else {
pageTransition = true;
2020-07-03 07:01:46 +08:00
swapElements(activePage, $(".page.pageLogin"), 250, () => {
pageTransition = false;
2020-07-03 08:35:45 +08:00
history.pushState("login", null, "login");
$(".page.pageLogin").addClass("active");
});
hideTestConfig();
hideSignOutButton();
}
2020-05-11 07:32:10 +08:00
}
}
2020-07-03 07:01:46 +08:00
function changeMode(mode, nosave) {
2020-05-11 07:32:10 +08:00
config.mode = mode;
$("#top .config .mode .text-button").removeClass("active");
$("#top .config .mode .text-button[mode='" + mode + "']").addClass("active");
2020-05-11 07:32:10 +08:00
if (config.mode == "time") {
$("#top .config .wordCount").addClass("hidden");
$("#top .config .time").removeClass("hidden");
$("#top .config .customText").addClass("hidden");
$("#top .config .punctuationMode").removeClass("hidden");
} else if (config.mode == "words") {
$("#top .config .wordCount").removeClass("hidden");
$("#top .config .time").addClass("hidden");
$("#top .config .customText").addClass("hidden");
$("#top .config .punctuationMode").removeClass("hidden");
} else if (config.mode == "custom") {
$("#top .config .wordCount").addClass("hidden");
$("#top .config .time").addClass("hidden");
$("#top .config .customText").removeClass("hidden");
$("#top .config .punctuationMode").addClass("hidden");
2020-07-03 07:01:46 +08:00
} else if (config.mode == "quote") {
setPunctuation(false);
2020-07-03 07:01:46 +08:00
$("#top .config .wordCount").addClass("hidden");
$("#top .config .time").addClass("hidden");
$("#top .config .customText").addClass("hidden");
$("#top .config .punctuationMode").addClass("hidden");
$("#result .stats .source").removeClass("hidden");
changeLanguage("english");
}
2020-07-03 07:01:46 +08:00
if (!nosave) saveConfigToCookie();
}
2020-07-13 06:53:15 +08:00
// function liveWPM() {
// let correctWordChars = 0;
// for (let i = 0; i < inputHistory.length; i++) {
// if (inputHistory[i] == wordsList[i]) {
// //the word is correct
// //+1 for space
// correctWordChars += wordsList[i].length + 1;
// }
// }
// let testNow = Date.now();
// let testSeconds = (testNow - testStart) / 1000;
// wpm = (correctWordChars * (60 / testSeconds)) / 5;
// return Math.round(wpm);
// }
// function liveRaw() {
// let chars = 0;
// for (let i = 0; i < inputHistory.length; i++) {
// chars += inputHistory[i].length + 1;
// }
// let testNow = Date.now();
// let testSeconds = (testNow - testStart) / 1000;
// raw = (chars * (60 / testSeconds)) / 5;
// return Math.round(raw);
// }
function liveWpmAndRaw() {
let chars = 0;
2020-05-11 07:32:10 +08:00
let correctWordChars = 0;
2020-07-18 07:32:02 +08:00
let spaces = 0;
2020-05-11 07:32:10 +08:00
for (let i = 0; i < inputHistory.length; i++) {
if (inputHistory[i] == wordsList[i]) {
//the word is correct
//+1 for space
2020-07-18 07:32:02 +08:00
correctWordChars += wordsList[i].length;
if (i < inputHistory.length - 1) {
spaces++;
}
2020-05-11 07:32:10 +08:00
}
2020-07-18 07:32:02 +08:00
chars += inputHistory[i].length;
}
let testNow = Date.now();
let testSeconds = (testNow - testStart) / 1000;
2020-07-18 07:32:02 +08:00
let wpm = Math.round(((correctWordChars + spaces) * (60 / testSeconds)) / 5);
let raw = Math.round(((chars + spaces) * (60 / testSeconds)) / 5);
2020-07-13 06:53:15 +08:00
return {
wpm: wpm,
raw: raw,
};
}
2020-05-11 07:32:10 +08:00
function updateLiveWpm(wpm) {
if (!config.showLiveWpm) return;
if (!testActive) {
hideLiveWpm();
} else {
showLiveWpm();
}
2020-05-15 10:19:39 +08:00
// let wpmstring = wpm < 100 ? `&nbsp;${wpm}` : `${wpm}`;
2020-07-13 06:53:15 +08:00
document.querySelector("#liveWpm").innerHTML = wpm;
// $("#liveWpm").html(wpm);
}
2020-05-11 07:32:10 +08:00
function showLiveWpm() {
if (!config.showLiveWpm) return;
if (!testActive) return;
$("#liveWpm").css("opacity", config.timerOpacity);
// if (config.timerStyle === "text") {
// $("#timerNumber").css("opacity", config.timerOpacity);
// }
2020-05-10 09:04:05 +08:00
}
2020-05-11 07:32:10 +08:00
function hideLiveWpm() {
2020-07-03 08:35:45 +08:00
$("#liveWpm").css("opacity", 0);
}
2020-07-03 08:35:45 +08:00
function swapElements(
el1,
el2,
totalDuration,
callback = function () {
return;
}
) {
if (
2020-07-03 08:35:45 +08:00
(el1.hasClass("hidden") && !el2.hasClass("hidden")) ||
(!el1.hasClass("hidden") && el2.hasClass("hidden"))
) {
//one of them is hidden and the other is visible
if (el1.hasClass("hidden")) {
callback();
return false;
}
2020-07-03 08:35:45 +08:00
$(el1)
.removeClass("hidden")
.css("opacity", 1)
.animate(
{
opacity: 0,
},
totalDuration / 2,
() => {
$(el1).addClass("hidden");
$(el2)
.removeClass("hidden")
.css("opacity", 0)
.animate(
{
opacity: 1,
},
totalDuration / 2,
() => {
callback();
}
);
}
);
} else if (el1.hasClass("hidden") && el2.hasClass("hidden")) {
//both are hidden, only fade in the second
2020-07-03 08:35:45 +08:00
$(el2)
.removeClass("hidden")
.css("opacity", 0)
.animate(
{
opacity: 1,
},
totalDuration,
() => {
callback();
}
);
2020-07-03 07:01:46 +08:00
} else {
callback();
}
}
function clearIntervals() {
2020-07-03 08:35:45 +08:00
timers.forEach((timer) => {
clearInterval(timer);
2020-07-03 08:35:45 +08:00
});
}
function updateAccountLoginButton() {
if (firebase.auth().currentUser != null) {
2020-07-03 08:35:45 +08:00
swapElements(
$("#menu .icon-button.login"),
$("#menu .icon-button.account"),
250
);
// $("#menu .icon-button.account").removeClass('hidden');
// $("#menu .icon-button.login").addClass('hidden');
} else {
2020-07-03 08:35:45 +08:00
swapElements(
$("#menu .icon-button.account"),
$("#menu .icon-button.login"),
250
);
// $("#menu .icon-button.login").removeClass('hidden');
// $("#menu .icon-button.account").addClass('hidden');
}
}
function accountIconLoading(truefalse) {
2020-07-03 07:01:46 +08:00
if (truefalse) {
2020-07-03 08:35:45 +08:00
$("#top #menu .account .icon").html(
'<i class="fas fa-fw fa-spin fa-circle-notch"></i>'
);
2020-07-03 07:01:46 +08:00
} else {
$("#top #menu .account .icon").html('<i class="fas fa-fw fa-user"></i>');
}
}
2020-07-03 07:01:46 +08:00
function toggleResultWordsDisplay() {
if (resultVisible) {
2020-07-03 08:35:45 +08:00
if ($("#words").stop(true, true).hasClass("hidden")) {
//show
$("#wordsTitle").css("opacity", 1).removeClass("hidden").slideDown(250);
if (!$("#showWordHistoryButton").hasClass("loaded")) {
$("#words").html(
`<div class="preloader"><i class="fas fa-fw fa-spin fa-circle-notch"></i></div>`
);
loadWordsHistory();
}
2020-07-03 08:35:45 +08:00
let newHeight = $("#words")
.removeClass("hidden")
.css("height", "auto")
.outerHeight();
$("#words")
.css({
height: 0,
opacity: 0,
})
.animate(
{
height: newHeight,
opacity: 1,
},
250
);
2020-07-03 07:01:46 +08:00
} else {
//hide
$("#wordsTitle").slideUp(250);
let oldHeight = $("#words").outerHeight();
2020-07-03 08:35:45 +08:00
$("#words").removeClass("hidden");
$("#words")
.css({
opacity: 1,
height: oldHeight,
})
.animate(
{
height: 0,
opacity: 0,
},
250,
() => {
$("#words").addClass("hidden");
}
);
}
}
}
async function loadWordsHistory() {
$("#words").empty();
inputHistory.forEach((input, index) => {
if (input === "") return;
let wordEl = `<div class='word' input='${input}'>`;
if (input !== wordsList[index]) {
wordEl = `<div class='word error' input='${input}'>`;
}
let loop;
if (input.length > wordsList[index].length) {
//input is longer - extra characters possible (loop over input)
loop = input.length;
} else {
//input is shorter or equal (loop over word list)
loop = wordsList[index].length;
}
for (let c = 0; c < loop; c++) {
// input.forEach((inputLetter, inputLetterIndex) => {
if (wordsList[index][c] !== undefined) {
if (input[c] === wordsList[index][c]) {
wordEl +=
'<letter class="correct">' + wordsList[index][c] + "</letter>";
} else {
if (input[c] === currentInput || input[c] === undefined) {
wordEl += "<letter>" + wordsList[index][c] + "</letter>";
} else {
wordEl +=
'<letter class="incorrect">' + wordsList[index][c] + "</letter>";
}
}
} else {
wordEl += '<letter class="incorrect extra">' + input[c] + "</letter>";
}
}
wordEl += "</div>";
$("#words").append(wordEl);
});
$("#showWordHistoryButton").addClass("loaded");
}
2020-07-03 07:01:46 +08:00
function flipTestColors(tf) {
if (tf) {
2020-07-03 08:35:45 +08:00
$("#words").addClass("flipped");
2020-07-03 07:01:46 +08:00
} else {
2020-07-03 08:35:45 +08:00
$("#words").removeClass("flipped");
2020-06-01 03:30:56 +08:00
}
}
2020-07-03 07:01:46 +08:00
function applyColorfulMode(tc) {
if (tc) {
2020-07-03 08:35:45 +08:00
$("#words").addClass("colorfulMode");
2020-07-03 07:01:46 +08:00
} else {
2020-07-03 08:35:45 +08:00
$("#words").removeClass("colorfulMode");
}
}
2020-07-03 07:01:46 +08:00
function showEditTags(action, id, name) {
if (action === "add") {
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit").attr("action", "add");
$("#tagsWrapper #tagsEdit .title").html("Add new tag");
2020-06-12 02:19:39 +08:00
$("#tagsWrapper #tagsEdit .button").html(`<i class="fas fa-plus"></i>`);
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit input").val("");
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
2020-07-03 07:01:46 +08:00
} else if (action === "edit") {
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit").attr("action", "edit");
$("#tagsWrapper #tagsEdit").attr("tagid", id);
$("#tagsWrapper #tagsEdit .title").html("Edit tag name");
$("#tagsWrapper #tagsEdit .button").html(`<i class="fas fa-pen"></i>`);
$("#tagsWrapper #tagsEdit input").val(name);
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
2020-07-03 07:01:46 +08:00
} else if (action === "remove") {
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit").attr("action", "remove");
$("#tagsWrapper #tagsEdit").attr("tagid", id);
$("#tagsWrapper #tagsEdit .title").html("Remove tag " + name);
$("#tagsWrapper #tagsEdit .button").html(`<i class="fas fa-check"></i>`);
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit input").addClass("hidden");
2020-06-12 02:19:39 +08:00
}
2020-07-03 07:01:46 +08:00
2020-06-12 02:19:39 +08:00
if ($("#tagsWrapper").hasClass("hidden")) {
$("#tagsWrapper")
2020-07-03 07:01:46 +08:00
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
2020-07-03 08:35:45 +08:00
.animate({ opacity: 1 }, 100, (e) => {
2020-07-03 07:01:46 +08:00
$("#tagsWrapper #tagsEdit input").focus();
});
}
2020-06-12 02:19:39 +08:00
}
2020-07-03 07:01:46 +08:00
function hideEditTags() {
2020-06-12 02:19:39 +08:00
if (!$("#tagsWrapper").hasClass("hidden")) {
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit").attr("action", "");
$("#tagsWrapper #tagsEdit").attr("tagid", "");
2020-06-12 02:19:39 +08:00
$("#tagsWrapper")
2020-07-03 07:01:46 +08:00
.stop(true, true)
.css("opacity", 1)
.animate(
2020-06-12 02:19:39 +08:00
{
2020-07-03 08:35:45 +08:00
opacity: 0,
},
100,
(e) => {
$("#tagsWrapper").addClass("hidden");
}
);
2020-07-03 07:01:46 +08:00
}
2020-06-12 02:19:39 +08:00
}
2020-07-03 07:01:46 +08:00
function showBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeIn(125);
2020-06-13 00:30:20 +08:00
}
2020-07-03 07:01:46 +08:00
function hideBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeOut(125);
2020-06-13 00:30:20 +08:00
}
2020-07-03 07:01:46 +08:00
function updateTestModesNotice() {
2020-06-24 01:17:08 +08:00
let anim = false;
2020-07-03 07:01:46 +08:00
if ($(".pageTest #testModesNotice").text() === "") anim = true;
2020-06-24 01:17:08 +08:00
$(".pageTest #testModesNotice").empty();
2020-07-03 07:01:46 +08:00
if (config.difficulty === "expert") {
2020-07-03 08:35:45 +08:00
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-star-half-alt"></i>expert</div>`
);
2020-07-03 07:01:46 +08:00
} else if (config.difficulty === "master") {
2020-07-03 08:35:45 +08:00
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-star"></i>master</div>`
);
}
2020-07-03 07:01:46 +08:00
if (config.blindMode) {
2020-07-03 08:35:45 +08:00
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-eye-slash"></i>blind</div>`
);
}
if (config.confidenceMode === "on") {
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-backspace"></i>confidence</div>`
);
}
if (config.confidenceMode === "max") {
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-backspace"></i>max confidence</div>`
);
}
if (config.stopOnError) {
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-hand-paper"></i>stop on error</div>`
);
}
if (config.layout !== "default") {
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-keyboard"></i>${config.layout}</div>`
);
}
tagsString = "";
2020-06-24 00:15:21 +08:00
// $.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
// if($(tag).children('.active').attr('active') === 'true'){
// tagsString += $(tag).children('.title').text() + ', ';
// }
// })
2020-07-03 07:01:46 +08:00
try {
2020-07-03 08:35:45 +08:00
dbSnapshot.tags.forEach((tag) => {
2020-07-03 07:01:46 +08:00
if (tag.active === true) {
2020-07-03 08:35:45 +08:00
tagsString += tag.name + ", ";
}
2020-07-03 08:35:45 +08:00
});
2020-06-24 00:15:21 +08:00
2020-07-03 07:01:46 +08:00
if (tagsString !== "") {
2020-07-03 08:35:45 +08:00
$(".pageTest #testModesNotice").append(
`<div><i class="fas fa-tag"></i>${tagsString.substring(
0,
tagsString.length - 2
)}</div>`
);
2020-06-24 00:15:21 +08:00
}
2020-07-03 08:35:45 +08:00
} catch (e) {}
2020-07-03 07:01:46 +08:00
if (anim) {
2020-07-03 08:35:45 +08:00
$(".pageTest #testModesNotice")
.css("transition", "none")
.css("opacity", 0)
.animate(
{
opacity: 1,
},
125,
(e) => {
$(".pageTest #testModesNotice").css("transition", ".125s");
}
);
2020-06-24 01:17:08 +08:00
}
}
2020-07-03 08:35:45 +08:00
$("#tagsWrapper").click((e) => {
if ($(e.target).attr("id") === "tagsWrapper") {
2020-06-12 02:19:39 +08:00
hideEditTags();
}
2020-07-03 08:35:45 +08:00
});
2020-06-12 02:19:39 +08:00
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit .button").click((e) => {
2020-06-16 06:25:28 +08:00
tagsEdit();
2020-07-03 08:35:45 +08:00
});
2020-06-16 06:25:28 +08:00
2020-07-03 08:35:45 +08:00
$("#tagsWrapper #tagsEdit input").keypress((e) => {
2020-06-16 06:25:28 +08:00
if (e.keyCode == 13) {
tagsEdit();
}
2020-07-03 08:35:45 +08:00
});
2020-06-16 06:25:28 +08:00
2020-07-03 07:01:46 +08:00
function tagsEdit() {
2020-07-03 08:35:45 +08:00
let action = $("#tagsWrapper #tagsEdit").attr("action");
2020-06-12 02:19:39 +08:00
let inputVal = $("#tagsWrapper #tagsEdit input").val();
2020-07-03 08:35:45 +08:00
let tagid = $("#tagsWrapper #tagsEdit").attr("tagid");
2020-06-12 02:19:39 +08:00
hideEditTags();
2020-07-03 07:01:46 +08:00
if (action === "add") {
2020-06-13 00:30:20 +08:00
showBackgroundLoader();
2020-07-03 08:35:45 +08:00
addTag({ uid: firebase.auth().currentUser.uid, name: inputVal }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag added", 2000);
dbSnapshot.tags.push({
name: inputVal,
id: e.data.id,
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
showNotification("Invalid tag name", 3000);
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
}
2020-07-03 08:35:45 +08:00
);
2020-07-03 07:01:46 +08:00
} else if (action === "edit") {
2020-06-13 00:30:20 +08:00
showBackgroundLoader();
2020-07-03 08:35:45 +08:00
editTag({
uid: firebase.auth().currentUser.uid,
name: inputVal,
tagid: tagid,
}).then((e) => {
2020-06-13 00:30:20 +08:00
hideBackgroundLoader();
let status = e.data.resultCode;
2020-07-03 07:01:46 +08:00
if (status === 1) {
2020-07-03 08:35:45 +08:00
showNotification("Tag updated", 2000);
dbSnapshot.tags.forEach((tag) => {
2020-07-03 07:01:46 +08:00
if (tag.id === tagid) {
tag.name = inputVal;
}
2020-07-03 08:35:45 +08:00
});
2020-06-25 04:20:35 +08:00
updateResultEditTagsPanelButtons();
updateSettingsPage();
2020-06-12 05:31:06 +08:00
updateFilterTags();
2020-07-03 07:01:46 +08:00
} else if (status === -1) {
2020-07-03 08:35:45 +08:00
showNotification("Invalid tag name", 3000);
2020-07-03 07:01:46 +08:00
} else if (status < -1) {
2020-07-03 08:35:45 +08:00
showNotification("Unknown error", 3000);
}
2020-07-03 08:35:45 +08:00
});
2020-07-03 07:01:46 +08:00
} else if (action === "remove") {
2020-06-13 00:30:20 +08:00
showBackgroundLoader();
2020-07-03 08:35:45 +08:00
removeTag({ uid: firebase.auth().currentUser.uid, tagid: tagid }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag removed", 2000);
dbSnapshot.tags.forEach((tag, index) => {
if (tag.id === tagid) {
dbSnapshot.tags.splice(index, 1);
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
updateActiveTags();
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
}
2020-07-03 08:35:45 +08:00
);
}
2020-06-16 06:25:28 +08:00
}
2020-07-23 20:42:16 +08:00
function showCapsWarning() {
if ($("#capsWarning").hasClass("hidden")) {
$("#capsWarning").removeClass("hidden");
}
}
function hideCapsWarning() {
if (!$("#capsWarning").hasClass("hidden")) {
$("#capsWarning").addClass("hidden");
}
}
function showCustomTextPopup() {
if ($("#customTextPopupWrapper").hasClass("hidden")) {
$("#customTextPopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
$("#customTextPopup textarea").val(customText.join(" "));
$("#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").click((e) => {
if ($(e.target).attr("id") === "customTextPopupWrapper") {
hideCustomTextPopup();
}
});
$("#customTextPopup .button").click((e) => {
let text = $("#customTextPopup textarea").val();
text = text.trim();
text = text.replace(/[\n\r\t ]/gm, " ");
text = text.replace(/ +/gm, " ");
text = text.split(" ");
if (text.length >= 10000) {
showNotification("Custom text cannot be longer than 10000 words.", 4000);
changeMode("time");
text = "The quick brown fox jumped over the lazy dog".split(" ");
} else {
customText = text;
customTextIsRandom = $("#customTextPopup .check input").prop("checked");
2020-07-25 22:32:21 +08:00
// if (customTextIsRandom && customText.length < 3) {
// showNotification("Random custom text requires at least 3 words", 4000);
// customTextIsRandom = false;
// }
customTextWordCount = $("#customTextPopup .wordcount input").val();
restartTest();
}
hideCustomTextPopup();
});
2020-07-31 03:16:07 +08:00
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");
}
);
}
}
$("#customMode2PopupWrapper").click((e) => {
if ($(e.target).attr("id") === "customMode2PopupWrapper") {
hideCustomMode2Popup();
}
});
2020-07-31 03:16:07 +08:00
$("#customMode2Popup input").keypress((e) => {
if (event.keyCode == 13) {
applyMode2Popup();
}
});
$("#customMode2Popup .button").click((e) => {
applyMode2Popup();
});
function applyMode2Popup() {
let mode = $("#customMode2Popup").attr("mode");
let val = $("#customMode2Popup input").val();
if (mode == "time") {
if (val !== null && !isNaN(val) && val > 0) {
changeTimeConfig(val);
restartTest();
if (val >= 1800) {
showNotification(
"Very long tests can cause performance issues or crash the website on some machines!",
5000
);
}
} else {
showNotification("Custom time can only be set between 1 and 3600", 3000);
}
} else if (mode == "words") {
if (val !== null && !isNaN(val) && val > 0 && val <= 10000) {
changeWordCount(val);
restartTest();
if (val > 2000) {
2020-07-03 08:35:45 +08:00
showNotification(
"Very long tests can cause performance issues or crash the website on some machines!",
5000
);
}
} else {
showNotification(
"Custom word amount can only be set between 1 and 10000",
3000
);
2020-05-24 21:22:41 +08:00
}
2020-07-31 03:16:07 +08:00
}
hideCustomMode2Popup();
}
$(document).on("click", "#top .logo", (e) => {
changePage("test");
});
$(document).on("click", "#top .config .wordCount .text-button", (e) => {
wrd = $(e.currentTarget).attr("wordCount");
if (wrd == "custom") {
// let newWrd = prompt("Custom word amount");
// if (newWrd !== null && !isNaN(newWrd) && newWrd > 0 && newWrd <= 10000) {
// changeWordCount(newWrd);
// if (newWrd > 2000) {
// showNotification(
// "Very long tests can cause performance issues or crash the website on some machines!",
// 5000
// );
// }
// } else {
// showNotification(
// "Custom word amount can only be set between 1 and 10000",
// 3000
// );
// }
showCustomMode2Popup("words");
2020-07-03 07:01:46 +08:00
} else {
2020-05-24 21:22:41 +08:00
changeWordCount(wrd);
2020-07-31 03:16:07 +08:00
restartTest();
2020-05-24 21:22:41 +08:00
}
2020-05-11 07:32:10 +08:00
});
$(document).on("click", "#top .config .time .text-button", (e) => {
2020-07-03 08:35:45 +08:00
time = $(e.currentTarget).attr("timeConfig");
2020-07-03 07:01:46 +08:00
if (time == "custom") {
2020-07-31 03:16:07 +08:00
// let newTime = prompt("Custom time in seconds");
// if (newTime !== null && !isNaN(newTime) && newTime > 0 && newTime <= 3600) {
// changeTimeConfig(newTime);
// if (newTime >= 1800) {
// showNotification(
// "Very long tests can cause performance issues or crash the website on some machines!",
// 5000
// );
// }
// } else {
// showNotification("Custom time can only be set between 1 and 3600", 3000);
// }
showCustomMode2Popup("time");
2020-07-03 07:01:46 +08:00
} else {
2020-05-23 02:23:15 +08:00
changeTimeConfig(time);
2020-07-31 03:16:07 +08:00
restartTest();
2020-05-23 02:23:15 +08:00
}
2020-05-11 07:32:10 +08:00
});
$(document).on("click", "#top .config .customText .text-button", (e) => {
// changeCustomText();
// restartTest();
showCustomTextPopup();
2020-05-11 07:32:10 +08:00
});
$(document).on("click", "#top .config .punctuationMode .text-button", (e) => {
2020-05-11 07:32:10 +08:00
togglePunctuation();
restartTest();
});
$("#words").click((e) => {
focusWords();
});
2020-05-09 08:29:47 +08:00
$(document).on("click", "#top .config .mode .text-button", (e) => {
2020-05-09 08:29:47 +08:00
if ($(e.currentTarget).hasClass("active")) return;
mode = e.currentTarget.innerHTML;
changeMode(mode);
restartTest();
2020-05-09 08:29:47 +08:00
});
$(document).on("click", "#top #menu .icon-button", (e) => {
2020-07-03 08:35:45 +08:00
if ($(e.currentTarget).hasClass("discord")) return;
2020-07-04 02:30:05 +08:00
if ($(e.currentTarget).hasClass("leaderboards")) {
showLeaderboards();
} else {
href = $(e.currentTarget).attr("href");
changePage(href.replace("/", ""));
}
2020-07-03 08:35:45 +08:00
});
2020-07-03 08:35:45 +08:00
$(window).on("popstate", (e) => {
let state = e.originalEvent.state;
if (state == "" || state == "/") {
// show test
2020-07-03 08:35:45 +08:00
changePage("test");
} else if (state == "about") {
// show about
changePage("about");
} else if (state == "account" || state == "login") {
if (firebase.auth().currentUser) {
changePage("account");
} else {
2020-07-03 08:35:45 +08:00
changePage("login");
}
}
2020-05-11 07:32:10 +08:00
});
2020-05-09 08:29:47 +08:00
$(document).on("keypress", "#restartTestButton", (event) => {
if (event.keyCode == 13) {
if (testActive && !afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
2020-05-09 08:29:47 +08:00
restartTest();
}
});
$(document.body).on("click", "#restartTestButton", (event) => {
2020-05-09 08:29:47 +08:00
restartTest();
});
$(document).on("keypress", "#showWordHistoryButton", (event) => {
if (event.keyCode == 13) {
toggleResultWordsDisplay();
}
});
$(document.body).on("click", "#showWordHistoryButton", (event) => {
toggleResultWordsDisplay();
});
$(document.body).on("click", "#restartTestButtonWithSameWordset", (event) => {
restartTest(true);
});
$(document).on("keypress", "#restartTestButtonWithSameWordset", (event) => {
if (event.keyCode == 13) {
restartTest(true);
}
});
$(document.body).on("click", "#copyResultToClipboardButton", (event) => {
copyResultToClipboard();
});
$(document.body).on("click", ".version", (event) => {
2020-07-03 08:35:45 +08:00
$("#versionHistoryWrapper")
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 125);
});
$(document.body).on("click", "#versionHistoryWrapper", (event) => {
2020-07-03 08:35:45 +08:00
$("#versionHistoryWrapper")
.css("opacity", 1)
.animate({ opacity: 0 }, 125, () => {
$("#versionHistoryWrapper").addClass("hidden");
});
});
2020-05-09 08:29:47 +08:00
$("#wordsInput").keypress((event) => {
event.preventDefault();
});
$("#wordsInput").on("focus", (event) => {
showCaret();
2020-05-09 08:29:47 +08:00
});
$("#wordsInput").on("focusout", (event) => {
hideCaret();
});
2020-05-11 07:32:10 +08:00
$(window).resize(() => {
updateCaretPosition();
});
2020-07-03 07:01:46 +08:00
$(document).mousemove(function (event) {
2020-07-03 08:35:45 +08:00
if (
$("#top").hasClass("focus") &&
(event.originalEvent.movementX > 0 || event.originalEvent.movementY > 0)
) {
setFocus(false);
}
2020-05-11 07:32:10 +08:00
});
2020-05-11 07:32:10 +08:00
//keypresses for the test, using different method to be more responsive
2020-07-03 07:01:46 +08:00
$(document).keypress(function (event) {
2020-06-04 00:10:14 +08:00
event = emulateLayout(event);
2020-05-09 08:29:47 +08:00
if (!$("#wordsInput").is(":focus")) return;
if (event["keyCode"] == 13) return;
if (event["keyCode"] == 32) return;
if (event["keyCode"] == 27) return;
2020-07-15 09:15:21 +08:00
if (event.key == "ContextMenu") return;
//start the test
if (currentInput == "" && inputHistory.length == 0 && !testActive) {
2020-07-03 07:01:46 +08:00
try {
if (firebase.auth().currentUser != null) {
2020-07-03 08:35:45 +08:00
firebase.analytics().logEvent("testStarted");
} else {
2020-07-03 08:35:45 +08:00
firebase.analytics().logEvent("testStartedNoLogin");
}
2020-07-03 07:01:46 +08:00
} catch (e) {
console.log("Analytics unavailable");
}
2020-05-09 08:29:47 +08:00
testActive = true;
testStart = Date.now();
// if (config.mode == "time") {
2020-07-03 07:01:46 +08:00
restartTimer();
showTimer();
2020-07-13 06:53:15 +08:00
$("#liveWpm").text("0");
showLiveWpm();
// }
2020-08-02 00:22:49 +08:00
// updateActiveElement();
2020-06-16 06:13:40 +08:00
updateTimer();
clearIntervals();
2020-07-06 07:05:42 +08:00
keypressStats = {
spacing: {
current: -1,
array: [],
},
duration: {
current: -1,
array: [],
},
};
2020-07-03 08:35:45 +08:00
timers.push(
setInterval(function () {
time++;
if (config.mode === "time") {
updateTimer();
2020-05-09 08:29:47 +08:00
}
2020-07-13 06:53:15 +08:00
// console.time("livewpm");
// let wpm = liveWPM();
// updateLiveWpm(wpm);
// showLiveWpm();
// wpmHistory.push(wpm);
// rawHistory.push(liveRaw());
let wpmAndRaw = liveWpmAndRaw();
updateLiveWpm(wpmAndRaw.wpm);
wpmHistory.push(wpmAndRaw.wpm);
rawHistory.push(wpmAndRaw.raw);
// console.timeEnd("livewpm");
2020-07-03 08:35:45 +08:00
keypressPerSecond.push(currentKeypressCount);
currentKeypressCount = 0;
errorsPerSecond.push(currentErrorCount);
currentErrorCount = 0;
if (
keypressPerSecond[time - 1] == 0 &&
keypressPerSecond[time - 2] == 0 &&
keypressPerSecond[time - 3] == 0 &&
keypressPerSecond[time - 4] == 0 &&
keypressPerSecond[time - 5] == 0 &&
keypressPerSecond[time - 6] == 0 &&
!afkDetected
) {
showNotification("AFK detected", 3000);
afkDetected = true;
}
if (config.mode == "time") {
if (time >= config.time) {
//times up
2020-07-03 08:35:45 +08:00
clearIntervals();
hideCaret();
testActive = false;
inputHistory.push(currentInput);
2020-07-03 08:35:45 +08:00
showResult();
}
}
}, 1000)
);
2020-05-09 08:29:47 +08:00
} else {
if (!testActive) return;
}
2020-07-15 05:01:05 +08:00
let thisCharCorrect;
2020-07-03 08:35:45 +08:00
if (
wordsList[currentWordIndex].substring(
currentInput.length,
currentInput.length + 1
) != event["key"]
) {
accuracyStats.incorrect++;
currentErrorCount++;
2020-07-15 05:01:05 +08:00
thisCharCorrect = false;
} else {
accuracyStats.correct++;
2020-07-15 05:01:05 +08:00
thisCharCorrect = true;
2020-05-09 08:29:47 +08:00
}
2020-05-23 23:29:36 +08:00
currentKeypressCount++;
2020-07-15 05:01:05 +08:00
if (config.stopOnError && !thisCharCorrect) {
if (config.difficulty == "master") {
//failed due to master diff when pressing a key
showResult(true);
if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
return;
} else {
return;
}
}
2020-07-15 05:01:05 +08:00
2020-05-09 08:29:47 +08:00
currentInput += event["key"];
2020-05-23 23:29:36 +08:00
setFocus(true);
activeWordTopBeforeJump = activeWordTop;
compareInput(!config.blindMode);
2020-07-03 07:08:00 +08:00
// let newActiveTop = $("#words .word.active").position().top;
2020-07-13 06:53:15 +08:00
// console.time("offcheck1");
2020-07-03 07:08:00 +08:00
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
2020-07-03 08:35:45 +08:00
if (activeWordTopBeforeJump != newActiveTop) {
activeWordJumped = true;
}
2020-07-13 06:53:15 +08:00
// console.timeEnd("offcheck2");
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.key, thisCharCorrect);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
2020-05-23 23:29:36 +08:00
updateCaretPosition();
2020-05-09 08:29:47 +08:00
});
2020-07-06 07:05:42 +08:00
$(document).keydown((event) => {
keypressStats.duration.current = performance.now();
2020-07-23 20:42:16 +08:00
if ($("#wordsInput").is(":focus")) {
try {
if (event.originalEvent.getModifierState("CapsLock")) {
showCapsWarning();
} else {
hideCapsWarning();
}
} catch (e) {}
}
2020-07-06 07:05:42 +08:00
});
$(document).keyup((event) => {
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;
});
2020-05-11 07:32:10 +08:00
//handle keyboard events
2020-05-09 08:29:47 +08:00
$(document).keydown((event) => {
2020-07-06 07:05:42 +08:00
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;
2020-07-06 07:05:42 +08:00
//tab
if (event["keyCode"] == 9) {
if (config.quickTab) {
event.preventDefault();
2020-07-03 07:01:46 +08:00
if ($(".pageTest").hasClass("active")) {
if (testActive && !afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
restartTest();
2020-07-03 07:01:46 +08:00
} else {
2020-07-03 08:35:45 +08:00
changePage("test");
}
}
}
2020-05-11 07:32:10 +08:00
//only for the typing test
2020-05-09 08:29:47 +08:00
if ($("#wordsInput").is(":focus")) {
2020-05-11 07:32:10 +08:00
//backspace
2020-05-09 08:29:47 +08:00
if (event["keyCode"] == 8) {
event.preventDefault();
if (!testActive) return;
if (currentInput == "" && inputHistory.length > 0) {
if (
2020-07-03 08:35:45 +08:00
(inputHistory[currentWordIndex - 1] ==
wordsList[currentWordIndex - 1] &&
!config.freedomMode) ||
$($(".word")[currentWordIndex - 1]).hasClass("hidden")
2020-05-09 08:29:47 +08:00
) {
return;
} else {
if (config.confidenceMode === "on" || config.confidenceMode === "max")
return;
2020-05-09 08:29:47 +08:00
if (event["ctrlKey"] || event["altKey"]) {
currentInput = "";
inputHistory.pop();
} else {
currentInput = inputHistory.pop();
}
currentWordIndex--;
currentWordElementIndex--;
2020-05-09 08:29:47 +08:00
updateActiveElement();
compareInput(!config.blindMode);
2020-05-09 08:29:47 +08:00
}
} else {
if (config.confidenceMode === "max") return;
2020-05-09 08:29:47 +08:00
if (event["ctrlKey"]) {
currentInput = "";
} else {
currentInput = currentInput.substring(0, currentInput.length - 1);
}
compareInput(!config.blindMode);
2020-05-09 08:29:47 +08:00
}
// currentKeypressCount++;
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
2020-05-09 08:29:47 +08:00
updateCaretPosition();
}
//space
2020-07-17 05:40:45 +08:00
if (event["keyCode"] == 32 || event.key === " ") {
2020-05-09 08:29:47 +08:00
if (!testActive) return;
if (currentInput == "") return;
event.preventDefault();
2020-05-09 08:29:47 +08:00
let currentWord = wordsList[currentWordIndex];
// if (config.mode == "time") {
if (!config.showAllLines || config.mode == "time") {
// let currentTop = Math.floor($($("#words .word")[currentWordIndex]).position().top);
// let nextTop = Math.floor($($("#words .word")[currentWordIndex + 1]).position().top);
let currentTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordElementIndex]
.offsetTop
);
let nextTop;
try {
nextTop = Math.floor(
document.querySelectorAll("#words .word")[
currentWordElementIndex + 1
].offsetTop
);
} catch (e) {
nextTop = 0;
}
if (nextTop > currentTop || activeWordJumped) {
//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 + 1; i++) {
if ($(wordElements[i]).hasClass("hidden")) continue;
// let forWordTop = Math.floor($(wordElements[i]).position().top);
let forWordTop = Math.floor(wordElements[i].offsetTop);
if (forWordTop < hideBound) {
// $($("#words .word")[i]).addClass("hidden");
toHide.push($($("#words .word")[i]));
}
}
toHide.forEach((el) => el.remove());
currentWordElementIndex -= toHide.length;
2020-05-09 08:29:47 +08:00
}
currentTestLine++;
2020-05-09 08:29:47 +08:00
}
}
// }
2020-07-03 08:35:45 +08:00
if (config.blindMode) $("#words .word.active letter").addClass("correct");
// document
// .querySelector("#words .word.active")
// .setAttribute("input", currentInput);
2020-05-09 08:29:47 +08:00
if (currentWord == currentInput) {
inputHistory.push(currentInput);
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
2020-05-09 08:29:47 +08:00
updateActiveElement();
updateCaretPosition();
2020-06-25 05:21:30 +08:00
currentKeypressCount++;
} else {
if (config.stopOnError) {
if (config.difficulty == "expert" || config.difficulty == "master") {
//failed due to diff when pressing space
showResult(true);
if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
return;
}
return;
}
2020-05-09 08:29:47 +08:00
inputHistory.push(currentInput);
highlightBadWord(currentWordElementIndex, !config.blindMode);
2020-05-09 08:29:47 +08:00
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
if (currentWordIndex == wordsList.length) {
//submitted last word that is incorrect
2020-05-11 07:32:10 +08:00
showResult();
2020-05-09 08:29:47 +08:00
return;
2020-07-03 08:35:45 +08:00
} else if (
config.difficulty == "expert" ||
config.difficulty == "master"
) {
//submitted last word incorrect and failed test
showResult(true);
2020-07-03 07:01:46 +08:00
if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
return;
2020-05-09 08:29:47 +08:00
}
updateActiveElement();
updateCaretPosition();
2020-06-25 05:21:30 +08:00
currentKeypressCount++;
2020-05-09 08:29:47 +08:00
}
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
2020-07-03 08:35:45 +08:00
if (
config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote"
) {
updateTimer();
}
if (config.showAllLines) {
if (config.mode == "time") {
addWord();
}
} else {
if (
config.mode == "time" ||
config.mode == "words" ||
(config.mode == "custom" && customTextIsRandom)
) {
addWord();
}
2020-05-09 08:29:47 +08:00
}
}
}
});
2020-05-11 07:32:10 +08:00
loadConfigFromCookie();
getReleasesFromGitHub();
if (firebase.app().options.projectId === "monkey-type-dev-67af4") {
$("#top .logo .bottom").text("monkey-dev");
$("head title").text("Monkey Dev");
2020-07-03 08:35:45 +08:00
$("body").append(`
<div class="devIndicator tr">
DEV
</div>
<div class="devIndicator bl">
DEV
</div>
`);
}
if (window.location.hostname === "localhost") {
2020-07-03 07:01:46 +08:00
window.onerror = function (error) {
this.showNotification(error, 3000);
};
$("#top .logo .top").text("localhost");
$("head title").text($("head title").text() + " (localhost)");
firebase.functions().useFunctionsEmulator("http://localhost:5001");
2020-07-03 08:35:45 +08:00
$("body").append(`<div class="devIndicator tl">
local
</div>
<div class="devIndicator br">
local
</div>`);
}
2020-07-03 08:35:45 +08:00
$(document).on("mouseenter", "#words .word", (e) => {
2020-07-03 07:01:46 +08:00
if (resultVisible) {
2020-07-03 08:35:45 +08:00
let input = $(e.currentTarget).attr("input");
if (input != undefined)
$(e.currentTarget).append(`<div class="wordInputAfter">${input}</div>`);
}
2020-07-03 08:35:45 +08:00
});
2020-07-03 08:35:45 +08:00
$(document).on("mouseleave", "#words .word", (e) => {
$(".wordInputAfter").remove();
});
2020-05-11 07:32:10 +08:00
$(document).ready(() => {
2020-07-03 07:01:46 +08:00
updateFavicon(32, 14);
2020-07-03 08:35:45 +08:00
$("body").css("transition", ".25s");
restartTest();
2020-05-11 07:32:10 +08:00
if (config.quickTab) {
2020-07-03 08:35:45 +08:00
$("#restartTestButton").addClass("hidden");
}
$("#centerContent")
.css("opacity", "0")
.removeClass("hidden")
.stop(true, true)
2020-07-31 08:33:17 +08:00
.animate({ opacity: 1 }, 250, () => {
if (window.location.pathname === "/account") {
history.replaceState("/", null, "/");
} else if (window.location.pathname !== "/") {
let page = window.location.pathname.replace("/", "");
changePage(page);
}
});
2020-05-11 07:32:10 +08:00
});
let ctx = $("#wpmChart");
let wpmOverTimeChart = new Chart(ctx, {
2020-07-03 08:35:45 +08:00
type: "line",
2020-05-11 07:32:10 +08:00
data: {
labels: [],
2020-07-03 08:35:45 +08:00
datasets: [
{
label: "wpm",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "wpm",
order: 2,
radius: 2,
},
2020-07-03 08:35:45 +08:00
{
label: "raw",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "raw",
order: 3,
radius: 2,
},
2020-07-03 08:35:45 +08:00
{
label: "errors",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(255, 125, 125, 1)",
borderWidth: 2,
order: 1,
yAxisID: "error",
// barPercentage: 0.1,
maxBarThickness: 10,
type: "scatter",
pointStyle: "crossRot",
radius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value.y <= 0 ? 0 : 3;
},
pointHoverRadius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value.y <= 0 ? 0 : 5;
},
},
],
2020-05-11 07:32:10 +08:00
},
options: {
tooltips: {
titleFontFamily: "Roboto Mono",
2020-05-24 21:05:40 +08:00
bodyFontFamily: "Roboto Mono",
2020-07-03 08:35:45 +08:00
mode: "index",
intersect: false,
},
2020-05-11 07:32:10 +08:00
legend: {
display: false,
labels: {
2020-07-03 08:35:45 +08:00
defaultFontFamily: "Roboto Mono",
},
2020-05-11 07:32:10 +08:00
},
responsive: true,
maintainAspectRatio: false,
// hover: {
// mode: 'x',
// intersect: false
// },
2020-05-11 07:32:10 +08:00
scales: {
2020-07-03 08:35:45 +08:00
xAxes: [
{
ticks: {
fontFamily: "Roboto Mono",
autoSkip: true,
autoSkipPadding: 40,
},
display: true,
2020-07-03 08:35:45 +08:00
scaleLabel: {
display: false,
2020-07-03 08:35:45 +08:00
labelString: "Seconds",
fontFamily: "Roboto Mono",
},
},
2020-07-03 08:35:45 +08:00
],
yAxes: [
{
id: "wpm",
2020-05-31 21:54:54 +08:00
display: true,
2020-07-03 08:35:45 +08:00
scaleLabel: {
display: true,
labelString: "Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
2020-08-02 08:08:20 +08:00
display: true,
2020-07-03 08:35:45 +08:00
},
2020-05-31 21:54:54 +08:00
},
2020-07-03 08:35:45 +08:00
{
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,
},
2020-05-31 21:54:54 +08:00
},
2020-07-03 08:35:45 +08:00
{
id: "error",
display: true,
2020-07-03 08:35:45 +08:00
position: "right",
scaleLabel: {
display: true,
labelString: "Errors",
fontFamily: "Roboto Mono",
},
ticks: {
precision: 0,
fontFamily: "Roboto Mono",
beginAtZero: true,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
2020-08-02 08:08:20 +08:00
display: false,
2020-07-03 08:35:45 +08:00
},
2020-05-24 09:02:31 +08:00
},
2020-07-03 08:35:45 +08:00
],
2020-06-05 02:37:16 +08:00
},
annotation: {
2020-07-03 08:35:45 +08:00
annotations: [
{
enabled: false,
type: "line",
mode: "horizontal",
scaleID: "wpm",
value: "-30",
borderColor: "red",
borderWidth: 1,
borderDash: [2, 2],
label: {
// Background color of label, default below
backgroundColor: "blue",
fontFamily: "Roboto Mono",
// Font size of text, inherits from global
fontSize: 11,
// Font style of text, default below
fontStyle: "normal",
// Font color of text, default below
fontColor: "#fff",
// Padding of label to add left/right, default below
xPadding: 6,
// Padding of label to add top/bottom, default below
yPadding: 6,
// Radius of label rectangle, default below
cornerRadius: 3,
// Anchor position of label on line, can be one of: top, bottom, left, right, center. Default below.
position: "center",
// Whether the label is enabled and should be displayed
enabled: true,
// Text to display in label - default is null. Provide an array to display values on a new line
content: "PB",
},
},
],
},
},
});