Merge pull request #2 from Miodec/master

merge code
This commit is contained in:
dazon 2020-07-13 17:13:33 -07:00 committed by GitHub
commit ed69343b3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 619 additions and 278 deletions

5
.firebaserc_example Normal file
View file

@ -0,0 +1,5 @@
{
"projects": {
"default": "project id"
}
}

View file

@ -14,23 +14,16 @@ Monkey-type is a minimalistic, customisable typing test, featuring many test mod
- command line
- and much more
# keybinds
You can use `tab` and `enter` (or just `tab` if you have quick tab mode enabled) to restart the typing test. Open the command line by pressing `esc` - there you can access all the functionality you need without touching your mouse.
# stats
- wpm - total amount of characters in the correctly typed words, divided by 5
- acc - percentage of correctly pressed keys
- key - correct characters / incorrect characters. Calculated after the test has ended
# discord bot
Recently, a Discord bot was added to autoassign roles. You can find the code for it over at https://github.com/Miodec/monkey-bot
# bug report or feature request
If you encounter a bug, or have a feature request - send me a message on Reddit, create an issue on GitHub or send me a message using the command line `esc`.
If you encounter a bug, or have a feature request - send me a message on Reddit, create an issue or join the [Discord server](https://discord.com/invite/yENzqcB).
# credits
montydrei for the name suggestion
everyone who provided valuable feedback on the original reddit post for the prototype of this website
Montydrei for the name suggestion
Everyone who provided valuable feedback on the original reddit post for the prototype of this website
Contributors that have helped with implementing various features, adding themes and more.
# support
If you wish to support further development and feeling extra awesome, you can do so [here](https://www.paypal.me/jackbartnik).
@ -38,9 +31,9 @@ If you wish to support further development and feeling extra awesome, you can do
# how to contribute
1. Head to [the firebase console](https://console.firebase.google.com/u/0/) and make a new project (the project name doesnt really matter, but just name it `monkey-type`). You dont need to enable analytics for it.
2. Install the [Firebase Command Line Interface](https://firebase.google.com/docs/cli), and use `firebase login` to log in to the same google account as you just used to make the project.
3. Git clone the project and make sure to rename `.firebaserc_example` to `.firebaserc` and changed the project name inside to your firebase project name.
3. Git clone the project and make sure to rename `.firebaserc_example` to `.firebaserc` and change the project name inside to your firebase project name you just created.
4. Make sure you use a SCSS compiler. For VSCode I recommend `Easy Sass` or `Live Sass Compiler` extension.
5. Run `firebase serve --only hosting` to start a local server on post 5000. Use ctrl+c to stop it.
5. Run `firebase serve` to start a local server on port 5000. Use ctrl+c to stop it.
6. Make sure to install `Prettier`. Its a code formatter, and it will make sure that we avoid any whitespace or formatting issues when merging code.
That should be it. If you run into any problems, let me know.

View file

@ -423,6 +423,9 @@ exports.testCompleted = functions.https.onCall((request, response) => {
);
}
obj.keySpacing = "removed";
obj.keyDuration = "removed";
return db
.collection("users")
.doc(request.uid)
@ -468,89 +471,94 @@ exports.testCompleted = functions.https.onCall((request, response) => {
checkLeaderboards(request.obj, "global", banned, name),
checkLeaderboards(request.obj, "daily", banned, name),
checkIfPB(request.uid, request.obj),
]).then((values) => {
let globallb = values[0].insertedAt;
let dailylb = values[1].insertedAt;
let ispb = values[2];
// console.log(values);
])
.then((values) => {
let globallb = values[0].insertedAt;
let dailylb = values[1].insertedAt;
let ispb = values[2];
// console.log(values);
let usr =
userdata.discordId !== undefined
? userdata.discordId
: userdata.name;
if (
globallb !== null &&
[1, 2, 3].includes(globallb.insertedAt + 1) &&
globallb.newBest
) {
let lbstring = `${obj.mode} ${obj.mode2} global`;
console.log(
`sending command to the bot to announce lb update ${
userdata.discordId
} ${globallb + 1} ${lbstring} ${obj.wpm}`
);
announceLbUpdate(
usr,
globallb.insertedAt + 1,
lbstring,
obj.wpm
);
}
let returnobj = {
resultCode: null,
globalLeaderboard: globallb,
dailyLeaderboard: dailylb,
lbBanned: banned,
name: name,
};
request.obj.keySpacing = "removed";
request.obj.keyDuration = "removed";
if (ispb) {
console.log(
`saved result for ${request.uid} (new PB) - ${JSON.stringify(
request.obj
)}`
);
if (
obj.mode === "time" &&
String(obj.mode2) === "60" &&
userdata.discordId !== null &&
let usr =
userdata.discordId !== undefined
? userdata.discordId
: userdata.name;
if (
globallb !== null &&
globallb.insertedAt >= 0 &&
globallb.insertedAt <= 9 &&
globallb.newBest
) {
let lbstring = `${obj.mode} ${obj.mode2} global`;
console.log(
`sending command to the bot to update the role for user ${request.uid} with wpm ${obj.wpm}`
`sending command to the bot to announce lb update ${
userdata.discordId
} ${globallb + 1} ${lbstring} ${obj.wpm}`
);
announceLbUpdate(
usr,
globallb.insertedAt + 1,
lbstring,
obj.wpm
);
updateDiscordRole(userdata.discordId, Math.round(obj.wpm));
return;
}
returnobj.resultCode = 2;
} else {
console.log(
`saved result for ${request.uid} - ${JSON.stringify(
request.obj
)}`
let returnobj = {
resultCode: null,
globalLeaderboard: globallb,
dailyLeaderboard: dailylb,
lbBanned: banned,
name: name,
};
if (ispb) {
console.log(
`saved result for ${
request.uid
} (new PB) - ${JSON.stringify(request.obj)}`
);
if (
obj.mode === "time" &&
String(obj.mode2) === "60" &&
userdata.discordId !== null &&
userdata.discordId !== undefined
) {
console.log(
`sending command to the bot to update the role for user ${request.uid} with wpm ${obj.wpm}`
);
updateDiscordRole(userdata.discordId, Math.round(obj.wpm));
}
returnobj.resultCode = 2;
} else {
console.log(
`saved result for ${request.uid} - ${JSON.stringify(
request.obj
)}`
);
returnobj.resultCode = 1;
}
return returnobj;
})
.catch((e) => {
console.error(
`error saving result when checking for PB / checking leaderboards for ${request.uid} - ${e.message}`
);
returnobj.resultCode = 1;
}
// console.log(returnobj);
return returnobj;
});
return { resultCode: -999, message: e.message };
});
})
.catch((e) => {
console.error(
`error saving result when checking for PB / checking leaderboards for ${request.uid} - ${e.message}`
`error saving result when adding result to the db for ${request.uid} - ${e.message}`
);
return { resultCode: -999 };
return { resultCode: -999, message: e.message };
});
})
.catch((e) => {
console.error(
`error saving result when getting user data for ${request.uid} - ${e.message}`
);
return { resultCode: -999 };
return { resultCode: -999, message: e.message };
});
} catch (e) {
console.error(
@ -558,7 +566,7 @@ exports.testCompleted = functions.https.onCall((request, response) => {
request.obj
)} - ${e}`
);
return { resultCode: -999 };
return { resultCode: -999, message: e.message };
}
});

View file

@ -308,6 +308,29 @@ a:hover {
}
}
#customThemeShareWrapper {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.75);
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: grid;
justify-content: center;
align-items: center;
padding: 5rem 0;
#customThemeShare {
width: 50vw;
background: var(--bg-color);
border-radius: var(--roundness);
padding: 2rem;
display: grid;
gap: 1rem;
overflow-y: scroll;
}
}
#resultEditTagsPanelWrapper {
width: 100%;

View file

@ -7,7 +7,7 @@
<title>Monkey Type</title>
<link rel="stylesheet" href="css/fa.css">
<link rel="stylesheet" href="css/balloon.css">
<link rel="stylesheet" href="css/style.css?v=33">
<link rel="stylesheet" href="css/style.css?v=36">
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme">
<link id="favicon" rel="shortcut icon" href="fav.png">
<link rel="shortcut icon" href="fav.png">
@ -37,6 +37,12 @@
Important information about your account. Please click this message.
</div>
<div class="notification">Signed in</div>
<div id="customThemeShareWrapper" class="hidden">
<div id="customThemeShare" action="">
<input type="text">
<div class="button">ok</div>
</div>
</div>
<div id="tagsWrapper" class="hidden">
<div id="tagsEdit" action="" tagid="">
<div class="title"></div>
@ -548,7 +554,7 @@
</div>
<div class="icon-button login" tabindex="2" href="/login" onclick="this.blur();">
<div class="icon">
<i class="fas fa-fw fa-sign-in-alt"></i>
<i class="far fa-fw fa-user"></i>
</div>
</div>
</div>
@ -868,16 +874,16 @@
</div>
</div>
<div class="section timerStyle" section="">
<h1>timer style</h1>
<div class="text">Change the style of the timer during a timed test.</div>
<h1>timer/progress style</h1>
<div class="text">Change the style of the timer/progress during a timed test.</div>
<div class="buttons">
<div class="button" timer="bar" tabindex="0" onclick="this.blur();">bar</div>
<div class="button" timer="text" tabindex="0" onclick="this.blur();">text</div>
</div>
</div>
<div class="section timerColor" section="">
<h1>timer color</h1>
<div class="text">Change the color of the timer number/bar and live wpm number.</div>
<h1>timer/progress color</h1>
<div class="text">Change the color of the timer/progress number/bar and live wpm number.</div>
<div class="buttons">
<div class="button" color="black" tabindex="0" onclick="this.blur();">black</div>
<div class="button" color="sub" tabindex="0" onclick="this.blur();">sub</div>
@ -886,8 +892,8 @@
</div>
</div>
<div class="section timerOpacity" section="">
<h1>timer opacity</h1>
<div class="text">Change the opacity of the timer number/bar and live wpm number.</div>
<h1>timer/progress opacity</h1>
<div class="text">Change the opacity of the timer/progress number/bar and live wpm number.</div>
<div class="buttons">
<div class="button" opacity="0.25" tabindex="0" onclick="this.blur();">0.25</div>
<div class="button" opacity="0.5" tabindex="0" onclick="this.blur();">0.5</div>
@ -999,7 +1005,10 @@
<label for="--colorful-error-extra-color">#e2b714</label>
<input type="color" value="" id="--colorful-error-extra-color">
</span>
<div class="button saveCustomThemeButton" style="grid-column: 4;">Save</div>
<div style="grid-column: 3/5;display:grid;gap:1rem;grid-auto-flow: column;">
<div class="button" id="shareCustomThemeButton">share</div>
<div class="button saveCustomThemeButton">save</div>
</div>
</div>
<div tabContent="preset" class="tabContent buttons">
</div>
@ -1076,6 +1085,7 @@
<div class="page pageAccount hidden">
<div class="preloader"><i class="fas fa-fw fa-spin fa-circle-notch"></i></div>
<div class="content hidden">
<div class="button" id="currentConfigFilter">set filters to current settings</div>
<div class="group filterButtons">
<div class="buttonsAndTitle">
<div class="title">filters</div>
@ -1097,6 +1107,7 @@
<div class="buttons modeFilters">
<div class="button" filter="mode_words">words</div>
<div class="button" filter="mode_time">time</div>
<div class="button" filter="mode_quote">quote</div>
<div class="button" filter="mode_custom">custom</div>
</div>
</div>
@ -1300,17 +1311,17 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script> -->
<script src="js/chart.js"></script>
<script src="js/chartjs-plugin-trendline.js?v=33"></script>
<script src="js/chartjs-plugin-trendline.js?v=36"></script>
<script src="js/chartjs-plugin-annotation.js"></script>
<script src="js/html2canvas.js"></script>
<script src="js/words.js?v=33"></script>
<script src="js/layouts.js?v=33"></script>
<script src="js/db.js?v=33"></script>
<script src="js/userconfig.js?v=33"></script>
<script src="js/commandline.js?v=33"></script>
<script src="js/leaderboards.js?v=33"></script>
<script src="js/settings.js?v=33"></script>
<script src="js/account.js?v=33"></script>
<script src="js/script.js?v=33"></script>
<script src="js/words.js?v=36"></script>
<script src="js/layouts.js?v=36"></script>
<script src="js/db.js?v=36"></script>
<script src="js/userconfig.js?v=36"></script>
<script src="js/commandline.js?v=36"></script>
<script src="js/leaderboards.js?v=36"></script>
<script src="js/settings.js?v=36"></script>
<script src="js/account.js?v=36"></script>
<script src="js/script.js?v=36"></script>
</html>

View file

@ -398,14 +398,14 @@ var resultHistoryChart = new Chart($(".pageAccount #resultHistoryChart"), {
Object.keys(words).forEach((language) => {
$(".pageAccount .content .filterButtons .buttons.languages").append(
`<div class="button" filter="${language}">${language.replace(
`<div class="button" filter="lang_${language}">${language.replace(
"_",
" "
)}</div>`
);
if (language === "english_expanded") {
$(".pageAccount .content .filterButtons .buttons.languages").append(
`<div class="button" filter="english_10k">english 10k</div>`
`<div class="button" filter="lang_english_10k">english 10k</div>`
);
}
});
@ -580,6 +580,61 @@ $(".pageAccount .filterButtons").click(".button", (e) => {
saveConfigToCookie();
});
$(".pageAccount #currentConfigFilter").click((e) => {
let disableGroups = [
"globalFilters",
"difficultyFilters",
"modeFilters",
"punctuationFilter",
"wordsFilter",
"timeFilter",
"languages",
"tags",
];
disableGroups.forEach((group) => {
$.each(
$(`.pageAccount .filterButtons .buttons.${group} .button`),
(index, button) => {
let fl = $(button).attr("filter");
disableFilterButton(fl);
config.resultFilters = config.resultFilters.filter((f) => f !== fl);
}
);
});
updateActiveFilters();
//rewrite this monstrosity soon pls
config.resultFilters.push(`difficulty_${config.difficulty}`);
toggleFilterButton(`difficulty_${config.difficulty}`);
config.resultFilters.push(`mode_${config.mode}`);
toggleFilterButton(`mode_${config.mode}`);
config.resultFilters.push(`words_${config.words}`);
toggleFilterButton(`words_${config.words}`);
config.resultFilters.push(`time_${config.time}`);
toggleFilterButton(`time_${config.time}`);
let puncfilter = config.punctuation ? "punc_on" : "punc_off";
config.resultFilters.push(puncfilter);
toggleFilterButton(puncfilter);
config.resultFilters.push(`lang_${config.language}`);
toggleFilterButton(`lang_${config.language}`);
let activeTags = [];
try {
dbSnapshot.tags.forEach((tag) => {
if (tag.active === true) {
activeTags.push(tag.id);
}
});
} catch (e) {}
activeTags.forEach((tag) => {
config.resultFilters.push(`tag_${tag}`);
toggleFilterButton(`tag_${tag}`);
});
saveConfigToCookie();
});
let filteredResults = [];
let visibleTableLines = 0;
@ -749,7 +804,7 @@ function refreshAccountPage() {
if (!activeFilters.includes(wordfilter)) return;
}
if (!activeFilters.includes(result.language)) return;
if (!activeFilters.includes("lang_" + result.language)) return;
let puncfilter = "punc_off";
if (result.punctuation) {
@ -808,17 +863,19 @@ function refreshAccountPage() {
//=======================================
tt = 0;
if (result.timeDuration == null) {
//test finished before timeduration field was introduced - estimate
if (result.testDuration == undefined) {
//test finished before testDuration field was introduced - estimate
if (result.mode == "time") {
tt = parseFloat(result.mode2);
} else if (result.mode == "words") {
tt = (parseFloat(result.mode2) / parseFloat(result.wpm)) * 60;
}
} else {
tt = parseFloat(result.timeDuration);
tt = parseFloat(result.testDuration);
}
if (result.restartCount != null) {
if (result.incompleteTestSeconds != undefined) {
tt += result.incompleteTestSeconds;
} else if (result.restartCount != undefined && result.restartCount > 0) {
tt += (tt / 4) * result.restartCount;
}
totalSecondsFiltered += tt;

View file

@ -157,7 +157,7 @@ let commands = {
},
{
id: "changeTimerStyle",
display: "Change timer style...",
display: "Change timer/progress style...",
subgroup: true,
exec: () => {
currentCommands.push(commandsTimerStyle);
@ -166,7 +166,7 @@ let commands = {
},
{
id: "changeTimerColor",
display: "Change timer color...",
display: "Change timer/progress color...",
subgroup: true,
exec: () => {
currentCommands.push(commandsTimerColor);
@ -175,7 +175,7 @@ let commands = {
},
{
id: "changeTimerOpacity",
display: "Change timer opacity...",
display: "Change timer/progress opacity...",
subgroup: true,
exec: () => {
currentCommands.push(commandsTimerOpacity);
@ -290,7 +290,7 @@ let commandsCaretStyle = {
};
let commandsTimerStyle = {
title: "Change timer...",
title: "Change timer/progress style...",
list: [
{
id: "setTimerStyleBar",
@ -310,7 +310,7 @@ let commandsTimerStyle = {
};
let commandsTimerColor = {
title: "Change timer color...",
title: "Change timer/progress color...",
list: [
{
id: "setTimerColorBlack",
@ -350,21 +350,21 @@ let commandsTimerOpacity = {
id: "setTimerOpacity.25",
display: ".25",
exec: () => {
setTimerOpacity(.25);
setTimerOpacity(0.25);
},
},
{
id: "setTimerOpacity.5",
display: ".5",
exec: () => {
setTimerOpacity(.5);
setTimerOpacity(0.5);
},
},
{
id: "setTimerOpacity.75",
display: ".75",
exec: () => {
setTimerOpacity(.75);
setTimerOpacity(0.75);
},
},
{

View file

@ -23,6 +23,7 @@ let activeWordTop = 0;
let activeWordJumped = false;
let sameWordset = false;
let quotes = [];
let focusState = false;
let accuracyStats = {
correct: 0,
@ -229,14 +230,15 @@ function getLastChar(word) {
}
function setFocus(foc) {
if (foc) {
// focus = true;
if (foc && !focusState) {
focusState = true;
stopCaretAnimation();
$("#top").addClass("focus");
$("#bottom").addClass("focus");
$("body").css("cursor", "none");
$("#middle").addClass("focus");
} else {
} else if (!foc && focusState) {
focusState = false;
startCaretAnimation();
$("#top").removeClass("focus");
$("#bottom").removeClass("focus");
@ -298,7 +300,11 @@ function initWords() {
}
if (config.mode == "time" || config.mode == "words") {
let wordsBound = config.mode == "time" ? 60 : config.words;
// let wordsBound = config.mode == "time" ? 60 : config.words;
let wordsBound = 60;
if (config.mode === "words" && config.words < wordsBound) {
wordsBound = config.words;
}
for (let i = 0; i < wordsBound; i++) {
randomWord = language[Math.floor(Math.random() * language.length)];
previousWord = wordsList[i - 1];
@ -460,6 +466,11 @@ function punctuateWord(previousWord, currentWord, index, maxindex) {
}
function addWord() {
if (
wordsList.length - inputHistory.length > 60 ||
(config.mode === "words" && wordsList.length >= config.words)
)
return;
let language = words[config.language];
let randomWord = language[Math.floor(Math.random() * language.length)];
previousWord = wordsList[wordsList.length - 1];
@ -486,52 +497,76 @@ function addWord() {
function showWords() {
$("#words").empty();
if (
config.mode == "words" ||
config.mode == "custom" ||
config.mode == "quote"
) {
$("#words").css("height", "auto");
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>";
}
w += "</div>";
$("#words").append(w);
// if (
// config.mode == "words" ||
// config.mode == "custom" ||
// config.mode == "quote"
// ) {
// $("#words").css("height", "auto");
// 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>";
// }
// w += "</div>";
// $("#words").append(w);
// }
// } else if (config.mode == "time") {
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>";
}
} else if (config.mode == "time") {
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>";
}
w += "</div>";
$("#words").append(w);
}
$("#words").removeClass("hidden");
const wordHeight = $($(".word")[0]).outerHeight(true);
$("#words")
.css("height", wordHeight * 3 + "px")
.css("overflow", "hidden");
w += "</div>";
$("#words").append(w);
}
$("#words").removeClass("hidden");
const wordHeight = $($(".word")[0]).outerHeight(true);
$("#words")
.css("height", wordHeight * 3 + "px")
.css("overflow", "hidden");
// }
updateActiveElement();
updateCaretPosition();
}
function updateActiveElement() {
$("#words .word").removeClass("active");
$($("#words .word")[currentWordIndex])
.addClass("active")
.removeClass("error");
// activeWordTop = $("#words .word.active").position().top;
activeWordTop = document.querySelector("#words .word.active").offsetTop;
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")[
currentWordIndex
];
activeWord.classList.add("active");
activeWord.classList.remove("error");
// activeWordTop = $("#words .word.active").position().top;
activeWordTop = document.querySelector("#words .active").offsetTop;
} catch (e) {}
}
function compareInput(wrdIndex, input, showError) {
$($("#words .word")[wrdIndex]).empty();
// let wrdAtIndex = $("#words .word")[wrdIndex];
let wordAtIndex;
let currentWord;
if (wrdIndex === null) {
wordAtIndex = document.querySelector("#words .word.active");
currentWord = wordsList[currentWordIndex];
} else {
wordAtIndex = document.querySelectorAll("#words .word")[wrdIndex];
wordsList[wrdIndex];
}
// while (wordAtIndex.firstChild) {
// wordAtIndex.removeChild(wordAtIndex.firstChild);
// }
let ret = "";
let currentWord = wordsList[wrdIndex];
for (let i = 0; i < input.length; i++) {
if (currentWord[i] == input[i]) {
ret += '<letter class="correct">' + currentWord[i] + "</letter>";
@ -567,11 +602,18 @@ function compareInput(wrdIndex, input, showError) {
ret += "<letter>" + currentWord[i] + "</letter>";
}
}
$($("#words .word")[wrdIndex]).html(ret);
wordAtIndex.innerHTML = ret;
let lastindex = currentWordIndex;
if (wrdIndex !== null) {
lastindex = wrdIndex;
}
if (
(currentWord == input ||
(config.quickEnd && currentWord.length == input.length)) &&
wrdIndex == wordsList.length - 1
lastindex == wordsList.length - 1
) {
inputHistory.push(input);
currentInput = "";
@ -718,20 +760,30 @@ function updateTimer() {
// $("#timerNumber").html(config.time - time);
}
} else if (
(config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote") &&
config.timerStyle === "bar"
config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote"
) {
let percent = Math.floor(((currentWordIndex + 1) / wordsList.length) * 100);
$("#timer")
.stop(true, true)
.animate(
{
width: percent + "vw",
},
250
if (config.timerStyle === "bar") {
let percent = Math.floor(
((currentWordIndex + 1) / wordsList.length) * 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;
}
$("#timerNumber").html(`${inputHistory.length}/${outof}`);
// $("#timerNumber").html(config.time - time);
}
}
}
@ -757,61 +809,68 @@ function startCaretAnimation() {
}
function updateCaretPosition() {
// return;
if ($("#words").hasClass("hidden")) return;
let caret = $("#caret");
let activeWord = $("#words .word.active");
// let activeWord = $("#words .word.active");
let inputLen = currentInput.length;
let currentLetterIndex = inputLen - 1;
if (currentLetterIndex == -1) {
currentLetterIndex = 0;
}
let currentLetter = $("#words .word.active letter")[currentLetterIndex];
if ($(currentLetter).length == 0) return;
// let currentLetterPos = currentLetter.position();
let currentLetterPosLeft = currentLetter.offsetLeft;
let currentLetterPosTop = currentLetter.offsetTop;
let letterHeight = $(currentLetter).height();
// let currentLetter = $("#words .word.active letter")[currentLetterIndex];
try {
let currentLetter = document
.querySelector("#words .active")
.querySelectorAll("letter")[currentLetterIndex];
let newTop = 0;
let newLeft = 0;
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;
}
newTop = currentLetterPosTop - letterHeight / 4;
if (inputLen == 0) {
newLeft = currentLetterPosLeft - caret.width() / 2;
} else {
newLeft =
currentLetterPosLeft + $(currentLetter).width() - caret.width() / 2;
}
let duration = 0;
let duration = 0;
if (config.smoothCaret) {
duration = 100;
// if (Math.round(caret[0].offsetTop) != Math.round(newTop)) {
// caret.css("top", newTop);
// duration = 10;
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
);
// let browserHeight = window.innerHeight;
// let middlePos = browserHeight / 2 - $("#caret").outerHeight() / 2;
// let contentHeight = document.body.scrollHeight;
// if (newTop >= middlePos && contentHeight > browserHeight) {
// window.scrollTo({
// left: 0,
// top: newTop - middlePos,
// behavior: "smooth",
// });
// }
}
caret.stop(true, true).animate(
{
top: newTop,
left: newLeft,
},
duration
);
let browserHeight = window.innerHeight;
let middlePos = browserHeight / 2 - $("#caret").outerHeight() / 2;
let contentHeight = document.body.scrollHeight;
if (newTop >= middlePos && contentHeight > browserHeight) {
window.scrollTo({
left: 0,
top: newTop - middlePos,
behavior: "smooth",
});
}
} catch (e) {}
}
function countChars() {
@ -1150,6 +1209,10 @@ function showResult(difficultyFailed = false) {
}).then((e) => {
accountIconLoading(false);
// console.log(JSON.stringify(e.data));
if (e.data == null) {
showNotification("Unexpected response from the server.", 4000);
return;
}
if (e.data.resultCode === -1) {
showNotification("Could not save result", 3000);
} else if (e.data.resultCode === -2) {
@ -1163,8 +1226,10 @@ function showResult(difficultyFailed = false) {
4000
);
} else if (e.data.resultCode === -999) {
console.error("internal error: " + e.data.message);
showNotification(
"Internal error. Result not saved. Refresh or contact Miodec on Discord.",
"Internal error. Result might not be saved. " +
e.data.message,
6000
);
} else if (e.data.resultCode === 1 || e.data.resultCode === 2) {
@ -1187,22 +1252,22 @@ function showResult(difficultyFailed = false) {
if (e.data.globalLeaderboard.newBest) {
let pos = e.data.globalLeaderboard.insertedAt + 1;
let numend = "th";
if (pos === 1) {
if (pos % 10 === 1) {
numend = "st";
} else if (pos === 2) {
} else if (pos % 10 === 2) {
numend = "nd";
} else if (pos === 3) {
} else if (pos % 10 === 3) {
numend = "rd";
}
globalLbString = `global: ${pos}${numend} place`;
} else {
let pos = e.data.globalLeaderboard.foundAt + 1;
let numend = "th";
if (pos === 1) {
if (pos % 10 === 1) {
numend = "st";
} else if (pos === 2) {
} else if (pos % 10 === 2) {
numend = "nd";
} else if (pos === 3) {
} else if (pos % 10 === 3) {
numend = "rd";
}
globalLbString = `global: already ${pos}${numend}`;
@ -1286,8 +1351,6 @@ function showResult(difficultyFailed = false) {
);
}
}
} else {
showNotification("Unexpected response from the server.", 4000);
}
});
});
@ -1682,7 +1745,34 @@ function changeMode(mode, nosave) {
if (!nosave) saveConfigToCookie();
}
function liveWPM() {
// 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;
let correctWordChars = 0;
for (let i = 0; i < inputHistory.length; i++) {
if (inputHistory[i] == wordsList[i]) {
@ -1690,29 +1780,24 @@ function liveWPM() {
//+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);
let wpm = Math.round((correctWordChars * (60 / testSeconds)) / 5);
let raw = Math.round((chars * (60 / testSeconds)) / 5);
return {
wpm: wpm,
raw: raw,
};
}
function updateLiveWpm(wpm) {
if (!config.showLiveWpm) return;
if (wpm == 0 || !testActive) hideLiveWpm();
// let wpmstring = wpm < 100 ? `&nbsp;${wpm}` : `${wpm}`;
$("#liveWpm").html(wpm);
document.querySelector("#liveWpm").innerHTML = wpm;
// $("#liveWpm").html(wpm);
}
function showLiveWpm() {
@ -2119,6 +2204,11 @@ $(document).on("click", "#top .config .wordCount .text-button", (e) => {
5000
);
}
} else {
showNotification(
"Custom word amount can only be set between 1 and 10000",
3000
);
}
} else {
changeWordCount(wrd);
@ -2138,6 +2228,8 @@ $(document).on("click", "#top .config .time .text-button", (e) => {
5000
);
}
} else {
showNotification("Custom time can only be set between 1 and 3600", 3000);
}
} else {
changeTimeConfig(time);
@ -2297,6 +2389,8 @@ $(document).keypress(function (event) {
// if (config.mode == "time") {
restartTimer();
showTimer();
$("#liveWpm").text("0");
showLiveWpm();
// }
updateActiveElement();
updateTimer();
@ -2317,11 +2411,18 @@ $(document).keypress(function (event) {
if (config.mode === "time") {
updateTimer();
}
let wpm = liveWPM();
updateLiveWpm(wpm);
showLiveWpm();
wpmHistory.push(wpm);
rawHistory.push(liveRaw());
// 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");
keypressPerSecond.push(currentKeypressCount);
currentKeypressCount = 0;
errorsPerSecond.push(currentErrorCount);
@ -2362,18 +2463,19 @@ $(document).keypress(function (event) {
} else {
accuracyStats.correct++;
}
currentKeypressCount++;
currentInput += event["key"];
$("#words .word.active").attr("input", currentInput);
setFocus(true);
activeWordTopBeforeJump = activeWordTop;
compareInput(currentWordIndex, currentInput, !config.blindMode);
compareInput(null, currentInput, !config.blindMode);
// let newActiveTop = $("#words .word.active").position().top;
// console.time("offcheck1");
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
if (activeWordTopBeforeJump != newActiveTop) {
activeWordJumped = true;
}
// console.timeEnd("offcheck2");
updateCaretPosition();
});
@ -2441,7 +2543,7 @@ $(document).keydown((event) => {
}
currentWordIndex--;
updateActiveElement();
compareInput(currentWordIndex, currentInput, !config.blindMode);
compareInput(null, currentInput, !config.blindMode);
}
} else {
// if ($($(".word")[currentWordIndex - 1]).hasClass("hidden")) {
@ -2452,7 +2554,7 @@ $(document).keydown((event) => {
} else {
currentInput = currentInput.substring(0, currentInput.length - 1);
}
compareInput(currentWordIndex, currentInput, !config.blindMode);
compareInput(null, currentInput, !config.blindMode);
}
// currentKeypressCount++;
updateCaretPosition();
@ -2463,42 +2565,45 @@ $(document).keydown((event) => {
if (currentInput == "") return;
event.preventDefault();
let currentWord = wordsList[currentWordIndex];
if (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")[currentWordIndex].offsetTop
);
let nextTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordIndex + 1]
.offsetTop
);
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 < currentWordIndex + 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.addClass("hidden"));
// if (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")[currentWordIndex].offsetTop
);
let nextTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordIndex + 1]
.offsetTop
);
if (nextTop > currentTop || activeWordJumped) {
//last word of the line
if (currentTestLine > 0) {
let hideBound = currentTop;
if (activeWordJumped) {
hideBound = activeWordTopBeforeJump;
}
currentTestLine++;
activeWordJumped = false;
let toHide = [];
let wordElements = $("#words .word");
for (let i = 0; i < currentWordIndex + 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.addClass("hidden"));
}
currentTestLine++;
}
// }
if (config.blindMode) $("#words .word.active letter").addClass("correct");
document
.querySelector("#words .word.active")
.setAttribute("input", currentInput);
if (currentWord == currentInput) {
inputHistory.push(currentInput);
currentInput = "";
@ -2538,7 +2643,7 @@ $(document).keydown((event) => {
) {
updateTimer();
}
if (config.mode == "time") {
if (config.mode == "time" || config.mode == "words") {
addWord();
}
}

View file

@ -71,6 +71,73 @@ function updateSettingsPage() {
}
}
function showCustomThemeShare() {
if ($("#customThemeShareWrapper").hasClass("hidden")) {
let save = [];
$.each(
$(".pageSettings .section.customTheme [type='color']"),
(index, element) => {
save.push($(element).attr("value"));
}
);
$("#customThemeShareWrapper input").val(JSON.stringify(save));
$("#customThemeShareWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
$("#customThemeShare input").focus();
$("#customThemeShare input").select();
$("#customThemeShare input").focus();
});
}
}
function hideCustomThemeShare() {
if (!$("#customThemeShareWrapper").hasClass("hidden")) {
try {
config.customThemeColors = JSON.parse(
$("#customThemeShareWrapper input").val()
);
} catch (e) {
showNotification(
"Something went wrong. Reverting to default custom colors.",
3000
);
config.customThemeColors = defaultConfig.customThemeColors;
}
setCustomThemeInputs();
applyCustomThemeColors();
$("#customThemeShareWrapper input").val("");
$("#customThemeShareWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#customThemeShareWrapper").addClass("hidden");
}
);
}
}
$("#customThemeShareWrapper").click((e) => {
if ($(e.target).attr("id") === "customThemeShareWrapper") {
hideCustomThemeShare();
}
});
$("#customThemeShare .button").click((e) => {
hideCustomThemeShare();
});
$("#shareCustomThemeButton").click((e) => {
showCustomThemeShare();
});
function refreshTagsSettingsSection() {
if (firebase.auth().currentUser !== null && dbSnapshot !== null) {
let tagsEl = $(".pageSettings .section.tags .tagsList").empty();
@ -192,7 +259,9 @@ function setActiveTimerColorButton() {
}
function setActiveTimerOpacityButton() {
$(`.pageSettings .section.timerOpacity .buttons .button`).removeClass("active");
$(`.pageSettings .section.timerOpacity .buttons .button`).removeClass(
"active"
);
$(
`.pageSettings .section.timerOpacity .buttons .button[opacity="` +
config.timerOpacity +

View file

@ -42,7 +42,9 @@ let defaultConfig = {
let cookieConfig = null;
let config = defaultConfig;
let config = {
...defaultConfig,
};
//cookies
function saveConfigToCookie() {

View file

@ -38,6 +38,11 @@
"bgColor": "#323437",
"textColor": "#e2b714"
},
{
"name": "nausea",
"bgColor": "#323437",
"textColor": "#e2b714"
},
{
"name": "bushido",
"bgColor": "#414755",

63
public/themes/nausea.css Normal file
View file

@ -0,0 +1,63 @@
:root {
--bg-color: #323437;
--main-color: #e2b714;
--caret-color: #e2b714;
--sub-color: #646669;
--text-color: #d1d0c5;
--error-color: #ca4754;
--error-extra-color: #7e2a33;
--colorful-error-color: #ca4754;
--colorful-error-extra-color: #7e2a33;
}
@keyframes woah {
0% {
transform: rotateY(-15deg) skewY(10deg) rotateX(-15deg) scaleX(1.2) scaleY(.9);
}
25% {
transform: rotateY(15deg) skewY(-10deg) rotateX(15deg) scaleX(1) scaleY(.8);
}
50% {
transform: rotateY(-15deg) skewY(10deg) rotateX(-15deg) scaleX(0.9) scaleY(.9);
}
75% {
transform: rotateY(15deg) skewY(-10deg) rotateX(15deg) scaleX(1.5) scaleY(1.1);
}
100% {
transform: rotateY(-15deg) skewY(10deg) rotateX(-15deg) scaleX(1.2) scaleY(.9);
}
}
@keyframes plsstop {
0% {
background: #323437;
}
50% {
background: #3e4146;
}
100% {
background: #323437;
}
}
#middle {
animation: woah 7s infinite cubic-bezier(0.5, 0, 0.5, 1);
}
#centerContent {
transform: rotate(5deg);
perspective: 500px;
}
body {
animation: plsstop 10s infinite cubic-bezier(0.5, 0, 0.5, 1);
overflow: hidden;
}