Merge remote-tracking branch 'upstream/master'

This commit is contained in:
monkeytypegeorge 2021-04-09 17:33:15 +00:00
commit b273a5d4a5
55 changed files with 12019 additions and 10843 deletions

View file

@ -1,6 +1,6 @@
# monkeytype
![](https://github.com/Miodec/monkeytype/blob/master/static/images/mtsocial.png?raw=true)
[![](https://github.com/Miodec/monkeytype/blob/master/static/images/mtsocial.png?raw=true)](https://monkeytype.com/)
<br />
<img align="left" alt="JavaScript" width="26px" src="https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/javascript/javascript.png" />
@ -35,6 +35,13 @@ Recently, a Discord bot was added to autoassign roles on our server. You can fin
If you encounter a bug, or have a feature request - send me a message on Reddit, [create an issue](https://github.com/Miodec/monkeytype/issues), [create a discussion thread](https://github.com/Miodec/monkeytype/discussions), or [join the Discord server](https://www.discord.gg/monkeytype).
# Contribute
Refer to [CONTRIBUTING.md](https://github.com/Miodec/monkeytype/blob/master/CONTRIBUTING.md)
# Code Of Conduct
Before contributing to this repository please refer to [CODE_OF_CONDUCT.md](https://github.com/Miodec/monkeytype/blob/master/CODE_OF_CONDUCT.md)
# Credits
Montydrei for the name suggestion
@ -47,10 +54,4 @@ Contributors that have helped with implementing various features, adding themes
If you wish to support further development and feel extra awesome, you can do so [here](https://www.paypal.me/jackbartnik).
# Contribute
Refer to [CONTRIBUTING.md](https://github.com/Miodec/monkeytype/blob/master/CONTRIBUTING.md)
# Code Of Conduct
Before contributing to this repository please refer to [CODE_OF_CONDUCT.md](https://github.com/Miodec/monkeytype/blob/master/CODE_OF_CONDUCT.md)

View file

@ -1782,6 +1782,7 @@ exports.saveConfig = functions.https.onCall((request, response) => {
}
if (err) return;
if (key === "resultFilters") return;
if (key === "customBackground") return;
let val = obj[key];
if (Array.isArray(val)) {
val.forEach((valarr) => {
@ -2306,6 +2307,38 @@ exports.checkLeaderboards = functions.https.onRequest(
return;
}
request = request.body.data;
function verifyValue(val) {
let errCount = 0;
if (val === null || val === undefined) {
} else if (Array.isArray(val)) {
//array
val.forEach((val2) => {
errCount += verifyValue(val2);
});
} else if (typeof val === "object" && !Array.isArray(val)) {
//object
Object.keys(val).forEach((valkey) => {
errCount += verifyValue(val[valkey]);
});
} else {
if (!/^[0-9a-zA-Z._\-\+]+$/.test(val)) errCount++;
}
return errCount;
}
let errCount = verifyValue(request);
if (errCount > 0) {
console.error(
`error checking leaderboard for ${
request.uid
} error count ${errCount} - bad input - ${JSON.stringify(request.obj)}`
);
response.status(200).send({ data: {
status: -999,
message: "Bad input",
}});
return;
}
try {
if (request.emailVerified === false) {
@ -2421,10 +2454,10 @@ exports.checkLeaderboards = functions.https.onRequest(
console.error(
`error in transaction checking leaderboards - ${error}`
);
return {
response.status(200).send({ data: {
status: -999,
message: error,
};
}});
});
let daily = await db
@ -2499,10 +2532,10 @@ exports.checkLeaderboards = functions.https.onRequest(
console.error(
`error in transaction checking leaderboards - ${error}`
);
return {
response.status(200).send({ data: {
status: -999,
message: error,
};
}});
});
//send discord update

View file

@ -90,7 +90,6 @@ const refactoredSrc = [
"./src/js/cloud-functions.js",
"./src/js/misc.js",
"./src/js/layouts.js",
"./src/js/result-filters.js",
"./src/js/sound.js",
"./src/js/theme-colors.js",
"./src/js/chart-controller.js",
@ -106,11 +105,20 @@ const refactoredSrc = [
"./src/js/account-controller.js",
"./src/js/simple-popups.js",
"./src/js/settings.js",
"./src/js/input-controller.js",
"./src/js/route-controller.js",
"./src/js/ready.js",
"./src/js/account/all-time-stats.js",
"./src/js/account/pb-tables.js",
"./src/js/account/result-filters.js",
"./src/js/account/verification-controller.js",
"./src/js/account.js",
"./src/js/elements/monkey.js",
"./src/js/elements/notifications.js",
"./src/js/elements/leaderboards.js",
"./src/js/elements/account-icon.js",
"./src/js/elements/account-button.js",
"./src/js/elements/loader.js",
"./src/js/elements/sign-out-button.js",
@ -125,6 +133,7 @@ const refactoredSrc = [
"./src/js/popups/edit-tags-popup.js",
"./src/js/popups/custom-theme-popup.js",
"./src/js/popups/import-settings-popup.js",
"./src/js/popups/custom-background-filter.js",
"./src/js/settings/language-picker.js",
"./src/js/settings/theme-picker.js",
@ -156,12 +165,7 @@ const refactoredSrc = [
//legacy files
//the order of files is important
const globalSrc = [
"./src/js/global-dependencies.js",
"./src/js/account.js",
"./src/js/script.js",
"./src/js/exports.js",
];
const globalSrc = ["./src/js/global-dependencies.js", "./src/js/exports.js"];
//concatenates and lints legacy js files and writes the output to dist/gen/index.js
task("cat", function () {

View file

@ -1,4 +1,18 @@
import * as Notifications from "./notifications";
import * as UpdateConfig from "./config";
import * as AccountButton from "./account-button";
import * as Account from "./account";
import * as CommandlineLists from "./commandline-lists";
import * as VerificationController from "./verification-controller";
import * as Misc from "./misc";
import * as Settings from "./settings";
import * as ChallengeController from "./challenge-controller";
import Config from "./config";
import * as CloudFunctions from "./cloud-functions";
import * as AllTimeStats from "./all-time-stats";
import * as DB from "./db";
import * as TestLogic from "./test-logic";
import * as UI from "./ui";
var gmailProvider = new firebase.auth.GoogleAuthProvider();
@ -17,7 +31,7 @@ export function signIn() {
.auth()
.signInWithEmailAndPassword(email, password)
.then((e) => {
// changePage("test");
// UI.changePage("test");
})
.catch(function (error) {
Notifications.add(error.message, -1);
@ -34,7 +48,7 @@ export function signIn() {
.auth()
.signInWithEmailAndPassword(email, password)
.then((e) => {
// changePage("test");
// UI.changePage("test");
})
.catch(function (error) {
Notifications.add(error.message, -1);
@ -96,19 +110,255 @@ export function signOut() {
.signOut()
.then(function () {
Notifications.add("Signed out", 0, 2);
setTimeout(() => {
location.reload();
}, 1000);
//TODO Bring this back when possible
// clearGlobalStats();
// Settings.hideAccountSection();
// updateAccountLoginButton();
// changePage("login");
// DB.setSnapshot(null);
AllTimeStats.clear();
Settings.hideAccountSection();
AccountButton.update();
UI.changePage("login");
DB.setSnapshot(null);
})
.catch(function (error) {
Notifications.add(error.message, -1);
});
}
function signUp() {
$(".pageLogin .register .button").addClass("disabled");
$(".pageLogin .preloader").removeClass("hidden");
let nname = $(".pageLogin .register input")[0].value;
let email = $(".pageLogin .register input")[1].value;
let password = $(".pageLogin .register input")[2].value;
let passwordVerify = $(".pageLogin .register input")[3].value;
if (password != passwordVerify) {
Notifications.add("Passwords do not match", 0, 3);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .register .button").removeClass("disabled");
return;
}
CloudFunctions.namecheck({ name: nname }).then((d) => {
if (d.data.resultCode === -1) {
Notifications.add("Name unavailable", -1);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .register .button").removeClass("disabled");
return;
} else if (d.data.resultCode === -2) {
Notifications.add(
"Name cannot contain special characters or contain more than 14 characters. Can include _ . and -",
-1
);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .register .button").removeClass("disabled");
return;
} else if (d.data.resultCode === 1) {
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((user) => {
// Account has been created here.
// dontCheckUserName = true;
let usr = user.user;
usr
.updateProfile({
displayName: nname,
})
.then(async function () {
// Update successful.
await firebase
.firestore()
.collection("users")
.doc(usr.uid)
.set({ name: nname }, { merge: true });
CloudFunctions.reserveName({ name: nname, uid: usr.uid }).catch(
(e) => {
console.error("Could not reserve name " + e);
throw "Could not reserve name";
}
);
usr.sendEmailVerification();
AllTimeStats.clear();
Notifications.add("Account created", 1, 3);
$("#menu .icon-button.account .text").text(nname);
try {
firebase.analytics().logEvent("accountCreated", usr.uid);
} catch (e) {
console.log("Analytics unavailable");
}
$(".pageLogin .preloader").addClass("hidden");
DB.setSnapshot({
results: [],
personalBests: {},
tags: [],
globalStats: {
time: undefined,
started: undefined,
completed: undefined,
},
});
if (TestLogic.notSignedInLastResult !== null) {
TestLogic.setNotSignedInUid(usr.uid);
CloudFunctions.testCompleted({
uid: usr.uid,
obj: TestLogic.notSignedInLastResult,
});
DB.getSnapshot().results.push(TestLogic.notSignedInLastResult);
}
UI.changePage("account");
usr.sendEmailVerification();
$(".pageLogin .register .button").removeClass("disabled");
})
.catch(function (error) {
// An error happened.
$(".pageLogin .register .button").removeClass("disabled");
console.error(error);
usr
.delete()
.then(function () {
// User deleted.
Notifications.add(
"Account not created. " + error.message,
-1
);
$(".pageLogin .preloader").addClass("hidden");
})
.catch(function (error) {
// An error happened.
$(".pageLogin .preloader").addClass("hidden");
Notifications.add(
"Something went wrong. " + error.message,
-1
);
console.error(error);
});
});
})
.catch(function (error) {
// Handle Errors here.
$(".pageLogin .register .button").removeClass("disabled");
Notifications.add(error.message, -1);
$(".pageLogin .preloader").addClass("hidden");
});
} else {
$(".pageLogin .preloader").addClass("hidden");
Notifications.add(
"Something went wrong when checking name: " + d.data.message,
-1
);
}
});
}
$(".pageLogin #forgotPasswordButton").click((e) => {
let email = prompt("Email address");
if (email) {
firebase
.auth()
.sendPasswordResetEmail(email)
.then(function () {
// Email sent.
Notifications.add("Email sent", 1, 2);
})
.catch(function (error) {
// An error happened.
Notifications.add(error.message, -1);
});
}
});
$(".pageLogin .login input").keyup((e) => {
if (e.key == "Enter") {
UpdateConfig.setChangedBeforeDb(false);
signIn();
}
});
$(".pageLogin .login .button.signIn").click((e) => {
UpdateConfig.setChangedBeforeDb(false);
signIn();
});
$(".pageLogin .login .button.signInWithGoogle").click((e) => {
UpdateConfig.setChangedBeforeDb(false);
signInWithGoogle();
});
$(".signOut").click((e) => {
signOut();
});
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
// User is signed in.
$(".pageAccount .content p.accountVerificatinNotice").remove();
if (user.emailVerified === false) {
$(".pageAccount .content").prepend(
`<p class="accountVerificatinNotice" style="text-align:center">Your account is not verified. Click <a onClick="sendVerificationEmail()">here</a> to resend the verification email.`
);
}
AccountButton.update();
AccountButton.loading(true);
Account.getDataAndInit();
var displayName = user.displayName;
// var email = user.email;
// var emailVerified = user.emailVerified;
// var photoURL = user.photoURL;
// var isAnonymous = user.isAnonymous;
// var uid = user.uid;
// var providerData = user.providerData;
$(".pageLogin .preloader").addClass("hidden");
$("#menu .icon-button.account .text").text(displayName);
// showFavouriteThemesAtTheTop();
CommandlineLists.updateThemeCommands();
let text = "Account created on " + user.metadata.creationTime;
const date1 = new Date(user.metadata.creationTime);
const date2 = new Date();
const diffTime = Math.abs(date2 - date1);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
text += ` (${diffDays} day${diffDays != 1 ? "s" : ""} ago)`;
$(".pageAccount .group.createdDate").text(text);
if (VerificationController.data !== null) {
VerificationController.verify(user);
}
}
let theme = Misc.findGetParameter("customTheme");
if (theme !== null) {
try {
theme = theme.split(",");
UpdateConfig.setCustomThemeColors(theme);
Notifications.add("Custom theme applied.", 1);
} catch (e) {
Notifications.add(
"Something went wrong. Reverting to default custom colors.",
0
);
UpdateConfig.setCustomThemeColors(Config.defaultConfig.customThemeColors);
}
UpdateConfig.setCustomTheme(true);
Settings.setCustomThemeInputs();
}
if (/challenge_.+/g.test(window.location.pathname)) {
Notifications.add("Loading challenge", 0);
let challengeName = window.location.pathname.split("_")[1];
setTimeout(() => {
ChallengeController.setup(challengeName);
}, 1000);
}
});
$(".pageLogin .register input").keyup((e) => {
if ($(".pageLogin .register .button").hasClass("disabled")) return;
if (e.key == "Enter") {
signUp();
}
});
$(".pageLogin .register .button").click((e) => {
if ($(".pageLogin .register .button").hasClass("disabled")) return;
signUp();
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
import * as DB from "./db";
export function clear() {
$(".pageAccount .globalTimeTyping .val").text(`-`);
$(".pageAccount .globalTestsStarted .val").text(`-`);
$(".pageAccount .globalTestsCompleted .val").text(`-`);
}
export function update() {
if (DB.getSnapshot().globalStats.time != undefined) {
let th = Math.floor(DB.getSnapshot().globalStats.time / 3600);
let tm = Math.floor((DB.getSnapshot().globalStats.time % 3600) / 60);
let ts = Math.floor((DB.getSnapshot().globalStats.time % 3600) % 60);
$(".pageAccount .globalTimeTyping .val").text(`
${th < 10 ? "0" + th : th}:${tm < 10 ? "0" + tm : tm}:${
ts < 10 ? "0" + ts : ts
}
`);
}
if (DB.getSnapshot().globalStats.started != undefined) {
$(".pageAccount .globalTestsStarted .val").text(
DB.getSnapshot().globalStats.started
);
}
if (DB.getSnapshot().globalStats.completed != undefined) {
$(".pageAccount .globalTestsCompleted .val").text(
DB.getSnapshot().globalStats.completed
);
}
}

234
src/js/account/pb-tables.js Normal file
View file

@ -0,0 +1,234 @@
import * as DB from "./db";
export function update() {
$(".pageAccount .timePbTable tbody").html(`
<tr>
<td>15</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>30</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>60</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>120</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
`);
$(".pageAccount .wordsPbTable tbody").html(`
<tr>
<td>10</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>25</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>50</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>100</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
`);
const pb = DB.getSnapshot().personalBests;
let pbData;
let text;
text = "";
try {
pbData = pb.time[15].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>15</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>15</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.time[30].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>30</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>30</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.time[60].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>60</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>60</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.time[120].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>120</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>120</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
$(".pageAccount .timePbTable tbody").html(text);
text = "";
try {
pbData = pb.words[10].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>10</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>10</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.words[25].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>25</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>25</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.words[50].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>50</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>50</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
try {
pbData = pb.words[100].sort((a, b) => b.wpm - a.wpm)[0];
text += `<tr>
<td>100</td>
<td>${pbData.wpm}</td>
<td>${pbData.raw === undefined ? "-" : pbData.raw}</td>
<td>${pbData.acc === undefined ? "-" : pbData.acc + "%"}</td>
<td>
${pbData.consistency === undefined ? "-" : pbData.consistency + "%"}
</td>
</tr>`;
} catch (e) {
text += `<tr>
<td>100</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>`;
}
$(".pageAccount .wordsPbTable tbody").html(text);
}

View file

@ -0,0 +1,454 @@
import * as Misc from "./misc";
import * as DB from "./db";
import Config from "./config";
import * as Notifications from "./notifications";
import * as Account from "./account";
import * as Funbox from "./funbox";
let defaultResultFilters = {
difficulty: {
normal: true,
expert: true,
master: true,
},
mode: {
words: true,
time: true,
quote: true,
zen: true,
custom: true,
},
words: {
10: true,
25: true,
50: true,
100: true,
200: true,
custom: true,
},
time: {
15: true,
30: true,
60: true,
120: true,
custom: true,
},
quoteLength: {
short: true,
medium: true,
long: true,
thicc: true,
},
punctuation: {
on: true,
off: true,
},
numbers: {
on: true,
off: true,
},
date: {
last_day: false,
last_week: false,
last_month: false,
all: true,
},
tags: {
none: true,
},
language: {},
funbox: {
none: true,
},
};
export let filters;
Promise.all([Misc.getLanguageList(), Misc.getFunboxList()]).then((values) => {
let languages = values[0];
let funboxModes = values[1];
languages.forEach((language) => {
defaultResultFilters.language[language] = true;
});
funboxModes.forEach((funbox) => {
defaultResultFilters.funbox[funbox.name] = true;
});
filters = defaultResultFilters;
});
export function getFilters() {
return filters;
}
export function getGroup(group) {
return filters[group];
}
// export function setFilter(group, filter, value) {
// filters[group][filter] = value;
// }
export function getFilter(group, filter) {
return filters[group][filter];
}
// export function toggleFilter(group, filter) {
// filters[group][filter] = !filters[group][filter];
// }
export function loadTags(tags) {
tags.forEach((tag) => {
defaultResultFilters[tag.id] = true;
});
}
export function save() {
Misc.setCookie("resultFilters", JSON.stringify(filters), 365);
}
export function load() {
// let newTags = $.cookie("activeTags");
try {
let newResultFilters = Misc.getCookie("resultFilters");
if (newResultFilters !== undefined && newResultFilters !== "") {
filters = JSON.parse(newResultFilters);
save();
} else {
filters = defaultResultFilters;
save();
}
} catch {
filters = defaultResultFilters;
save();
}
}
export function reset() {
filters = defaultResultFilters;
save();
}
load();
export function updateActive() {
let aboveChartDisplay = {};
Object.keys(getFilters()).forEach((group) => {
aboveChartDisplay[group] = {
all: true,
array: [],
};
Object.keys(getGroup(group)).forEach((filter) => {
if (getFilter(group, filter)) {
aboveChartDisplay[group].array.push(filter);
} else {
aboveChartDisplay[group].all = false;
}
let buttonEl;
if (group === "date") {
buttonEl = $(
`.pageAccount .group.topFilters .filterGroup[group="${group}"] .button[filter="${filter}"]`
);
} else {
buttonEl = $(
`.pageAccount .group.filterButtons .filterGroup[group="${group}"] .button[filter="${filter}"]`
);
}
if (getFilter(group, filter)) {
buttonEl.addClass("active");
} else {
buttonEl.removeClass("active");
}
});
});
function addText(group) {
let ret = "";
ret += "<div class='group'>";
if (group == "difficulty") {
ret += `<span aria-label="Difficulty" data-balloon-pos="up"><i class="fas fa-fw fa-star"></i>`;
} else if (group == "mode") {
ret += `<span aria-label="Mode" data-balloon-pos="up"><i class="fas fa-fw fa-bars"></i>`;
} else if (group == "punctuation") {
ret += `<span aria-label="Punctuation" data-balloon-pos="up"><span class="punc" style="font-weight: 900;
width: 1.25rem;
text-align: center;
display: inline-block;
letter-spacing: -.1rem;">!?</span>`;
} else if (group == "numbers") {
ret += `<span aria-label="Numbers" data-balloon-pos="up"><span class="numbers" style="font-weight: 900;
width: 1.25rem;
text-align: center;
margin-right: .1rem;
display: inline-block;
letter-spacing: -.1rem;">15</span>`;
} else if (group == "words") {
ret += `<span aria-label="Words" data-balloon-pos="up"><i class="fas fa-fw fa-font"></i>`;
} else if (group == "time") {
ret += `<span aria-label="Time" data-balloon-pos="up"><i class="fas fa-fw fa-clock"></i>`;
} else if (group == "date") {
ret += `<span aria-label="Date" data-balloon-pos="up"><i class="fas fa-fw fa-calendar"></i>`;
} else if (group == "tags") {
ret += `<span aria-label="Tags" data-balloon-pos="up"><i class="fas fa-fw fa-tags"></i>`;
} else if (group == "language") {
ret += `<span aria-label="Language" data-balloon-pos="up"><i class="fas fa-fw fa-globe-americas"></i>`;
} else if (group == "funbox") {
ret += `<span aria-label="Funbox" data-balloon-pos="up"><i class="fas fa-fw fa-gamepad"></i>`;
}
if (aboveChartDisplay[group].all) {
ret += "all";
} else {
if (group === "tags") {
ret += aboveChartDisplay.tags.array
.map((id) => {
if (id == "none") return id;
let name = DB.getSnapshot().tags.filter((t) => t.id == id)[0];
if (name !== undefined) {
return DB.getSnapshot().tags.filter((t) => t.id == id)[0].name;
}
})
.join(", ");
} else {
ret += aboveChartDisplay[group].array.join(", ").replace(/_/g, " ");
}
}
ret += "</span></div>";
return ret;
}
let chartString = "";
//date
chartString += addText("date");
chartString += `<div class="spacer"></div>`;
//mode
chartString += addText("mode");
chartString += `<div class="spacer"></div>`;
//time
if (aboveChartDisplay.mode.array.includes("time")) {
chartString += addText("time");
chartString += `<div class="spacer"></div>`;
}
//words
if (aboveChartDisplay.mode.array.includes("words")) {
chartString += addText("words");
chartString += `<div class="spacer"></div>`;
}
//diff
chartString += addText("difficulty");
chartString += `<div class="spacer"></div>`;
//punc
chartString += addText("punctuation");
chartString += `<div class="spacer"></div>`;
//numbers
chartString += addText("numbers");
chartString += `<div class="spacer"></div>`;
//language
chartString += addText("language");
chartString += `<div class="spacer"></div>`;
//funbox
chartString += addText("funbox");
chartString += `<div class="spacer"></div>`;
//tags
chartString += addText("tags");
$(".pageAccount .group.chart .above").html(chartString);
Account.update();
}
export function toggle(group, filter) {
try {
if (group === "date") {
Object.keys(getGroup("date")).forEach((date) => {
filters["date"][date] = false;
});
}
filters[group][filter] = !filters[group][filter];
save();
} catch (e) {
Notifications.add(
"Something went wrong toggling filter. Reverting to defaults",
0
);
console.log("toggling filter error");
console.error(e);
reset();
updateActive();
}
}
export function updateTags() {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).empty();
if (DB.getSnapshot().tags.length > 0) {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").removeClass(
"hidden"
);
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="none">no tag</div>`);
DB.getSnapshot().tags.forEach((tag) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="${tag.id}">${tag.name}</div>`);
});
} else {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").addClass(
"hidden"
);
}
}
$(
".pageAccount .filterButtons .buttonsAndTitle .buttons, .pageAccount .group.topFilters .buttonsAndTitle.testDate .buttons"
).click(".button", (e) => {
const filter = $(e.target).attr("filter");
const group = $(e.target).parents(".buttons").attr("group");
if ($(e.target).hasClass("allFilters")) {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
if (group === "date") {
filters[group][filter] = false;
} else {
filters[group][filter] = true;
}
});
});
filters["date"]["all"] = true;
} else if ($(e.target).hasClass("noFilters")) {
Object.keys(getFilters()).forEach((group) => {
if (group !== "date") {
Object.keys(getGroup(group)).forEach((filter) => {
filters[group][filter] = false;
});
}
});
} else {
if (e.shiftKey) {
Object.keys(getGroup(group)).forEach((filter) => {
filters[group][filter] = false;
});
filters[group][filter] = true;
} else {
toggle(group, filter);
// filters[group][filter] = !filters[group][filter];
}
}
updateActive();
save();
});
$(".pageAccount .topFilters .button.allFilters").click((e) => {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
if (group === "date") {
filters[group][filter] = false;
} else {
filters[group][filter] = true;
}
});
});
filters["date"]["all"] = true;
updateActive();
save();
});
$(".pageAccount .topFilters .button.currentConfigFilter").click((e) => {
Object.keys(getFilters()).forEach((group) => {
Object.keys(getGroup(group)).forEach((filter) => {
filters[group][filter] = false;
});
});
filters["difficulty"][Config.difficulty] = true;
filters["mode"][Config.mode] = true;
if (Config.mode === "time") {
filters["time"][Config.time] = true;
} else if (Config.mode === "words") {
filters["words"][Config.words] = true;
} else if (Config.mode === "quote") {
Object.keys(getGroup("quoteLength")).forEach((ql) => {
filters["quoteLength"][ql] = true;
});
}
if (Config.punctuation) {
filters["punctuation"]["on"] = true;
} else {
filters["punctuation"]["off"] = true;
}
if (Config.numbers) {
filters["numbers"]["on"] = true;
} else {
filters["numbers"]["off"] = true;
}
if (Config.mode === "quote" && /english.*/.test(Config.language)) {
filters["language"]["english"] = true;
} else {
filters["language"][Config.language] = true;
}
if (Funbox.active === "none") {
filters.funbox.none = true;
} else {
filters.funbox[Funbox.active] = true;
}
filters["tags"]["none"] = true;
DB.getSnapshot().tags.forEach((tag) => {
if (tag.active === true) {
filters["tags"]["none"] = false;
filters["tags"][tag.id] = true;
}
});
filters["date"]["all"] = true;
updateActive();
save();
console.log(getFilters());
});
$(".pageAccount .topFilters .button.toggleAdvancedFilters").click((e) => {
$(".pageAccount .filterButtons").slideToggle(250);
$(".pageAccount .topFilters .button.toggleAdvancedFilters").toggleClass(
"active"
);
});
Misc.getLanguageList().then((languages) => {
languages.forEach((language) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.languages .buttons"
).append(
`<div class="button" filter="${language}">${language.replace(
"_",
" "
)}</div>`
);
});
});
$(
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .buttons"
).append(`<div class="button" filter="none">none</div>`);
Misc.getFunboxList().then((funboxModes) => {
funboxModes.forEach((funbox) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .buttons"
).append(
`<div class="button" filter="${funbox.name}">${funbox.name.replace(
/_/g,
" "
)}</div>`
);
});
});

View file

@ -0,0 +1,23 @@
import * as CloudFunctions from "./cloud-functions";
import * as Notifications from "./notifications";
import * as Settings from "./settings";
import * as DB from "./db";
export let data = null;
export function set(val) {
data = val;
}
export function verify(user) {
Notifications.add("Verifying", 0, 3);
data.uid = user.uid;
CloudFunctions.verifyUser(data).then((data) => {
if (data.data.status === 1) {
Notifications.add(data.data.message, 1);
DB.getSnapshot().discordId = data.data.did;
Settings.updateDiscordSection();
} else {
Notifications.add(data.data.message, -1);
}
});
}

View file

@ -61,7 +61,7 @@ if (Object.keys(layouts).length > 0) {
});
}
let commandsKeymapLayouts = {
export let commandsKeymapLayouts = {
title: "Change keymap layout...",
list: [
{
@ -126,7 +126,7 @@ let commandsFunbox = {
id: "changeFunboxNone",
display: "none",
exec: () => {
if (Funbox.activate("none", null)) {
if (Funbox.setFunbox("none", null)) {
TestLogic.restart();
}
},
@ -140,7 +140,7 @@ Misc.getFunboxList().then((funboxes) => {
id: "changeFunbox" + funbox.name,
display: funbox.name.replace(/_/g, " "),
exec: () => {
if (Funbox.activate(funbox.name, funbox.type)) {
if (Funbox.setFunbox(funbox.name, funbox.type)) {
TestLogic.restart();
}
},
@ -413,7 +413,7 @@ let commandsDifficulty = {
],
};
let commandsEnableAds = {
export let commandsEnableAds = {
title: "Set enable ads...",
list: [
{
@ -1117,7 +1117,7 @@ let commandsPageWidth = {
],
};
let themeCommands = {
export let themeCommands = {
title: "Change theme...",
list: [],
};
@ -1596,6 +1596,15 @@ export let defaultCommands = {
Commandline.show();
},
},
{
id: "changeCustomBackground",
display: "Change custom background...",
defaultValue: "",
input: true,
exec: (input) => {
UpdateConfig.setCustomBackground(input);
},
},
{
id: "changeTheme",
display: "Change theme...",

View file

@ -7,15 +7,18 @@ import * as TestUI from "./test-ui";
let commandLineMouseMode = false;
function showInput(command, placeholder) {
function showInput(command, placeholder, defaultValue = "") {
$("#commandLineWrapper").removeClass("hidden");
$("#commandLine").addClass("hidden");
$("#commandInput").removeClass("hidden");
$("#commandInput input").attr("placeholder", placeholder);
$("#commandInput input").val("");
$("#commandInput input").val(defaultValue);
$("#commandInput input").focus();
$("#commandInput input").attr("command", "");
$("#commandInput input").attr("command", command);
if (defaultValue != ""){
$("#commandInput input").select();
}
}
function showFound() {
@ -142,7 +145,7 @@ function trigger(command) {
if (obj.id == command) {
if (obj.input) {
input = true;
showInput(obj.id, obj.display);
showInput(obj.id, obj.display, obj.defaultValue);
} else {
obj.exec();
if (obj.subgroup !== null && obj.subgroup !== undefined) {
@ -498,6 +501,6 @@ $(document).keydown((e) => {
});
$(document).on("click", "#commandLineMobileButton", () => {
CommandlineLists.setCurrent(CommandlineLists.defaultCommands);
CommandlineLists.setCurrent([CommandlineLists.defaultCommands]);
show();
});

View file

@ -15,6 +15,8 @@ import * as LanguagePicker from "./language-picker";
import * as TestLogic from "./test-logic";
import * as PaceCaret from "./pace-caret";
import * as UI from "./ui";
import * as CommandlineLists from "./commandline-lists";
import * as BackgroundFilter from "./custom-background-filter";
export let cookieConfig = null;
export let dbConfigLoaded = false;
@ -75,11 +77,11 @@ let defaultConfig = {
savedLayout: "default",
confidenceMode: "off",
indicateTypos: false,
timerStyle: "text",
timerStyle: "mini",
colorfulMode: false,
randomTheme: "off",
timerColor: "black",
timerOpacity: "0.25",
timerColor: "main",
timerOpacity: "1",
stopOnError: "off",
showAllLines: false,
keymapMode: "off",
@ -113,6 +115,9 @@ let defaultConfig = {
monkey: false,
repeatQuotes: "off",
oppositeShiftMode: "off",
customBackground: "",
customBackgroundSize: "cover",
customBackgroundFilter: [0, 1, 1, 1, 1],
};
function isConfigKeyValid(name) {
@ -472,6 +477,10 @@ export function setPaceCaret(val, nosave) {
if (val == undefined) {
val = "off";
}
// if (val == "pb" && firebase.auth().currentUser === null) {
// Notifications.add("PB pace caret is unavailable without an account", 0);
// return;
// }
// if (config.mode === "zen" && val != "off") {
// Notifications.add(`Can't use pace caret with zen mode.`, 0);
// val = "off";
@ -833,7 +842,7 @@ export function toggleHideExtraLetters() {
export function setTimerStyle(style, nosave) {
if (style == null || style == undefined) {
style = "bar";
style = "mini";
}
config.timerStyle = style;
if (!nosave) saveToCookie();
@ -1148,12 +1157,17 @@ export function setIndicateTypos(it, nosave) {
export function setCustomTheme(boolean, nosave) {
if (boolean !== undefined) config.customTheme = boolean;
if (boolean) {
ThemeController.set("custom");
} else if (!boolean && !nosave) {
ThemeController.set(config.theme);
}
if (!nosave) saveToCookie();
}
export function setTheme(name, nosave) {
config.theme = name;
setCustomTheme(false, true);
setCustomTheme(false, true, true);
ThemeController.set(config.theme);
if (!nosave) saveToCookie();
}
@ -1338,6 +1352,44 @@ export function setFontSize(fontSize, nosave) {
if (!nosave) saveToCookie();
}
export function setCustomBackground(value, nosave) {
if (value == null || value == undefined) {
value = "";
}
value = value.trim();
if (
/(https|http):\/\/(www\.|).+\..+\/.+(\.png|\.gif|\.jpeg|\.jpg)/gi.test(
value
) ||
value == ""
) {
config.customBackground = value;
CommandlineLists.defaultCommands.list.filter(
(command) => command.id == "changeCustomBackground"
)[0].defaultValue = value;
ThemeController.applyCustomBackground();
if (!nosave) saveToCookie();
} else {
Notifications.add("Invalid custom background URL", 0);
}
}
export function setCustomBackgroundSize(value, nosave) {
if (value != "cover" && value != "contain" && value != "max") {
value = "cover";
}
config.customBackgroundSize = value;
ThemeController.applyCustomBackgroundSize();
if (!nosave) saveToCookie();
}
export function setCustomBackgroundFilter(array, nosave) {
config.customBackgroundFilter = array;
BackgroundFilter.loadConfig(config.customBackgroundFilter);
BackgroundFilter.apply();
if (!nosave) saveToCookie();
}
export function apply(configObj) {
if (configObj == null || configObj == undefined) {
Notifications.add("Could not apply config", -1, 3);
@ -1350,8 +1402,11 @@ export function apply(configObj) {
});
if (configObj && configObj != null && configObj != "null") {
setTheme(configObj.theme, true);
setCustomTheme(configObj.customTheme, true);
setCustomThemeColors(configObj.customThemeColors, true);
setCustomTheme(configObj.customTheme, true, true);
setCustomBackground(configObj.customBackground, true);
setCustomBackgroundSize(configObj.customBackgroundSize, true);
setCustomBackgroundFilter(configObj.customBackgroundFilter, true);
setQuickTabMode(configObj.quickTab, true);
setKeyTips(configObj.showKeyTips, true);
setTimeConfig(configObj.time, true);
@ -1626,6 +1681,10 @@ export function loadFromCookie() {
loadDone();
}
export function setConfig(newConfig) {
config = newConfig;
}
export let loadPromise = new Promise((v) => {
loadDone = v;
});

View file

@ -1,5 +1,5 @@
import { loadTags } from "./result-filters";
import * as AccountButton from "./account-icon";
import * as AccountButton from "./account-button";
import * as CloudFunctions from "./cloud-functions";
import * as Notifications from "./notifications";
@ -17,8 +17,12 @@ export function getSnapshot() {
}
export function setSnapshot(newSnapshot) {
delete newSnapshot.banned;
delete newSnapshot.verified;
try {
delete newSnapshot.banned;
} catch {}
try {
delete newSnapshot.verified;
} catch {}
dbSnapshot = newSnapshot;
}

View file

@ -10,3 +10,5 @@ global.snapshot = DB.getSnapshot;
global.config = Config;
// global.addnotif = Notifications.add;
global.link = AccountController.linkWithGoogle;
global.filters = ResultFilters.filters;

View file

@ -9,45 +9,14 @@ Chart.plugins.register(chartAnnotation);
import * as DB from "./db";
import * as Misc from "./misc";
import * as CloudFunctions from "./cloud-functions";
import * as Monkey from "./monkey";
import * as Notifications from "./notifications";
import * as ResultFilters from "./result-filters";
import * as Leaderboards from "./leaderboards";
import * as Sound from "./sound";
import * as CustomText from "./custom-text";
import * as ShiftTracker from "./shift-tracker";
import * as TestStats from "./test-stats";
import * as ThemeColors from "./theme-colors";
import * as ChartController from "./chart-controller";
import * as Caret from "./caret";
import * as ManualRestart from "./manual-restart-tracker";
import Config, * as UpdateConfig from "./config";
import * as Focus from "./focus";
import * as AccountButton from "./account-icon";
import * as TestUI from "./test-ui";
import * as Keymap from "./keymap";
import Config from "./config";
import * as SimplePopups from "./simple-popups";
import * as AccountController from "./account-controller";
import "./caps-warning";
import * as LiveAcc from "./live-acc";
import * as TimerProgress from "./timer-progress";
import * as TestLogic from "./test-logic";
import * as Funbox from "./funbox";
import * as PaceCaret from "./pace-caret";
import * as TagController from "./tag-controller";
import * as TestTimer from "./test-timer";
import * as UI from "./ui";
import * as CommandlineLists from "./commandline-lists";
import * as ChallengeController from "./challenge-controller";
import * as TestConfig from "./test-config";
import * as MiniResultChart from "./mini-result-chart";
import * as SignOutButton from "./sign-out-button";
import "./support-popup";
import "./version-popup";
import * as LayoutEmulator from "./layout-emulator";
import * as AccountController from "./account-controller";
import * as ResultTagsPopup from "./result-tags-popup";
import * as Settings from "./settings";
import * as SimplePopups from "./simple-popups";
import * as ThemePicker from "./theme-picker";
import "./custom-theme-popup";
import "./import-settings-popup";
import "./input-controller";
import "./ready";

View file

@ -1,129 +1,25 @@
//test timer
//ui
let verifyUserWhenLoggedIn = null;
///
// let CustomText = "The quick brown fox jumps over the lazy dog".split(" ");
// let CustomText.isWordRandom = false;
// let CustomText.word = 1;
(function (history) {
var pushState = history.pushState;
history.pushState = function (state) {
if (Funbox.active === "memory" && state !== "/") {
Funbox.resetMemoryTimer();
}
return pushState.apply(history, arguments);
};
})(window.history);
function changePage(page) {
if (UI.pageTransition) {
return;
}
let activePage = $(".page.active");
$(".page").removeClass("active");
$("#wordsInput").focusout();
if (page == "test" || page == "") {
UI.setPageTransition(true);
UI.swapElements(
activePage,
$(".page.pageTest"),
250,
() => {
UI.setPageTransition(false);
TestUI.focusWords();
$(".page.pageTest").addClass("active");
history.pushState("/", null, "/");
},
() => {
TestConfig.show();
}
);
SignOutButton.hide();
// restartCount = 0;
// incompleteTestSeconds = 0;
TestStats.resetIncomplete();
ManualRestart.set();
TestLogic.restart();
} else if (page == "about") {
UI.setPageTransition(true);
TestLogic.restart();
UI.swapElements(activePage, $(".page.pageAbout"), 250, () => {
UI.setPageTransition(false);
history.pushState("about", null, "about");
$(".page.pageAbout").addClass("active");
});
TestConfig.hide();
SignOutButton.hide();
} else if (page == "settings") {
UI.setPageTransition(true);
TestLogic.restart();
UI.swapElements(activePage, $(".page.pageSettings"), 250, () => {
UI.setPageTransition(false);
history.pushState("settings", null, "settings");
$(".page.pageSettings").addClass("active");
});
Settings.update();
TestConfig.hide();
SignOutButton.hide();
} else if (page == "account") {
if (!firebase.auth().currentUser) {
changePage("login");
} else {
UI.setPageTransition(true);
TestLogic.restart();
UI.swapElements(
activePage,
$(".page.pageAccount"),
250,
() => {
UI.setPageTransition(false);
history.pushState("account", null, "account");
$(".page.pageAccount").addClass("active");
},
() => {
SignOutButton.show();
}
);
refreshAccountPage();
TestConfig.hide();
}
} else if (page == "login") {
if (firebase.auth().currentUser != null) {
changePage("account");
} else {
UI.setPageTransition(true);
TestLogic.restart();
UI.swapElements(activePage, $(".page.pageLogin"), 250, () => {
UI.setPageTransition(false);
history.pushState("login", null, "login");
$(".page.pageLogin").addClass("active");
});
TestConfig.hide();
SignOutButton.hide();
}
}
}
$(window).on("popstate", (e) => {
let state = e.originalEvent.state;
if (state == "" || state == "/") {
// show test
changePage("test");
} else if (state == "about") {
// show about
changePage("about");
} else if (state == "account" || state == "login") {
if (firebase.auth().currentUser) {
changePage("account");
} else {
changePage("login");
}
}
});
import * as TestLogic from "./test-logic";
import * as TestUI from "./test-ui";
import * as TestStats from "./test-stats";
import * as Monkey from "./monkey";
import Config, * as UpdateConfig from "./config";
import * as Keymap from "./keymap";
import * as Misc from "./misc";
import * as LiveAcc from "./live-acc";
import * as Funbox from "./funbox";
import * as Sound from "./sound";
import * as Caret from "./caret";
import * as ManualRestart from "./manual-restart-tracker";
import * as Notifications from "./notifications";
import * as CustomText from "./custom-text";
import * as UI from "./ui";
import * as Settings from "./settings";
import * as LayoutEmulator from "./layout-emulator";
import * as PaceCaret from "./pace-caret";
import * as TimerProgress from "./timer-progress";
import * as TestTimer from "./test-timer";
import * as Focus from "./focus";
import * as ShiftTracker from "./shift-tracker";
$("#wordsInput").keypress((event) => {
event.preventDefault();
@ -131,106 +27,6 @@ $("#wordsInput").keypress((event) => {
let dontInsertSpace = false;
$(document).keyup((event) => {
if (!event.originalEvent.isTrusted) return;
if (TestUI.resultVisible) return;
let now = performance.now();
let diff = Math.abs(TestStats.keypressTimings.duration.current - now);
if (TestStats.keypressTimings.duration.current !== -1) {
TestStats.pushKeypressDuration(diff);
// keypressStats.duration.array.push(diff);
}
TestStats.setKeypressDuration(now);
// keypressStats.duration.current = now;
Monkey.stop();
});
$(document).keydown(function (event) {
if (!(event.key == " ") && !event.originalEvent.isTrusted) return;
if (!TestUI.resultVisible) {
TestStats.recordKeypressSpacing();
}
Monkey.type();
//autofocus
let pageTestActive = !$(".pageTest").hasClass("hidden");
let commandLineVisible = !$("#commandLineWrapper").hasClass("hidden");
let wordsFocused = $("#wordsInput").is(":focus");
let modePopupVisible =
!$("#customTextPopupWrapper").hasClass("hidden") ||
!$("#customWordAmountPopupWrapper").hasClass("hidden") ||
!$("#customTestDurationPopupWrapper").hasClass("hidden") ||
!$("#quoteSearchPopupWrapper").hasClass("hidden") ||
!$("#wordFilterPopupWrapper").hasClass("hidden");
if (
pageTestActive &&
!commandLineVisible &&
!modePopupVisible &&
!TestUI.resultVisible &&
!wordsFocused &&
event.key !== "Enter"
) {
TestUI.focusWords();
wordsFocused = true;
// if (Config.showOutOfFocusWarning) return;
}
//tab
if (
(event.key == "Tab" && !Config.swapEscAndTab) ||
(event.key == "Escape" && Config.swapEscAndTab)
) {
handleTab(event);
// event.preventDefault();
}
//blocking firefox from going back in history with backspace
if (event.key === "Backspace" && wordsFocused) {
let t = /INPUT|SELECT|TEXTAREA/i;
if (
!t.test(event.target.tagName) ||
event.target.disabled ||
event.target.readOnly
) {
event.preventDefault();
}
}
// keypressStats.duration.current = performance.now();
TestStats.setKeypressDuration(performance.now());
if (TestUI.testRestarting) {
return;
}
//backspace
const isBackspace =
event.key === "Backspace" ||
(Config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace && wordsFocused) {
handleBackspace(event);
}
if (event.key === "Enter" && Funbox.active === "58008" && wordsFocused) {
event.key = " ";
}
//space or enter
if (event.key === " " && wordsFocused) {
handleSpace(event, false);
}
if (wordsFocused && !commandLineVisible) {
handleAlpha(event);
}
let acc = Misc.roundTo2(TestStats.calculateAccuracy());
LiveAcc.update(acc);
});
function handleTab(event) {
if (TestUI.resultCalculating) {
event.preventDefault();
@ -256,96 +52,42 @@ function handleTab(event) {
// );
return;
} else if (
$(".pageTest").hasClass("active") &&
!TestUI.resultCalculating &&
$("#commandLineWrapper").hasClass("hidden") &&
$("#simplePopupWrapper").hasClass("hidden")
) {
if (Config.quickTab) {
if (Config.mode == "zen" && !event.shiftKey) {
//ignore
} else {
if (event.shiftKey) ManualRestart.set();
if (
TestLogic.active &&
Config.repeatQuotes === "typing" &&
Config.mode === "quote"
) {
TestLogic.restart(true, false, event);
if ($(".pageTest").hasClass("active")) {
if (Config.quickTab) {
if (Config.mode == "zen" && !event.shiftKey) {
//ignore
} else {
TestLogic.restart(false, false, event);
if (event.shiftKey) ManualRestart.set();
event.preventDefault();
if (
TestLogic.active &&
Config.repeatQuotes === "typing" &&
Config.mode === "quote"
) {
TestLogic.restart(true, false, event);
} else {
TestLogic.restart(false, false, event);
}
}
} else {
if (
!TestUI.resultVisible &&
((TestLogic.hasTab && event.shiftKey) ||
(!TestLogic.hasTab && Config.mode !== "zen") ||
(Config.mode === "zen" && event.shiftKey))
) {
event.preventDefault();
$("#restartTestButton").focus();
}
}
} else {
if (
!TestUI.resultVisible &&
((TestLogic.hasTab && event.shiftKey) ||
(!TestLogic.hasTab && Config.mode !== "zen") ||
(Config.mode === "zen" && event.shiftKey))
) {
event.preventDefault();
$("#restartTestButton").focus();
}
} else if (Config.quickTab) {
UI.changePage("test");
}
} else if (Config.quickTab) {
changePage("test");
}
// } else if (
// !event.ctrlKey &&
// (
// (!event.shiftKey && !TestLogic.hasTab) ||
// (event.shiftKey && TestLogic.hasTab) ||
// TestUI.resultVisible
// ) &&
// Config.quickTab &&
// !$(".pageLogin").hasClass("active") &&
// !resultCalculating &&
// $("#commandLineWrapper").hasClass("hidden") &&
// $("#simplePopupWrapper").hasClass("hidden")
// ) {
// event.preventDefault();
// if ($(".pageTest").hasClass("active")) {
// if (
// (Config.mode === "words" && Config.words < 1000) ||
// (Config.mode === "time" && Config.time < 3600) ||
// Config.mode === "quote" ||
// (Config.mode === "custom" &&
// CustomText.isWordRandom &&
// CustomText.word < 1000) ||
// (Config.mode === "custom" &&
// CustomText.isTimeRandom &&
// CustomText.time < 3600) ||
// (Config.mode === "custom" &&
// !CustomText.isWordRandom &&
// CustomText.text.length < 1000)
// ) {
// if (TestLogic.active) {
// let testNow = performance.now();
// let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
// let afkseconds = keypressPerSecond.filter(
// (x) => x.count == 0 && x.mod == 0
// ).length;
// incompleteTestSeconds += testSeconds - afkseconds;
// restartCount++;
// }
// TestLogic.restart();
// } else {
// Notifications.add("Quick restart disabled for long tests", 0);
// }
// } else {
// changePage("test");
// }
// } else if (
// !Config.quickTab &&
// TestLogic.hasTab &&
// event.shiftKey &&
// !TestUI.resultVisible
// ) {
// event.preventDefault();
// $("#restartTestButton").focus();
// }
}
function handleBackspace(event) {
@ -966,81 +708,102 @@ function handleAlpha(event) {
Caret.updatePosition();
}
ManualRestart.set();
UpdateConfig.loadFromCookie();
Misc.getReleasesFromGitHub();
// getPatreonNames();
$(document).keyup((event) => {
if (!event.originalEvent.isTrusted) return;
let mappedRoutes = {
"/": "pageTest",
"/login": "pageLogin",
"/settings": "pageSettings",
"/about": "pageAbout",
"/account": "pageAccount",
"/verify": "pageTest",
};
function handleInitialPageClasses(el) {
$(el).removeClass("hidden");
$(el).addClass("active");
}
$(document).ready(() => {
handleInitialPageClasses(
$(".page." + mappedRoutes[window.location.pathname])
);
if (window.location.pathname === "/") {
$("#top .config").removeClass("hidden");
if (TestUI.resultVisible) return;
let now = performance.now();
let diff = Math.abs(TestStats.keypressTimings.duration.current - now);
if (TestStats.keypressTimings.duration.current !== -1) {
TestStats.pushKeypressDuration(diff);
// keypressStats.duration.array.push(diff);
}
$("body").css("transition", ".25s");
if (Config.quickTab) {
$("#restartTestButton").addClass("hidden");
}
if (!Misc.getCookie("merchbannerclosed")) {
$(".merchBanner").removeClass("hidden");
} else {
$(".merchBanner").remove();
}
$("#centerContent")
.css("opacity", "0")
.removeClass("hidden")
.stop(true, true)
.animate({ opacity: 1 }, 250, () => {
if (window.location.pathname === "/verify") {
const fragment = new URLSearchParams(window.location.hash.slice(1));
if (fragment.has("access_token")) {
const accessToken = fragment.get("access_token");
const tokenType = fragment.get("token_type");
verifyUserWhenLoggedIn = {
accessToken: accessToken,
tokenType: tokenType,
};
history.replaceState("/", null, "/");
}
} else if (window.location.pathname === "/account") {
// history.replaceState("/", null, "/");
} else if (/challenge_.+/g.test(window.location.pathname)) {
//do nothing
// }
} else if (window.location.pathname !== "/") {
let page = window.location.pathname.replace("/", "");
changePage(page);
}
});
Settings.settingsFillPromise.then(Settings.update);
TestStats.setKeypressDuration(now);
// keypressStats.duration.current = now;
Monkey.stop();
});
//TODO move after account is a module
$(document).on("click", "#top .logo", (e) => {
changePage("test");
});
$(document).keydown(function (event) {
if (!(event.key == " ") && !event.originalEvent.isTrusted) return;
$(document).on("click", "#top #menu .icon-button", (e) => {
if ($(e.currentTarget).hasClass("leaderboards")) {
Leaderboards.show();
} else {
const href = $(e.currentTarget).attr("href");
ManualRestart.set();
changePage(href.replace("/", ""));
if (!TestUI.resultVisible) {
TestStats.recordKeypressSpacing();
}
Monkey.type();
//autofocus
let pageTestActive = !$(".pageTest").hasClass("hidden");
let commandLineVisible = !$("#commandLineWrapper").hasClass("hidden");
let wordsFocused = $("#wordsInput").is(":focus");
let modePopupVisible =
!$("#customTextPopupWrapper").hasClass("hidden") ||
!$("#customWordAmountPopupWrapper").hasClass("hidden") ||
!$("#customTestDurationPopupWrapper").hasClass("hidden") ||
!$("#quoteSearchPopupWrapper").hasClass("hidden") ||
!$("#wordFilterPopupWrapper").hasClass("hidden");
if (
pageTestActive &&
!commandLineVisible &&
!modePopupVisible &&
!TestUI.resultVisible &&
!wordsFocused &&
event.key !== "Enter"
) {
TestUI.focusWords();
wordsFocused = true;
// if (Config.showOutOfFocusWarning) return;
}
//tab
if (
(event.key == "Tab" && !Config.swapEscAndTab) ||
(event.key == "Escape" && Config.swapEscAndTab)
) {
handleTab(event);
// event.preventDefault();
}
//blocking firefox from going back in history with backspace
if (event.key === "Backspace" && wordsFocused) {
let t = /INPUT|SELECT|TEXTAREA/i;
if (
!t.test(event.target.tagName) ||
event.target.disabled ||
event.target.readOnly
) {
event.preventDefault();
}
}
// keypressStats.duration.current = performance.now();
TestStats.setKeypressDuration(performance.now());
if (TestUI.testRestarting) {
return;
}
//backspace
const isBackspace =
event.key === "Backspace" ||
(Config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace && wordsFocused) {
handleBackspace(event);
}
if (event.key === "Enter" && Funbox.active === "58008" && wordsFocused) {
event.key = " ";
}
//space or enter
if (event.key === " " && wordsFocused) {
handleSpace(event, false);
}
if (wordsFocused && !commandLineVisible) {
handleAlpha(event);
}
let acc = Misc.roundTo2(TestStats.calculateAccuracy());
LiveAcc.update(acc);
});

View file

@ -0,0 +1,118 @@
import * as UpdateConfig from "./config";
import * as Notifications from "./notifications";
let filters = {
blur: {
value: 0,
default: 0,
},
brightness: {
value: 1,
default: 1,
},
saturate: {
value: 1,
default: 1,
},
opacity: {
value: 1,
default: 1,
},
};
export function getCSS() {
let ret = "";
Object.keys(filters).forEach((filterKey) => {
if (filters[filterKey].value != filters[filterKey].default) {
ret += `${filterKey}(${filters[filterKey].value}${
filterKey == "blur" ? "rem" : ""
}) `;
}
});
return ret;
}
export function apply() {
let filterCSS = getCSS();
$(".customBackground").css({
filter: filterCSS,
});
}
function syncSliders() {
$(".section.customBackgroundFilter .blur input").val(filters["blur"].value);
$(".section.customBackgroundFilter .brightness input").val(
filters["brightness"].value
);
$(".section.customBackgroundFilter .saturate input").val(
filters["saturate"].value
);
$(".section.customBackgroundFilter .opacity input").val(
filters["opacity"].value
);
}
$(".section.customBackgroundFilter .blur input").on("input", (e) => {
filters["blur"].value = $(
".section.customBackgroundFilter .blur input"
).val();
updateNumbers();
apply();
});
$(".section.customBackgroundFilter .brightness input").on("input", (e) => {
filters["brightness"].value = $(
".section.customBackgroundFilter .brightness input"
).val();
updateNumbers();
apply();
});
$(".section.customBackgroundFilter .saturate input").on("input", (e) => {
filters["saturate"].value = $(
".section.customBackgroundFilter .saturate input"
).val();
updateNumbers();
apply();
});
$(".section.customBackgroundFilter .opacity input").on("input", (e) => {
filters["opacity"].value = $(
".section.customBackgroundFilter .opacity input"
).val();
updateNumbers();
apply();
});
$(".section.customBackgroundFilter .save.button").click((e) => {
let arr = [];
Object.keys(filters).forEach((filterKey) => {
arr.push(filters[filterKey].value);
});
UpdateConfig.setCustomBackgroundFilter(arr, false);
Notifications.add("Custom background filters saved", 1);
});
export function loadConfig(config) {
filters.blur.value = config[0];
filters.brightness.value = config[1];
filters.saturate.value = config[2];
filters.opacity.value = config[3];
updateNumbers();
syncSliders();
}
function updateNumbers() {
$(".section.customBackgroundFilter .blur .value").html(
parseFloat(filters.blur.value).toFixed(1)
);
$(".section.customBackgroundFilter .brightness .value").html(
parseFloat(filters.brightness.value).toFixed(1)
);
$(".section.customBackgroundFilter .saturate .value").html(
parseFloat(filters.saturate.value).toFixed(1)
);
$(".section.customBackgroundFilter .opacity .value").html(
parseFloat(filters.opacity.value).toFixed(1)
);
}

54
src/js/ready.js Normal file
View file

@ -0,0 +1,54 @@
import * as ManualRestart from "./manual-restart-tracker";
import Config, * as UpdateConfig from "./config";
import * as Misc from "./misc";
import * as VerificationController from "./verification-controller";
import * as Settings from "./settings";
import * as RouteController from "./route-controller";
import * as UI from "./ui";
ManualRestart.set();
UpdateConfig.loadFromCookie();
Misc.getReleasesFromGitHub();
$(document).ready(() => {
RouteController.handleInitialPageClasses(window.location.pathname);
if (window.location.pathname === "/") {
$("#top .config").removeClass("hidden");
}
$("body").css("transition", ".25s");
if (Config.quickTab) {
$("#restartTestButton").addClass("hidden");
}
if (!Misc.getCookie("merchbannerclosed")) {
$(".merchBanner").removeClass("hidden");
} else {
$(".merchBanner").remove();
}
$("#centerContent")
.css("opacity", "0")
.removeClass("hidden")
.stop(true, true)
.animate({ opacity: 1 }, 250, () => {
if (window.location.pathname === "/verify") {
const fragment = new URLSearchParams(window.location.hash.slice(1));
if (fragment.has("access_token")) {
const accessToken = fragment.get("access_token");
const tokenType = fragment.get("token_type");
VerificationController.set({
accessToken: accessToken,
tokenType: tokenType,
});
history.replaceState("/", null, "/");
}
} else if (window.location.pathname === "/account") {
// history.replaceState("/", null, "/");
} else if (/challenge_.+/g.test(window.location.pathname)) {
//do nothing
// }
} else if (window.location.pathname !== "/") {
let page = window.location.pathname.replace("/", "");
UI.changePage(page);
}
});
Settings.settingsFillPromise.then(Settings.update);
});

View file

@ -1,149 +0,0 @@
import * as Misc from "./misc";
import * as DB from "./db";
let defaultResultFilters = {
difficulty: {
normal: true,
expert: true,
master: true,
},
mode: {
words: true,
time: true,
quote: true,
custom: true,
},
words: {
10: true,
25: true,
50: true,
100: true,
200: true,
custom: true,
},
time: {
15: true,
30: true,
60: true,
120: true,
custom: true,
},
quoteLength: {
short: true,
medium: true,
long: true,
thicc: true,
},
punctuation: {
on: true,
off: true,
},
numbers: {
on: true,
off: true,
},
date: {
last_day: false,
last_week: false,
last_month: false,
all: true,
},
tags: {
none: true,
},
language: {},
funbox: {
none: true,
},
};
let filters = defaultResultFilters;
Misc.getLanguageList().then((languages) => {
languages.forEach((language) => {
defaultResultFilters.language[language] = true;
});
});
Misc.getFunboxList().then((funboxModes) => {
funboxModes.forEach((funbox) => {
defaultResultFilters.funbox[funbox.name] = true;
});
});
export function getFilters() {
return filters;
}
export function getGroup(group) {
return filters[group];
}
export function setFilter(group, filter, value) {
filters[group][filter] = value;
}
export function getFilter(group, filter) {
return filters[group][filter];
}
export function toggleFilter(group, filter) {
filters[group][filter] = !filters[group][filter];
}
export function loadTags(tags) {
tags.forEach((tag) => {
defaultResultFilters.tags[tag.id] = true;
});
}
export function save() {
Misc.setCookie("resultFilters", JSON.stringify(filters), 365);
}
export function load() {
// let newTags = $.cookie("activeTags");
try {
let newResultFilters = Misc.getCookie("resultFilters");
if (newResultFilters !== undefined && newResultFilters !== "") {
filters = JSON.parse(newResultFilters);
save();
} else {
filters = defaultResultFilters;
save();
}
} catch {
filters = defaultResultFilters;
save();
}
}
export function reset() {
filters = defaultResultFilters;
save();
}
load();
export function updateTags() {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).empty();
if (DB.getSnapshot().tags.length > 0) {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").removeClass(
"hidden"
);
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="none">no tag</div>`);
DB.getSnapshot().tags.forEach((tag) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.tags .buttons"
).append(`<div class="button" filter="${tag.id}">${tag.name}</div>`);
});
} else {
$(".pageAccount .content .filterButtons .buttonsAndTitle.tags").addClass(
"hidden"
);
}
}

View file

@ -0,0 +1,44 @@
import * as Funbox from "./funbox";
import * as UI from "./ui";
let mappedRoutes = {
"/": "pageTest",
"/login": "pageLogin",
"/settings": "pageSettings",
"/about": "pageAbout",
"/account": "pageAccount",
"/verify": "pageTest",
};
export function handleInitialPageClasses(pathname) {
let el = $(".page." + mappedRoutes[pathname]);
$(el).removeClass("hidden");
$(el).addClass("active");
}
(function (history) {
var pushState = history.pushState;
history.pushState = function (state) {
if (Funbox.active === "memory" && state !== "/") {
Funbox.resetMemoryTimer();
}
return pushState.apply(history, arguments);
};
})(window.history);
$(window).on("popstate", (e) => {
let state = e.originalEvent.state;
if (state == "" || state == "/") {
// show test
UI.changePage("test");
} else if (state == "about") {
// show about
UI.changePage("about");
} else if (state == "account" || state == "login") {
if (firebase.auth().currentUser) {
UI.changePage("account");
} else {
UI.changePage("login");
}
}
});

View file

@ -267,6 +267,10 @@ async function initGroups() {
"alwaysShowCPM",
UpdateConfig.setAlwaysShowCPM
);
groups.customBackgroundSize = new SettingsGroup(
"customBackgroundSize",
UpdateConfig.setCustomBackgroundSize
);
}
async function fillSettingsPage() {
@ -369,6 +373,10 @@ async function fillSettingsPage() {
})
.appendTo(fontsEl);
});
$(".pageSettings .section.customBackgroundSize input").val(
Config.customBackground
);
}
export let settingsFillPromise = fillSettingsPage();
@ -420,7 +428,7 @@ export function updateDiscordSection() {
function setActiveFunboxButton() {
$(`.pageSettings .section.funbox .button`).removeClass("active");
$(
`.pageSettings .section.funbox .button[funbox='${Funbox.active}']`
`.pageSettings .section.funbox .button[funbox='${Funbox.funboxSaved}']`
).addClass("active");
}
@ -616,7 +624,7 @@ $(".pageSettings .section.discordIntegration #unlinkDiscordButton").click(
$(document).on("click", ".pageSettings .section.funbox .button", (e) => {
let funbox = $(e.currentTarget).attr("funbox");
let type = $(e.currentTarget).attr("type");
Funbox.activate(funbox, type);
Funbox.setFunbox(funbox, type);
setActiveFunboxButton();
});
@ -727,3 +735,34 @@ $(".pageSettings .sectionGroupTitle").click((e) => {
);
}
});
$(".pageSettings #resetPersonalBestsButton").on("click", (e) => {
SimplePopups.list.resetPersonalBests.show();
});
$(".pageSettings #updateAccountEmail").on("click", (e) => {
SimplePopups.list.updateEmail.show();
});
$(".pageSettings .section.customBackgroundSize .inputAndButton .save").on(
"click",
(e) => {
UpdateConfig.setCustomBackground(
$(
".pageSettings .section.customBackgroundSize .inputAndButton input"
).val()
);
}
);
$(".pageSettings .section.customBackgroundSize .inputAndButton input").keypress(
(e) => {
if (e.keyCode == 13) {
UpdateConfig.setCustomBackground(
$(
".pageSettings .section.customBackgroundSize .inputAndButton input"
).val()
);
}
}
);

View file

@ -5,6 +5,7 @@ import * as Notifications from "./notifications";
import * as CommandlineLists from "./commandline-lists";
import * as ThemeColors from "./theme-colors";
import * as ChartController from "./chart-controller";
import * as UI from "./ui";
export function updateActiveButton() {
$(`.pageSettings .section.themes .theme`).removeClass("active");
@ -99,9 +100,28 @@ function toggleFavourite(themename) {
}
export function updateActiveTab() {
Config.customTheme === true
? $(".pageSettings .section.themes .tabs .button[tab='custom']").click()
: $(".pageSettings .section.themes .tabs .button[tab='preset']").click();
$(".pageSettings .section.themes .tabs .button").removeClass("active");
if (!Config.customTheme) {
$(".pageSettings .section.themes .tabs .button[tab='preset']").addClass(
"active"
);
UI.swapElements(
$('.pageSettings .section.themes .tabContainer [tabContent="custom"]'),
$('.pageSettings .section.themes .tabContainer [tabContent="preset"]'),
250
);
} else {
$(".pageSettings .section.themes .tabs .button[tab='custom']").addClass(
"active"
);
UI.swapElements(
$('.pageSettings .section.themes .tabContainer [tabContent="preset"]'),
$('.pageSettings .section.themes .tabContainer [tabContent="custom"]'),
250
);
}
}
$("#shareCustomThemeButton").click((e) => {
@ -138,7 +158,7 @@ $(".pageSettings .section.themes .tabs .button").click((e) => {
setCustomInputs();
if ($target.attr("tab") == "preset") {
UpdateConfig.setCustomTheme(false);
ThemeController.set(Config.theme);
// ThemeController.set(Config.theme);
// applyCustomThemeColors();
// UI.swapElements(
// $('.pageSettings .section.themes .tabContainer [tabContent="custom"]'),
@ -147,7 +167,7 @@ $(".pageSettings .section.themes .tabs .button").click((e) => {
// );
} else {
UpdateConfig.setCustomTheme(true);
ThemeController.set("custom");
// ThemeController.set("custom");
// applyCustomThemeColors();
// UI.swapElements(
// $('.pageSettings .section.themes .tabContainer [tabContent="preset"]'),
@ -202,7 +222,7 @@ $(".pageSettings .saveCustomThemeButton").click((e) => {
$(".pageSettings #loadCustomColorsFromPreset").click((e) => {
// previewTheme(Config.theme);
ThemeController.preview(Config.theme);
$("#currentTheme").attr("href", `themes/${Config.theme}.css`);
ThemeController.colorVars.forEach((e) => {
document.documentElement.style.setProperty(e, "");

View file

@ -79,42 +79,42 @@ export function init() {
{
sounds: [
new Audio("../sound/click4/click4_1.wav"),
new Audio("../sound/click4/click4_1.wav"),
new Audio("../sound/click4/click4_11.wav"),
],
counter: 0,
},
{
sounds: [
new Audio("../sound/click4/click4_2.wav"),
new Audio("../sound/click4/click4_2.wav"),
new Audio("../sound/click4/click4_22.wav"),
],
counter: 0,
},
{
sounds: [
new Audio("../sound/click4/click4_3.wav"),
new Audio("../sound/click4/click4_3.wav"),
new Audio("../sound/click4/click4_33.wav"),
],
counter: 0,
},
{
sounds: [
new Audio("../sound/click4/click4_4.wav"),
new Audio("../sound/click4/click4_4.wav"),
new Audio("../sound/click4/click4_44.wav"),
],
counter: 0,
},
{
sounds: [
new Audio("../sound/click4/click4_5.wav"),
new Audio("../sound/click4/click4_5.wav"),
new Audio("../sound/click4/click4_55.wav"),
],
counter: 0,
},
{
sounds: [
new Audio("../sound/click4/click4_6.wav"),
new Audio("../sound/click4/click4_6.wav"),
new Audio("../sound/click4/click4_66.wav"),
],
counter: 0,
},

View file

@ -7,6 +7,8 @@ import Config, * as UpdateConfig from "./config";
import * as Settings from "./settings";
export let active = "none";
export let funboxSaved = "none";
export let modeSaved = null;
let memoryTimer = null;
let memoryInterval = null;
@ -71,12 +73,8 @@ export function toggleScript(...params) {
}
export async function activate(funbox, mode) {
if (TestLogic.active || TestUI.resultVisible) {
Notifications.add(
"You can only change the funbox before starting a test.",
0
);
return false;
if (funbox === undefined || funbox === null) {
funbox = funboxSaved;
}
if (Misc.getCurrentLanguage().ligatures) {
if (funbox == "choo_choo" || funbox == "earthquake") {
@ -96,8 +94,12 @@ export async function activate(funbox, mode) {
$("#wordsWrapper").removeClass("hidden");
// }
if (mode === null || mode === undefined) {
if (funbox === "none" && mode === undefined) {
mode = null;
} else if (
(funbox !== "none" && mode === undefined) ||
(funbox !== "none" && mode === null)
) {
let list = await Misc.getFunboxList();
mode = list.filter((f) => f.name === funbox)[0].type;
}
@ -162,3 +164,16 @@ export async function activate(funbox, mode) {
TestUI.updateModesNotice();
return true;
}
export function setFunbox(funbox, mode) {
if (TestLogic.active || TestUI.resultVisible) {
Notifications.add(
"You can only change the funbox before starting a test.",
0
);
return false;
}
funboxSaved = funbox;
modeSaved = mode;
active = funbox;
return true;
}

View file

@ -246,6 +246,6 @@ export function refreshKeys(layout) {
}
$(document).on("click", ".keymap .r5 #KeySpace", (e) => {
CommandlineLists.setCurrent(CommandlineLists.commandsKeymapLayouts);
CommandlineLists.setCurrent([CommandlineLists.commandsKeymapLayouts]);
Commandline.show();
});

View file

@ -10,7 +10,7 @@ export function show(data, mode2) {
let string = "";
if (data.needsToVerifyEmail === true) {
string = `please verify your email<br>to access leaderboards - <a onClick="sendVerificationEmail()">resend email</a>`;
} else if (data.lbBanned) {
} else if (data.banned || data.lbBanned) {
string = "banned";
} else if (data.name === false) {
string = "update your name to access leaderboards";

View file

@ -22,7 +22,7 @@ import * as QuoteSearchPopup from "./quote-search-popup";
import * as PbCrown from "./pb-crown";
import * as TestTimer from "./test-timer";
import * as OutOfFocus from "./out-of-focus";
import * as AccountButton from "./account-icon";
import * as AccountButton from "./account-button";
import * as DB from "./db";
import * as ThemeColors from "./theme-colors";
import * as CloudFunctions from "./cloud-functions";
@ -576,6 +576,9 @@ export async function init() {
// } else {
TestUI.showWords();
// }
if ($(".pageTest").hasClass("active")) {
Funbox.activate();
}
}
export function restart(withSameWordset = false, nosave = false, event) {
@ -697,6 +700,7 @@ export function restart(withSameWordset = false, nosave = false, event) {
input.reset();
PaceCaret.init();
TestUI.showWords();
Funbox.activate();
}
if (Config.mode === "quote") {
setRepeated(false);
@ -924,6 +928,7 @@ export function finish(difficultyFailed = false) {
LiveAcc.hide();
TimerProgress.hide();
Keymap.hide();
Funbox.activate("none", null);
let stats = TestStats.calculateStats();
if (stats === undefined) {
stats = {
@ -1653,8 +1658,8 @@ export function finish(difficultyFailed = false) {
if (Config.blindMode) {
testType += "<br>blind";
}
if (Funbox.active !== "none") {
testType += "<br>" + Funbox.active.replace(/_/g, " ");
if (Funbox.funboxSaved !== "none") {
testType += "<br>" + Funbox.funboxSaved.replace(/_/g, " ");
}
if (Config.difficulty == "expert") {
testType += "<br>expert";
@ -1708,6 +1713,33 @@ export function finish(difficultyFailed = false) {
$("#result .stats .source").addClass("hidden");
}
if (Funbox.funboxSaved !== "none") {
ChartController.result.options.annotation.annotations.push({
enabled: false,
type: "line",
mode: "horizontal",
scaleID: "wpm",
value: 0,
borderColor: "transparent",
borderWidth: 1,
borderDash: [2, 2],
label: {
backgroundColor: "transparent",
fontFamily: Config.fontFamily.replace(/_/g, " "),
fontSize: 11,
fontStyle: "normal",
fontColor: ThemeColors.sub,
xPadding: 6,
yPadding: 6,
cornerRadius: 3,
position: "left",
enabled: true,
content: `${Funbox.funboxSaved}`,
yAdjust: -11,
},
});
}
ChartController.result.options.scales.yAxes[0].ticks.max = maxChartVal;
ChartController.result.options.scales.yAxes[1].ticks.max = maxChartVal;

View file

@ -255,6 +255,14 @@ export function screenshot() {
if (firebase.auth().currentUser == null)
$(".pageTest .loginTip").removeClass("hidden");
}
setTimeout(() => {
$("#notificationCenter").removeClass("hidden");
$("#commandLineMobileButton").removeClass("hidden");
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
if (firebase.auth().currentUser == null)
$(".pageTest .loginTip").removeClass("hidden");
}, 3000);
}
export function updateWordElement(showError) {

View file

@ -149,3 +149,27 @@ export function randomiseTheme() {
export function clearRandom() {
randomTheme = null;
}
export function applyCustomBackground() {
$(".customBackground").css({
backgroundImage: `url(${Config.customBackground})`,
backgroundAttachment: "fixed",
});
if (Config.customBackground === "") {
$("#words").removeClass("noErrorBorder");
} else {
$("#words").addClass("noErrorBorder");
}
}
export function applyCustomBackgroundSize() {
if (Config.customBackgroundSize == "max") {
$(".customBackground").css({
backgroundSize: "100% 100%",
});
} else if (Config.customBackgroundSize != "") {
$(".customBackground").css({
backgroundSize: Config.customBackgroundSize,
});
}
}

View file

@ -6,6 +6,15 @@ import * as TestLogic from "./test-logic";
import * as CustomText from "./custom-text";
import * as CommandlineLists from "./commandline-lists";
import * as Commandline from "./commandline";
import * as TestUI from "./test-ui";
import * as TestConfig from "./test-config";
import * as SignOutButton from "./sign-out-button";
import * as TestStats from "./test-stats";
import * as ManualRestart from "./manual-restart-tracker";
import * as Settings from "./settings";
import * as Account from "./account";
import * as Leaderboards from "./leaderboards";
import * as Funbox from "./funbox";
export let pageTransition = false;
@ -99,6 +108,100 @@ export function swapElements(
}
}
export function changePage(page) {
if (pageTransition) {
return;
}
let activePage = $(".page.active");
$(".page").removeClass("active");
$("#wordsInput").focusout();
if (page == "test" || page == "") {
setPageTransition(true);
swapElements(
activePage,
$(".page.pageTest"),
250,
() => {
setPageTransition(false);
TestUI.focusWords();
$(".page.pageTest").addClass("active");
history.pushState("/", null, "/");
},
() => {
TestConfig.show();
}
);
SignOutButton.hide();
// restartCount = 0;
// incompleteTestSeconds = 0;
TestStats.resetIncomplete();
ManualRestart.set();
TestLogic.restart();
Funbox.activate(Funbox.funboxSaved, Funbox.modeSaved);
} else if (page == "about") {
setPageTransition(true);
TestLogic.restart();
swapElements(activePage, $(".page.pageAbout"), 250, () => {
setPageTransition(false);
history.pushState("about", null, "about");
$(".page.pageAbout").addClass("active");
});
Funbox.activate("none", null);
TestConfig.hide();
SignOutButton.hide();
} else if (page == "settings") {
setPageTransition(true);
TestLogic.restart();
swapElements(activePage, $(".page.pageSettings"), 250, () => {
setPageTransition(false);
history.pushState("settings", null, "settings");
$(".page.pageSettings").addClass("active");
});
Funbox.activate("none", null);
Settings.update();
TestConfig.hide();
SignOutButton.hide();
} else if (page == "account") {
if (!firebase.auth().currentUser) {
changePage("login");
} else {
setPageTransition(true);
TestLogic.restart();
swapElements(
activePage,
$(".page.pageAccount"),
250,
() => {
setPageTransition(false);
history.pushState("account", null, "account");
$(".page.pageAccount").addClass("active");
},
() => {
SignOutButton.show();
}
);
Funbox.activate("none", null);
Account.update();
TestConfig.hide();
}
} else if (page == "login") {
if (firebase.auth().currentUser != null) {
changePage("account");
} else {
setPageTransition(true);
TestLogic.restart();
swapElements(activePage, $(".page.pageLogin"), 250, () => {
setPageTransition(false);
history.pushState("login", null, "login");
$(".page.pageLogin").addClass("active");
});
Funbox.activate("none", null);
TestConfig.hide();
SignOutButton.hide();
}
}
}
if (firebase.app().options.projectId === "monkey-type-dev-67af4") {
$("#top .logo .bottom").text("monkey-dev");
$("head title").text("Monkey Dev");
@ -152,7 +255,7 @@ $(document).on("click", "#bottom .leftright .right .current-theme", (e) => {
// if (Config.customTheme) {
// toggleCustomTheme();
// }
CommandlineLists.setCurrent(CommandlineLists.themeCommands);
CommandlineLists.setCurrent([CommandlineLists.themeCommands]);
Commandline.show();
}
});
@ -191,3 +294,17 @@ window.addEventListener("beforeunload", (event) => {
$(window).resize(() => {
Caret.updatePosition();
});
$(document).on("click", "#top .logo", (e) => {
changePage("test");
});
$(document).on("click", "#top #menu .icon-button", (e) => {
if ($(e.currentTarget).hasClass("leaderboards")) {
Leaderboards.show();
} else {
const href = $(e.currentTarget).attr("href");
ManualRestart.set();
changePage(href.replace("/", ""));
}
});

View file

@ -44,6 +44,22 @@ input {
font-family: var(--font);
}
input[type="range"] {
-webkit-appearance: none;
padding: 0;
width: 100%;
height: 1rem;
border-radius: var(--roundness);
&::-webkit-slider-thumb {
-webkit-appearance: none;
padding: 0;
width: 2rem;
height: 1rem;
border-radius: var(--roundness);
background-color: var(--main-color);
}
}
input[type="color"] {
-webkit-appearance: none;
padding: 0;
@ -107,10 +123,22 @@ body {
margin: 0;
padding: 0;
min-height: 100vh;
background: var(--bg-color);
font-family: var(--font);
color: var(--main-color);
overflow-x: hidden;
background: var(--bg-color);
}
.customBackground {
content: "";
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
background-position: center center;
background-repeat: no-repeat;
z-index: -999;
}
html {
@ -1496,12 +1524,12 @@ a:hover {
@keyframes caretFlashHard {
0%,
50% {
opacity: 0;
opacity: 1;
}
51%,
100% {
opacity: 1;
opacity: 0;
}
}
@ -2465,6 +2493,11 @@ key {
1px 1px 0px var(--bg-color), -1px 1px 0px var(--bg-color);
}
#words.noErrorBorder {
.word.error {
text-shadow: none;
}
}
// .word letter {
// transition: .1s;
// height: 1rem;
@ -2714,6 +2747,56 @@ key {
}
}
&.customBackgroundSize {
.inputAndButton {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 0.5rem;
margin-bottom: 0.5rem;
input {
grid-column: 1/3;
}
.save {
grid-column: 3/4;
height: auto;
.fas {
margin-right: 0rem;
vertical-align: sub;
}
}
}
}
&.customBackgroundFilter {
.groups {
grid-area: buttons;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-top: 2rem;
.group {
display: grid;
grid-template-columns: 1fr auto 2fr;
gap: 1rem;
.title,
.value {
color: var(--text-color);
}
}
}
.saveContainer {
grid-column: -1/-3;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
.fas {
margin-right: 0rem;
}
}
&.customTheme {
grid-template-columns: 1fr 1fr 1fr 1fr;
justify-items: stretch;
@ -2960,7 +3043,8 @@ key {
&.keymapLayout,
&.fontFamily,
&.funbox,
&.keymapStyle {
&.keymapStyle,
&.customBackgroundFilter {
grid-template-columns: 2fr 1fr;
grid-template-areas:
"title tabs"
@ -3515,6 +3599,15 @@ key {
}
}
.pageSettings .section.customBackgroundFilter {
.groups {
grid-template-columns: 1fr;
}
.saveContainer {
grid-column: -1/-2;
}
}
#commandLine,
#commandLineInput {
width: 500px !important;

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 567 B

View file

@ -14,7 +14,32 @@
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme" />
<link rel="stylesheet" href="" id="funBoxTheme" />
<link id="favicon" rel="shortcut icon" href="images/fav.png" />
<link rel="shortcut icon" href="images/fav.png" />
<link rel="shortcut icon" href="images/favicon/fav.png" />
<link
href="images/favicon/apple-touch-icon-180x180.png"
rel="apple-touch-icon"
sizes="180x180"
/>
<link
href="images/favicon/apple-touch-icon-152x152.png"
rel="apple-touch-icon"
sizes="152x152"
/>
<link
href="images/favicon/apple-touch-icon-120x120.png"
rel="apple-touch-icon"
sizes="120x120"
/>
<link
href="images/favicon/apple-touch-icon-76x76.png"
rel="apple-touch-icon"
sizes="76x76"
/>
<link
rel="apple-touch-icon"
href="images/favicon/apple-touch-icon-60x60.png"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
@ -54,7 +79,7 @@
</script>
<script async src="https://s.nitropay.com/ads-693.js"></script>
</head>
<div class="customBackground"></div>
<body>
<div id="backgroundLoader" style="display: none"></div>
<div id="notificationCenter">
@ -875,7 +900,7 @@
</div>
</div>
<div id="timerWrapper">
<div id="timer"></div>
<div id="timer" class="timerMain"></div>
</div>
<div style="display: flex; justify-content: space-around">
<div id="nitropay_ad_left" class="hidden"></div>
@ -1067,10 +1092,10 @@
<div id="caret" class="default size15"></div>
<div id="paceCaret" class="default size15 hidden"></div>
<input id="wordsInput" class="" tabindex="0" autocomplete="off" />
<div id="timerNumber">
<div id="timerNumber" class="timerMain">
<div>60</div>
</div>
<div id="miniTimerAndLiveWpm">
<div id="miniTimerAndLiveWpm" class="timerMain size15">
<div class="time hidden">1:00</div>
<div class="wpm">60</div>
<div class="acc">100%</div>
@ -1256,7 +1281,7 @@
</div>
</div>
</div>
<div id="largeLiveWpmAndAcc">
<div id="largeLiveWpmAndAcc" class="timerMain">
<div id="liveWpm" class="hidden">123</div>
<div id="liveAcc" class="hidden">100%%</div>
</div>
@ -2920,6 +2945,92 @@
</div>
</div>
</div>
<div class="section customBackgroundSize">
<h1>custom background</h1>
<div class="text">
Set an image url to be a custom background image. Cover fits
the image to cover the screen. Contain fits the image to be
fully visible. Max fits the image corner to corner.
</div>
<div>
<div class="inputAndButton">
<input
type="text"
placeholder="image url"
class="input"
tabindex="0"
onClick="this.select();"
/>
<div
class="button save"
tabindex="0"
onclick="this.blur();"
>
<i class="fas fa-save fa-fw"></i>
</div>
</div>
<div class="buttons">
<div
class="button"
customBackgroundSize="cover"
tabindex="0"
onclick="this.blur();"
>
cover
</div>
<div
class="button"
customBackgroundSize="contain"
tabindex="0"
onclick="this.blur();"
>
contain
</div>
<div
class="button"
customBackGroundSize="max"
tabindex="0"
onclick="this.blur();"
>
max
</div>
</div>
</div>
</div>
<div class="section customBackgroundFilter">
<h1>custom background filter</h1>
<div class="text">
Apply various effects to the custom background.
</div>
<div class="groups">
<div class="group blur">
<div class="title">blur</div>
<div class="value"></div>
<input type="range" min="0" max="5" value="0" step="0.1" />
</div>
<div class="group brightness">
<div class="title">brightness</div>
<div class="value"></div>
<input type="range" min="0" max="2" value="1" step="0.1" />
</div>
<div class="group saturate">
<div class="title">saturate</div>
<div class="value"></div>
<input type="range" min="0" max="2" value="1" step="0.1" />
</div>
<div class="group opacity">
<div class="title">opacity</div>
<div class="value"></div>
<input type="range" min="0" max="1" value="1" step="0.1" />
</div>
<div class="saveContainer">
<div class="save button" style="grid-column: 3">
<!-- <i class="fas fa-save fa-fw"></i> -->
save
</div>
</div>
</div>
</div>
<div class="section themes">
<h1>theme</h1>
<div class="tabs">
@ -3225,7 +3336,7 @@
class="button off danger"
id="resetPersonalBestsButton"
tabindex="0"
onclick="this.blur();simplePopups.resetPersonalBests.show();"
onclick="this.blur();"
>
reset personal bests
</div>
@ -3241,7 +3352,7 @@
class="button off danger"
id="updateAccountEmail"
tabindex="0"
onclick="this.blur();simplePopups.updateEmail.show();"
onclick="this.blur();"
>
update email
</div>

View file

@ -167,8 +167,6 @@
"málo",
"myslit",
"stejně",
"-li",
"Český",
"moc",
"problém",
"milión",

File diff suppressed because it is too large Load diff

View file

@ -26,9 +26,7 @@
"tak",
"po",
"už",
"V",
"co",
"A",
"jsou",
"nebo",
"které",
@ -54,22 +52,18 @@
"ještě",
"bude",
"ze",
"Na",
"také",
"která",
"ji",
"pak",
"být",
"ani",
"To",
"před",
"při",
"není",
"však",
"jejich",
"Ale",
"toho",
"Je",
"kde",
"své",
"tam",
@ -78,7 +72,6 @@
"tom",
"tím",
"tu",
"Když",
"či",
"protože",
"něco",
@ -115,11 +108,9 @@
"teď",
"mají",
"něj",
"Co",
"nám",
"proto",
"přes",
"Jak",
"nich",
"již",
"jim",
@ -135,15 +126,12 @@
"vám",
"sebe",
"mít",
"Z",
"dobře",
"ti",
"všechny",
"nikdy",
"I",
"vás",
"vůbec",
"Po",
"proti",
"jeden",
"svou",
@ -156,13 +144,10 @@
"moc",
"například",
"stále",
"Pokud",
"pokud",
"tady",
"Tak",
"lidí",
"místo",
"Já",
"S",
"svého",
"víc",
"zase",
@ -175,14 +160,11 @@
"případě",
"dnes",
"den",
"O",
"době",
"Ve",
"dvě",
"práce",
"mohl",
"lze",
"pokud",
"korun",
"mohou",
"často",
@ -198,13 +180,11 @@
"vlastní",
"život",
"ta",
"Za",
"takže",
"člověk",
"jde",
"dál",
"svých",
"Pro",
"sobě",
"ním",
"měli",
@ -212,7 +192,6 @@
"on",
"taky",
"svůj",
"li",
"děti",
"mám",
"znovu",
@ -220,9 +199,7 @@
"poslední",
"především",
"každý",
"Už",
"příliš",
"Podle",
"jednou",
"možná",
"ovšem",
@ -232,12 +209,9 @@
"úplně",
"nové",
"sebou",
"Pak",
"jenom",
"K",
"téměř",
"Kč",
"Do",
"jež",
"něm",
"čas",
@ -258,7 +232,6 @@
"zcela",
"nejen",
"těch",
"Ne",
"života",
"později",
"tento",
@ -273,9 +246,7 @@
"tohoto",
"kdyby",
"opravdu",
"U",
"větší",
"Při",
"nikdo",
"věci",
"století",
@ -283,12 +254,10 @@
"světa",
"během",
"tisíc",
"Byl",
"celý",
"dlouho",
"abych",
"těchto",
"Jeho",
"dalších",
"tě",
"pořád",
@ -296,7 +265,6 @@
"jej",
"velké",
"někdy",
"Jako",
"patří",
"díky",
"nyní",
@ -308,7 +276,6 @@
"rychle",
"můžete",
"opět",
"Ten",
"města",
"ni",
"jinak",
@ -333,11 +300,8 @@
"samozřejmě",
"jednoho",
"vody",
"Bylo",
"sem",
"Proč",
"doby",
"Od",
"začal",
"bychom",
"straně",
@ -348,7 +312,6 @@
"ně",
"svém",
"čtyři",
"Ty",
"chtěl",
"zatím",
"vše",
@ -366,13 +329,12 @@
"pět",
"nějaké",
"ať",
"Ano",
"ano",
"ona",
"Teď",
"strany",
"rád",
"domu",
"No",
"no",
"sama",
"doma",
"mnohem",
@ -381,7 +343,6 @@
"země",
"vidět",
"např.",
"Jen",
"máme",
"možnost",
"méně",
@ -408,7 +369,6 @@
"my",
"ruku",
"hlavu",
"Byla",
"skoro",
"hlavní",
"jehož",
@ -422,7 +382,6 @@
"prý",
"večer",
"roky",
"Možná",
"musel",
"naopak",
"rámci",
@ -441,8 +400,7 @@
"školy",
"dveře",
"určitě",
"České",
"Není",
"české",
"lidi",
"mnou",
"znamená",
@ -450,7 +408,6 @@
"mimo",
"lety",
"paní",
"Takže",
"půl",
"ostatní",
"svět",
@ -468,7 +425,7 @@
"firmy",
"Praze",
"jedno",
"Jenže",
"jenže",
"zatímco",
"nemůže",
"největší",
@ -476,13 +433,10 @@
"alespoň",
"nebyla",
"místa",
"Jsem",
"naší",
"Proto",
"nový",
"množství",
"žádný",
"Ani",
"dětí",
"situace",
"dobré",
@ -491,14 +445,11 @@
"většinou",
"zařízení",
"mělo",
"Ještě",
"poprvé",
"přišel",
"budu",
"malé",
"tato",
"Ta",
"české",
"jít",
"jich",
"udělat",
@ -540,9 +491,7 @@
"situaci",
"mé",
"mnoha",
"Jsou",
"řízení",
"První",
"druhou",
"Jan",
"jenž",
@ -550,9 +499,7 @@
"jiný",
"ČR",
"spíš",
"Kdo",
"muže",
"Protože",
"budeme",
"máte",
"zeptal",
@ -576,7 +523,6 @@
"problémy",
"viděl",
"přesto",
"ano",
"oba",
"dům",
"stavu",
@ -591,20 +537,16 @@
"kterých",
"hlas",
"počet",
"Mám",
"došlo",
"začátku",
"pomalu",
"Před",
"m",
"Tento",
"prostor",
"vlasy",
"obvykle",
"prvním",
"velice",
"srdce",
"Další",
"skupiny",
"velkou",
"tělo",
@ -619,14 +561,11 @@
"postupně",
"dříve",
"docela",
"Kromě",
"dny",
"ulici",
"trhu",
"konce",
"Až",
"podařilo",
"Že",
"slovo",
"jasné",
"každé",
@ -647,27 +586,22 @@
"dolů",
"šest",
"jejím",
"Její",
"naprosto",
"metrů",
"domácí",
"věcí",
"abychom",
"základě",
"Měl",
"Právě",
"občas",
"sociální",
"nutné",
"území",
"ven",
"Nebo",
"nohy",
"zájem",
"dát",
"hrát",
"věku",
"Má",
"různé",
"tvoří",
"pravdu",
@ -681,9 +615,6 @@
"takhle",
"způsob",
"myslím",
"Myslím",
"Dnes",
"Mezi",
"cesty",
"menší",
"ví",
@ -717,9 +648,7 @@
"projektu",
"umění",
"muset",
"Tato",
"aspoň",
"Díky",
"přijde",
"náš",
"čeká",
@ -768,7 +697,6 @@
"městě",
"dřív",
"štěstí",
"Jejich",
"vzduchu",
"dělá",
"vede",
@ -779,15 +707,12 @@
"moci",
"věděl",
"aniž",
"Každý",
"musíme",
"Navíc",
"zvláštní",
"mého",
"snadno",
"cestě",
"dvacet",
"Také",
"policie",
"dlouhé",
"šlo",
@ -806,30 +731,22 @@
"přišla",
"podobě",
"vztah",
"Tohle",
"střední",
"informací",
"Kdyby",
"starší",
"dávno",
"auta",
"Jde",
"Všichni",
"Jestli",
"strach",
"začíná",
"vrátil",
"Nic",
"průběhu",
"zákona",
"všeho",
"jejího",
"Zatímco",
"svému",
"ředitel",
"možnosti",
"konec",
"Stejně",
"začne",
"udělal",
"pěti",
@ -864,7 +781,6 @@
"Evropě",
"program",
"minulosti",
"Nikdy",
"činnosti",
"uvnitř",
"taková",
@ -881,7 +797,6 @@
"těžké",
"státu",
"výsledky",
"Asi",
"staré",
"republiky",
"kdysi",
@ -892,7 +807,6 @@
"očí",
"finanční",
"představuje",
"Nakonec",
"dodal",
"utkání",
"myslí",
@ -904,10 +818,8 @@
"Jana",
"každého",
"představit",
"My",
"radost",
"buď",
"Tady",
"chtějí",
"potřeba",
"jaký",
@ -915,9 +827,7 @@
"měsíců",
"druhého",
"měsíce",
"Přesto",
"uprostřed",
"Samozřejmě",
"podmínky",
"žen",
"prostřednictvím",
@ -946,28 +856,21 @@
"jedná",
"stala",
"takovou",
"Potom",
"děje",
"náměstí",
"špatně",
"auto",
"prohlásil",
"Tím",
"jasně",
"On",
"zdraví",
"čem",
"anebo",
"Například",
"Jeden",
"pokoje",
"dostala",
"podstatě",
"Tam",
"stran",
"nemocnice",
"bys",
"Ze",
"miliardy",
"Pavel",
"otázku",
@ -995,9 +898,7 @@
"sedm",
"rozhodl",
"nejde",
"Během",
"vliv",
"Jo",
"světla",
"č.",
"přičemž",

File diff suppressed because it is too large Load diff

View file

@ -60,7 +60,7 @@
<div class="logo">
<div class="top">monkey see</div>
<div class="bottom">
monkeytype
<a href="/ " style="text-decoration:none; color:inherit;">monkeytype</a>
<span style="color: var(--text-color)">Privacy Policy</span>
</div>
</div>

View file

@ -1,41 +1,29 @@
{
"language": "english",
"groups": [
[
0,
100
],
[
101,
300
],
[
301,
600
],
[
601,
9999
]
[0, 100],
[101, 300],
[301, 600],
[601, 9999]
],
"quotes": [
{
"text": "You have the power to heal your life, and you need to know that.",
"source": "Meditations to Heal Your Life",
"id": 1,
"length": 64
"length": 64,
"id": 1
},
{
"text": "They don't know that we know they know we know.",
"source": "Friends",
"id": 2,
"length": 47
"length": 47,
"id": 2
},
{
"text": "Don't it make you sad to know that life is more than who you are?",
"source": "Name",
"id": 3,
"length": 65
"length": 65,
"id": 3
},
{
"text": "Leave something for someone but don't leave someone for something.",
@ -29780,7 +29768,7 @@
"length": 309
},
{
"text": "All depression has its roots in self-pity, and all self-pity is rooted in people taking themselves too seriously. At the time Switters had disputed her assertion. Even at seventeen, he was aware that depression could have chemical causes. The key word here is roots, Maestra had countered. The roots of depression. For most people, self-awareness and self-pity blossom simultaneously in early adolescence. It's about that time that we start viewing the world as something other than a whoop-de-doo playground, we start to experience personally how threatening it can be, how cruel and unjust. At the very moment when we become, for the first time, both introspective and socially conscientious, we receive the bad news that the world, by and large, doesn't give a rat's ass. Even an old tomato like me can recall how painful, scary, and disillusioning that realization was. So, there's a tendency, then, to slip into rage and self-pity, which if indulged, can fester into bouts of depression. Yeah but Maestra-. Don't interrupt. Now, unless someone stronger and wiser - a friend, a parent, a novelist, filmmaker, teacher, or musician - can josh us out of it, can elevate us and show us how petty and pompous and monumentally useless it is to take ourselves so seriously, then depression can become a habit, which, in tern, can produce a neurological imprint. Are you with me? Gradually, our brain chemistry becomes conditioned to react to negative stimuli in a particular, predictable way. One thing'll go wrong and it'll automatically switch on its blender and mix us that black cocktail, the ol' doomsday daiquiri, and before we know it, we're soused to the gills from the inside out. Once depression has become electrochemically integrated, it can be extremely difficult to philosophically or psychologically override it; by then it's playing by physical rules, a whole different ball game. That's why, Switters my dearest, every time you've shown signs of feeling sorry for yourself, I've played my blues records really loud or read to you from The Horse's Mouth. And that's why when you've exhibited the slightest tendency toward self-importance, I've reminded you that you and me - you and I: excuse me - may be every bit as important as the President or the pope or the biggest prime-time icon in Hollywood, but none of us is much more than a pimple on the ass-end of creation, so let's not get carried away with ourselves. Preventive medicine, boy. It's preventive medicine. But what about self-esteem? Heh! Self-esteem is for sissies. Accept that you're a pimple and try to keep a lively sense of humor about it. That way lies grace-and maybe even glory.",
"text": "All depression has its roots in self-pity, and all self-pity is rooted in people taking themselves too seriously. At the time Switters had disputed her assertion. Even at seventeen, he was aware that depression could have chemical causes. The key word here is roots, Maestra had countered. The roots of depression. For most people, self-awareness and self-pity blossom simultaneously in early adolescence. It's about that time that we start viewing the world as something other than a whoop-de-doo playground, we start to experience personally how threatening it can be, how cruel and unjust. At the very moment when we become, for the first time, both introspective and socially conscientious, we receive the bad news that the world, by and large, doesn't give a rat's ass. Even an old tomato like me can recall how painful, scary, and disillusioning that realization was. So, there's a tendency, then, to slip into rage and self-pity, which if indulged, can fester into bouts of depression. Yeah but Maestra-. Don't interrupt. Now, unless someone stronger and wiser - a friend, a parent, a novelist, filmmaker, teacher, or musician - can josh us out of it, can elevate us and show us how petty and pompous and monumentally useless it is to take ourselves so seriously, then depression can become a habit, which, in turn, can produce a neurological imprint. Are you with me? Gradually, our brain chemistry becomes conditioned to react to negative stimuli in a particular, predictable way. One thing'll go wrong and it'll automatically switch on its blender and mix us that black cocktail, the ol' doomsday daiquiri, and before we know it, we're soused to the gills from the inside out. Once depression has become electrochemically integrated, it can be extremely difficult to philosophically or psychologically override it; by then it's playing by physical rules, a whole different ball game. That's why, Switters my dearest, every time you've shown signs of feeling sorry for yourself, I've played my blues records really loud or read to you from The Horse's Mouth. And that's why when you've exhibited the slightest tendency toward self-importance, I've reminded you that you and me - you and I: excuse me - may be every bit as important as the President or the pope or the biggest prime-time icon in Hollywood, but none of us is much more than a pimple on the ass-end of creation, so let's not get carried away with ourselves. Preventive medicine, boy. It's preventive medicine. But what about self-esteem? Heh! Self-esteem is for sissies. Accept that you're a pimple and try to keep a lively sense of humor about it. That way lies grace-and maybe even glory.",
"source": "Fierce Invalids Home from Hot Climates",
"id": 5013,
"length": 2663
@ -30112,32 +30100,32 @@
{
"text": "NO ADMITTANCE. NOT EVEN TO AUTHORIZED PERSONNEL. YOU ARE WASTING YOUR TIME HERE. GO AWAY.",
"source": "Mostly Harmless",
"id": 5068,
"length": 89
"length": 89,
"id": 5068
},
{
"text": "He had a nasty feeling that that might be an idiotic thing to do, but he did it anyway, and sure enough it had turned out to be an idiotic thing to do. You live and learn. At any rate, you live.",
"source": "Mostly Harmless",
"id": 5069,
"length": 194
"length": 194,
"id": 5069
},
{
"text": "Fall, though, is the worst. Few things are worse than fall in New York, Some of the things that live in the lower intestines of rats would disagree, but most of the things that live in the lower intestines of rats are highly disagreeable anyways, so their opinion can and should be discounted.",
"source": "Mostly Harmless",
"id": 5070,
"length": 293
"length": 293,
"id": 5070
},
{
"text": "Every single decision we make, every breath we draw, opens some doors and closes many others. Most of them we don't nonce, Some we do.",
"source": "Mostly Harmless",
"id": 5071,
"length": 134
"length": 134,
"id": 5071
},
{
"text": "At every level, vital instructions were missing, and the instructions about what to do in the event of discovering that vital instructions were missing, were also missing.",
"source": "Mostly Harmless",
"id": 5072,
"length": 171
"length": 171,
"id": 5072
},
{
"text": "If you set your goals ridiculously high and it's a failure, you will fail above everyone else's success.",
@ -32384,16 +32372,242 @@
"id": 5446
},
{
"text": "My intent, here, is to tell our story in a dramatically truthful way. While the facts may be less than accurate, please understand that the emotion is true. The intent is true. And, dramatically speaking, intention is everything.",
"source": "Enzo, The Art of Racing in the Rain (Garth Stein)",
"length": 229,
"text": "Do not pity the dead, Harry. Pity the living, and, above all those who live without love.",
"source": "Albus Dumbledore",
"length": 89,
"id": 5447
},
{
"text": "A winner, a champion, will accept his fate. He will continue with his wheels in the dirt. He will do his best to maintain his line and gradually get himself back on the track when it is safe to do so. Yes, he loses a few places in the race. Yes, he is at a disadvantage. But he is still racing. He is still alive.",
"source": "The Art of Racing in the Rain (Garth Stein)",
"length": 313,
"text": "It does not do well to dwell on dreams and forget to live.",
"source": "Albus Dumbledore",
"length": 58,
"id": 5448
},
{
"text": "Have you ever had a dream, Neo, that you seemed so sure it was real? But if were unable to wake up from that dream, how would you tell the difference between the dream world & the real world?",
"source": "The Matrix",
"length": 191,
"id": 5449
},
{
"text": "If real is what you can feel, smell, taste and see, then 'real' is simply electrical signals interpreted by your brain.",
"source": "The Matrix",
"length": 119,
"id": 5450
},
{
"text": "If you aint scared… you aint human.",
"source": "Alby, The Maze Runner",
"length": 37,
"id": 5451
},
{
"text": "It's kind of hard to ask a dead guy what he did wrong.",
"source": "Minho, The Maze Runner",
"length": 54,
"id": 5452
},
{
"text": "I promised I'd save him, take him home! I promised him!",
"source": "Thomas, The Maze Runner",
"length": 55,
"id": 5453
},
{
"text": "Good that.",
"source": "Newt, The Maze Runner",
"length": 10,
"id": 5454
},
{
"text": "Maybe you should just press the button",
"source": "The Maze Runner",
"length": "38",
"id": 5455
},
{
"text": "I just...feel like I need to save everyone. To redeem myself.",
"source": "Thomas, The Maze Runner",
"length": 61,
"id": 5456
},
{
"text": "People who live in glass houses should shut the f*** up.",
"source": "Anorak's Almanac, Ready Player One",
"length": 56,
"id": 5457
},
{
"text": "Going outside is highly overrated.",
"source": "Anorak's Almanac, Ready Player One",
"length": 34,
"id": 5458
},
{
"text": "No one in the world gets what they want and that is beautiful",
"source": "Ready Player One",
"length": 61,
"id": 5459
},
{
"text": "You'd be amazed how much research you can get done when you have no life whatsoever",
"source": "Wade Watts, Ready Player One",
"length": 83,
"id": 5460
},
{
"text": "Being human totally sucks most of the time. Videogames are the only thing that make life bearable.",
"source": "Anorak's Almanac, Ready Player One",
"length": 98,
"id": 5461
},
{
"text": "You're probably wondering what's going to happen to you. That's easy. The same thing is going to happen to you that has happened to every other human being who has ever lived. You're going to die. We all die. That's just how it is.",
"source": "Ready Player One",
"length": 231,
"id": 5462
},
{
"text": "For a bunch of hair-less apes, we've actually managed to invent some pretty incredible things.",
"source": "Ready Player One",
"length": 94,
"id": 5463
},
{
"text": "I was watching a collection of vintage '80s cereal commercials when I paused to wonder why cereal manufacturers no longer included toy prizes inside every box. It was a tradegy, in my opinion. Another sign that civilization was going straight down the tubes.",
"source": "Wade Watts, Ready Player One",
"length": 258,
"id": 5464
},
{
"text": "My friend Kira always said that life is like an extremely difficult, horribly unbalanced videogame. When youre born, youre given a randomly generated character, with a randomly determined name, race, face, and social class. Your body is your avatar, and you spawn in a random geographic location, at a random moment in human history, surrounded by a random group of people, and then you have to try to survive for as long as you can. Sometimes the game might seem easy. Even fun. Other times it might be so difficult you want to give up and quit. But unfortunately, in this game you only get one life. When your body grows too hungry or thirsty or ill or injured or old, your health meter runs out and then its Game Over. Some people play the game for a hundred years without ever figuring out that its a game, or that there is a way to win it. To win the videogame of life you just have to try to make the experience of being forced to play it as pleasant as possible, for yourself, and for all of the other players you encounter in your travels. Kira says that if everyone played the game to win, itd be a lot more fun for everyone.",
"source": "Anorak's Almanac, Ready Player Two",
"length": 1139,
"id": 5465
},
{
"text": "Human beings were never meant to participate in a worldwide social network comprised of billions of people. We were designed by evolution to be hunter-gatherers, with the mental capacity to interact and socialize with the other members of our tribe—a tribe made up of a few hundred other people at most. Interacting with thousands or even millions of other people on a daily basis was way too much for our ape-descended melons to handle. That was why social media had been gradually driving the entire population of the world insane since it emerged back around the turn of the century.",
"source": "Ready Player Two",
"length": 586,
"id": 5466
},
{
"text": "Everybody wants to rule the world.",
"source": "Wade Watts, Ready Player Two",
"length": 34,
"id": 5467
},
{
"text": "How the f*** do you negotiate with a piece of software?",
"source": "Wade Watts, Ready Player Two",
"length": 55,
"id": 5468
},
{
"text": "The worlds population was fast approaching ten billion people, and Mother Earth was making it abundantly clear that she could no longer sustain all of us",
"source": "Wade Watts, Ready Player Two",
"length": 154,
"id": 5469
},
{
"text": "You get tough like me and you don't get hurt. You look out for yourself and nothin' can touch you...",
"source": "Dally, The Outsiders",
"length": 100,
"id": 5470
},
{
"text": "Things are rough all over.",
"source": "Cherry, The Outsiders"
},
{
"text": "I am a greaser. I am a JD and a hood. I blacken the name of our fair city. I beat up people. I rob gas stations. I am a manace to society. Man do I have fun!",
"source": "The Outsiders",
"length": 157,
"id": 5471
},
{
"text": "You still have a lot of time to make yourself be what you want. There's still lots of good in the world. Tell Dally. I don't think he knows.",
"source": "Johnny, The Outsiders",
"length": 140,
"id": 5472
},
{
"text": "Happy Hunger Games! And may the odds be in your favor.",
"source": "The Hunger Games",
"length": 54,
"id": 5473
},
{
"text": "Destroying things is much easier than making them.",
"source": "The Hunger Games",
"length": 50,
"id": 5474
},
{
"text": "You have only one life, make the most of it.",
"source": "Holes",
"length": 44,
"id": 5475
},
{
"text": "Nothing in life is easy, but that's no reason to give up. You'll be surprised what you can accomplish when you set your mind to it.",
"source": "Holes",
"length": 131,
"id": 5476
},
{
"text": "You may have done some bad things, but that doesn't mean you're a bad kid",
"source": "Holes",
"length": 73,
"id": 5477
},
{
"text": "Don't ask for guarantees. And don't look to be saved in any one thing, person, machine, or library. Do your own bit of saving, and if you drown, at least die knowing you where heading for shore.",
"source": "Fahrenheit 451",
"length": 192,
"id": 5478
},
{
"text": "I still love books. Nothing a computer can do can compare to a book. You can't really put a book on the Internet. Three companies have offered to put books by me on the Net, and I said, 'If you can make something that has a nice jacket, nice paper with that nice smell, then we'll talk.' All the computer can give you is a manuscript. People don't want to read manuscripts. They want to read books. Books smell good. They look good. You can press it to your bosom. You can carry it in your pocket.",
"source": "Fahrenheit 451",
"length": 497,
"id": 5479
},
{
"text": "It was a pleasure to burn.",
"source": "Fahrenheit 451",
"length": 26,
"id": 4580
},
{
"text": "I don't talk things, Sir. I talk the meaning of things.",
"source": "Fahrenheit 451",
"length": 55,
"id": 5481
},
{
"text": "Our civilization is flinging itself to pieces. Stand back from the centrifuge",
"source": "Fahrenheit 451",
"length": 77,
"id": 5482
},
{
"text": "Live as if you'd drop dead in ten seconds.",
"source": "Fahrenheit 451",
"length": 42,
"id": 5483
},
{
"text": "Have you ever watched the jet cars race on the boulevard?...I sometimes think drivers dont know what grass is, or flowers, because they never see them slowly...If you showed a driver a green blur, Oh yes! He'd say, thats grass! A pink blur! Thats a rose garden! White blurs are houses. Brown blurs are cows.",
"source": "Fahrenheit 451",
"length": 310,
"id": 5484
},
{
"text": "My father picked me up from school one day and we played hookey and went to the beach. It was too cold to go in the water so we sat on a blanket and ate pizza. When I got home my sneakers were full of sand and I dumped it on my bedroom floor. I didn't know the difference, I was six. My mother screamed at me for the mess but he wasn't mad. He said that billions of years ago the world 's shifting and ocean moving brought that sand to that spot on the beach and then I took it away. Every day he said we change the world. Which is a nice thought until I think about how many days and lifetimes I would need to bring a shoe full of sand home until there is no beach. Until it made a difference to anyone. Every day we change the world. But to change the world in a way that means anything that takes more time than most people have. it never happens all at once. Its slow. Its methodical. Its exhausting. We don't all have the stomach for it.",
"source": "Mr. Robot",
"length": 942,
"id": 5485
}
]
}
}

View file

@ -1,22 +1,10 @@
{
"language": "german",
"groups": [
[
0,
100
],
[
101,
300
],
[
301,
600
],
[
601,
9999
]
[0, 100],
[101, 300],
[301, 600],
[601, 9999]
],
"quotes": [
{
@ -320,7 +308,7 @@
"id": 50
},
{
"text": "Das schauerlichste Übel also, der Tod, geht uns nichts an; denn solange wir existieren, ist der Tod nicht da, und wenn der Tod da ist, existieren wir nicht mehr.",
"text": "Das schauerlichste Übel, also der Tod, geht uns nichts an; denn solange wir existieren, ist der Tod nicht da, und wenn der Tod da ist, existieren wir nicht mehr.",
"source": "Epikur",
"length": 161,
"id": 51
@ -722,4 +710,4 @@
"id": 117
}
]
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -4,6 +4,11 @@
"bgColor": "#111",
"textColor": "#eee"
},
{
"name": "muted",
"bgColor": "#525252",
"textColor": "#B1E4E3"
},
{
"name": "dark_magic_girl",
"bgColor": "#091f2c",
@ -69,6 +74,11 @@
"bgColor": "#0f1f2c",
"textColor": "#56c3b7"
},
{
"name": "mountain",
"bgColor": "#0f0f0f",
"textColor": "#e7e7e7"
},
{
"name": "laser",
"bgColor": "#221b44",

View file

@ -0,0 +1,11 @@
:root {
--bg-color: #0f0f0f;
--main-color: #e7e7e7;
--caret-color: #f5f5f5;
--sub-color: #4c4c4c;
--text-color: #e7e7e7;
--error-color: #ac8c8c;
--error-extra-color: #c49ea0;
--colorful-error-color: #aca98a;
--colorful-error-extra-color: #c4c19e;
}

8
static/themes/muted.css Normal file
View file

@ -0,0 +1,8 @@
:root {
--bg-color: #525252;
--main-color: #C5B4E3;
--caret-color: #B1E4E3;
--sub-color: #939eae;
--text-color: #B1E4E3;
--error-color: #EDC1CD;
}