refactored misc and cloud functions

This commit is contained in:
typer 2020-11-27 23:27:24 -08:00
parent b875d7933f
commit decba8eaaa
13 changed files with 530 additions and 487 deletions

View file

@ -85,13 +85,18 @@ let eslintConfig = {
//refactored files, which should be es6 modules
//once all files are moved here, then can we use a bundler to its full potential
const refactoredSrc = ["./src/js/db.js"];
const refactoredSrc = [
"./src/js/db.js",
"./src/js/dom-util.js",
"./src/js/cloud-functions.js",
"./src/js/misc.js",
];
//legacy files
//the order of files is important
const globalSrc = [
"./src/js/global-dependencies.js",
"./src/js/misc.js",
"./src/js/simple-popups.js",
"./src/js/words.js",
"./src/js/layouts.js",
"./src/js/userconfig.js",

View file

@ -38,11 +38,11 @@ $(".pageLogin #forgotPasswordButton").click((e) => {
.sendPasswordResetEmail(email)
.then(function () {
// Email sent.
showNotification("Email sent", 2000);
Misc.showNotification("Email sent", 2000);
})
.catch(function (error) {
// An error happened.
showNotification(error.message, 5000);
Misc.showNotification(error.message, 5000);
});
}
});
@ -73,7 +73,7 @@ function signIn() {
changePage("test");
})
.catch(function (error) {
showNotification(error.message, 5000);
Misc.showNotification(error.message, 5000);
$(".pageLogin .preloader").addClass("hidden");
});
});
@ -90,7 +90,7 @@ function signIn() {
changePage("test");
})
.catch(function (error) {
showNotification(error.message, 5000);
Misc.showNotification(error.message, 5000);
$(".pageLogin .preloader").addClass("hidden");
});
});
@ -108,22 +108,20 @@ function signUp() {
let passwordVerify = $(".pageLogin .register input")[3].value;
if (password != passwordVerify) {
showNotification("Passwords do not match", 3000);
Misc.showNotification("Passwords do not match", 3000);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .register .button").removeClass("disabled");
return;
}
const namecheck = firebase.functions().httpsCallable("checkNameAvailability");
namecheck({ name: nname }).then((d) => {
CloudFunctions.namecheck({ name: nname }).then((d) => {
if (d.data === -1) {
showNotification("Name unavailable", 3000);
Misc.showNotification("Name unavailable", 3000);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .register .button").removeClass("disabled");
return;
} else if (d.data === -2) {
showNotification(
Misc.showNotification(
"Name cannot contain special characters or contain more than 14 characters. Can include _ . and -",
8000
);
@ -149,10 +147,10 @@ function signUp() {
.collection("users")
.doc(usr.uid)
.set({ name: nname }, { merge: true });
reserveName({ name: nname, uid: usr.uid });
CloudFunctions.reserveName({ name: nname, uid: usr.uid });
usr.sendEmailVerification();
clearGlobalStats();
showNotification("Account created", 2000);
Misc.showNotification("Account created", 2000);
$("#menu .icon-button.account .text").text(nname);
try {
firebase.analytics().logEvent("accountCreated", usr.uid);
@ -172,7 +170,7 @@ function signUp() {
});
if (notSignedInLastResult !== null) {
notSignedInLastResult.uid = usr.uid;
testCompleted({
CloudFunctions.testCompleted({
uid: usr.uid,
obj: notSignedInLastResult,
});
@ -191,7 +189,7 @@ function signUp() {
.delete()
.then(function () {
// User deleted.
showNotification(
Misc.showNotification(
"An error occured. Account not created.",
2000
);
@ -208,7 +206,7 @@ function signUp() {
// Handle Errors here.
$(".pageLogin .register .button").removeClass("disabled");
var errorMessage = error.message;
showNotification(errorMessage, 5000);
Misc.showNotification(errorMessage, 5000);
$(".pageLogin .preloader").addClass("hidden");
});
}
@ -220,7 +218,7 @@ function signOut() {
.auth()
.signOut()
.then(function () {
showNotification("Signed out", 2000);
Misc.showNotification("Signed out", 2000);
clearGlobalStats();
hideAccountSettingsSection();
updateAccountLoginButton();
@ -228,7 +226,7 @@ function signOut() {
db_setSnapshot(null);
})
.catch(function (error) {
showNotification(error.message, 5000);
Misc.showNotification(error.message, 5000);
});
}
@ -268,10 +266,10 @@ firebase.auth().onAuthStateChanged(function (user) {
$(".pageAccount .group.createdDate").text(text);
if (verifyUserWhenLoggedIn !== null) {
showNotification("Verifying", 1000);
Misc.showNotification("Verifying", 1000);
verifyUserWhenLoggedIn.uid = user.uid;
verifyUser(verifyUserWhenLoggedIn).then((data) => {
showNotification(data.data.message, 3000);
CloudFunctions.verifyUser(verifyUserWhenLoggedIn).then((data) => {
Misc.showNotification(data.data.message, 3000);
if (data.data.status === 1) {
db_getSnapshot().discordId = data.data.did;
updateDiscordSettingsSection();
@ -279,14 +277,14 @@ firebase.auth().onAuthStateChanged(function (user) {
});
}
}
let theme = findGetParameter("customTheme");
let theme = Misc.findGetParameter("customTheme");
if (theme !== null) {
try {
theme = theme.split(",");
config.customThemeColors = theme;
showNotification("Custom theme applied.", 1000);
Misc.showNotification("Custom theme applied.", 1000);
} catch (e) {
showNotification(
Misc.showNotification(
"Something went wrong. Reverting to default custom colors.",
3000
);
@ -393,7 +391,7 @@ function getAccountDataAndInit() {
.catch((e) => {
accountIconLoading(false);
console.error(e);
showNotification(
Misc.showNotification(
"Error downloading user data. Refresh to try again. If error persists contact Miodec.",
5000
);
@ -1003,7 +1001,7 @@ let defaultAccountFilters = {
},
};
getLanguageList().then((languages) => {
Misc.getLanguageList().then((languages) => {
languages.forEach((language) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.languages .buttons"
@ -1020,7 +1018,7 @@ getLanguageList().then((languages) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .buttons"
).append(`<div class="button" filter="none">none</div>`);
getFunboxList().then((funboxModes) => {
Misc.getFunboxList().then((funboxModes) => {
funboxModes.forEach((funbox) => {
$(
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .buttons"
@ -1883,7 +1881,7 @@ function refreshAccountPage() {
filteredResults.push(result);
} catch (e) {
showNotification(
Misc.showNotification(
"Something went wrong when filtering. Resetting filters.",
5000
);
@ -2038,7 +2036,7 @@ function refreshAccountPage() {
});
activityChartData_avgWpm.push({
x: parseInt(date),
y: roundTo2(
y: Misc.roundTo2(
activityChartData[date].totalWpm / activityChartData[date].amount
),
});
@ -2206,7 +2204,7 @@ function refreshAccountPage() {
let wpmPoints = filteredResults.map((r) => r.wpm).reverse();
let trend = findLineByLeastSquares(wpmPoints);
let trend = Misc.findLineByLeastSquares(wpmPoints);
let wpmChange = trend[1][1] - trend[0][1];
@ -2216,7 +2214,7 @@ function refreshAccountPage() {
$(".pageAccount .group.chart .below .text").text(
`Speed change per hour spent typing: ${
plus + roundTo2(wpmChangePerHour)
plus + Misc.roundTo2(wpmChangePerHour)
} wpm.`
);
@ -2226,7 +2224,7 @@ function refreshAccountPage() {
swapElements($(".pageAccount .preloader"), $(".pageAccount .content"), 250);
}
if (db_getSnapshot() === null) {
showNotification(`Missing account data. Please refresh.`, 5000);
Misc.showNotification(`Missing account data. Please refresh.`, 5000);
$(".pageAccount .preloader").html("Missing account data. Please refresh.");
} else if (db_getSnapshot().results === undefined) {
db_getUserResults().then((d) => {
@ -2244,7 +2242,7 @@ function refreshAccountPage() {
cont();
} catch (e) {
console.error(e);
showNotification(`Something went wrong: ${e}`, 5000);
Misc.showNotification(`Something went wrong: ${e}`, 5000);
}
}
}
@ -2339,14 +2337,14 @@ $("#resultEditTagsPanel .confirmButton").click((f) => {
});
showBackgroundLoader();
hideResultEditTagsPanel();
updateResultTags({
CloudFunctions.updateResultTags({
uid: firebase.auth().currentUser.uid,
tags: newtags,
resultid: resultid,
}).then((r) => {
hideBackgroundLoader();
if (r.data.resultCode === 1) {
showNotification("Tags updated.", 3000);
Misc.showNotification("Tags updated.", 3000);
db_getSnapshot().results.forEach((result) => {
if (result.id === resultid) {
result.tags = newtags;
@ -2397,7 +2395,7 @@ $("#resultEditTagsPanel .confirmButton").click((f) => {
);
}
} else {
showNotification("Error updating tags", 3000);
Misc.showNotification("Error updating tags", 3000);
}
});
});

28
src/js/cloud-functions.js Normal file
View file

@ -0,0 +1,28 @@
export const testCompleted = firebase
.functions()
.httpsCallable("testCompleted");
export const addTag = firebase.functions().httpsCallable("addTag");
export const editTag = firebase.functions().httpsCallable("editTag");
export const removeTag = firebase.functions().httpsCallable("removeTag");
export const updateResultTags = firebase
.functions()
.httpsCallable("updateResultTags");
export const saveConfig = firebase.functions().httpsCallable("saveConfig");
export const generatePairingCode = firebase
.functions()
.httpsCallable("generatePairingCode");
export const saveLbMemory = firebase.functions().httpsCallable("saveLbMemory");
export const unlinkDiscord = firebase
.functions()
.httpsCallable("unlinkDiscord");
export const verifyUser = firebase.functions().httpsCallable("verifyUser");
export const reserveName = firebase
.functions()
.httpsCallable("reserveDisplayName");
export const updateEmail = firebase.functions().httpsCallable("updateEmail");
export const namecheck = firebase
.functions()
.httpsCallable("checkNameAvailability");
export const getLeaderboard = firebase
.functions()
.httpsCallable("getLeaderboard");

View file

@ -1,3 +1,17 @@
function canBailOut() {
return (
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount >= 5000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length >= 5000) ||
(config.mode === "words" && config.words >= 5000) ||
config.words === 0 ||
(config.mode === "time" && (config.time >= 3600 || config.time === 0))
);
}
function addChildCommands(
unifiedCommands,
commandItem,
@ -557,7 +571,7 @@ let commands = {
id: "toggleFullscreen",
display: "Toggle Fullscreen",
exec: () => {
toggleFullscreen();
Misc.toggleFullscreen();
},
},
{
@ -841,7 +855,7 @@ let commandsEnableAds = {
display: "off",
exec: () => {
setEnableAds("off");
showNotification("Don't forget to refresh the page!", 3000);
Misc.showNotification("Don't forget to refresh the page!", 3000);
},
},
{
@ -849,7 +863,7 @@ let commandsEnableAds = {
display: "on",
exec: () => {
setEnableAds("on");
showNotification("Don't forget to refresh the page!", 3000);
Misc.showNotification("Don't forget to refresh the page!", 3000);
},
},
{
@ -857,7 +871,7 @@ let commandsEnableAds = {
display: "Sellout",
exec: () => {
setEnableAds("max");
showNotification("Don't forget to refresh the page!", 3000);
Misc.showNotification("Don't forget to refresh the page!", 3000);
},
},
],
@ -1510,10 +1524,10 @@ function updateCommandsTagsList() {
}
}
getThemesList().then((themes) => {
Misc.getThemesList().then((themes) => {
themes.forEach((theme) => {
commandsThemes.list.push({
id: "changeTheme" + capitalizeFirstLetter(theme.name),
id: "changeTheme" + Misc.capitalizeFirstLetter(theme.name),
display: theme.name.replace(/_/g, " "),
hover: () => {
previewTheme(theme.name);
@ -1530,7 +1544,7 @@ function showFavouriteThemesAtTheTop() {
commandsThemes.list = [];
config.favThemes.forEach((theme) => {
commandsThemes.list.push({
id: "changeTheme" + capitalizeFirstLetter(theme),
id: "changeTheme" + Misc.capitalizeFirstLetter(theme),
display: theme.replace(/_/g, " "),
hover: () => {
previewTheme(theme);
@ -1540,11 +1554,11 @@ function showFavouriteThemesAtTheTop() {
},
});
});
getThemesList().then((themes) => {
Misc.getThemesList().then((themes) => {
themes.forEach((theme) => {
if (config.favThemes.includes(theme.name)) return;
commandsThemes.list.push({
id: "changeTheme" + capitalizeFirstLetter(theme.name),
id: "changeTheme" + Misc.capitalizeFirstLetter(theme.name),
display: theme.name.replace(/_/g, " "),
hover: () => {
previewTheme(theme.name);
@ -1563,7 +1577,7 @@ let commandsFonts = {
list: [],
};
getFontsList().then((fonts) => {
Misc.getFontsList().then((fonts) => {
fonts.forEach((font) => {
commandsFonts.list.push({
id: "changeFont" + font.name.replace(/ /g, "_"),
@ -1593,7 +1607,7 @@ let commandsFunbox = {
],
};
getFunboxList().then((funboxes) => {
Misc.getFunboxList().then((funboxes) => {
funboxes.forEach((funbox) => {
commandsFunbox.list.push({
id: "changeFunbox" + funbox.name,
@ -1623,10 +1637,10 @@ let commandsLanguages = {
};
commandsLanguages.list = [];
getLanguageList().then((languages) => {
Misc.getLanguageList().then((languages) => {
languages.forEach((language) => {
commandsLanguages.list.push({
id: "changeLanguage" + capitalizeFirstLetter(language),
id: "changeLanguage" + Misc.capitalizeFirstLetter(language),
display: language.replace(/_/g, " "),
exec: () => {
setLanguage(language);
@ -1651,7 +1665,7 @@ if (Object.keys(layouts).length > 0) {
commandsLayouts.list = [];
Object.keys(layouts).forEach((layout) => {
commandsLayouts.list.push({
id: "changeLayout" + capitalizeFirstLetter(layout),
id: "changeLayout" + Misc.capitalizeFirstLetter(layout),
display: layout.replace(/_/g, " "),
exec: () => {
setSavedLayout(layout);
@ -1685,7 +1699,7 @@ if (Object.keys(layouts).length > 0) {
Object.keys(layouts).forEach((layout) => {
if (layout.toString() != "default") {
commandsKeymapLayouts.list.push({
id: "changeKeymapLayout" + capitalizeFirstLetter(layout),
id: "changeKeymapLayout" + Misc.capitalizeFirstLetter(layout),
display: layout.replace(/_/g, " "),
exec: () => {
setKeymapLayout(layout);

7
src/js/dom-util.js Normal file
View file

@ -0,0 +1,7 @@
export function showBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeIn(125);
}
export function hideBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeOut(125);
}

View file

@ -1,4 +1,8 @@
//this file should be concatenated with the legacy js files
//try to keep this list short because we need to eliminate it eventually
global.simplePopups = simplePopups;
global.sendVerificationEmail = Misc.sendVerificationEmail;
//these exports are just for debugging in the browser
global.snapshot = db_getSnapshot;

View file

@ -16,3 +16,7 @@ import {
db_getLocalPB,
db_saveLocalPB,
} from "./db";
import { showBackgroundLoader, hideBackgroundLoader } from "./dom-util";
import * as Misc from "./misc";
import * as CloudFunctions from "./cloud-functions";

View file

@ -49,13 +49,13 @@ function updateLeaderboards() {
showBackgroundLoader();
Promise.all([
firebase.functions().httpsCallable("getLeaderboard")({
CloudFunctions.getLeaderboard({
mode: boardinfo[0],
mode2: boardinfo[1],
type: "daily",
uid: uid,
}),
firebase.functions().httpsCallable("getLeaderboard")({
CloudFunctions.getLeaderboard({
mode: boardinfo[0],
mode2: boardinfo[1],
type: "global",
@ -217,7 +217,7 @@ function updateLeaderboards() {
}
})
.catch((e) => {
showNotification("Something went wrong", 3000);
Misc.showNotification("Something went wrong", 3000);
});
}

View file

@ -1,5 +1,7 @@
import { showBackgroundLoader, hideBackgroundLoader } from "./dom-util";
let themesList = null;
async function getThemesList() {
export async function getThemesList() {
if (themesList == null) {
return $.getJSON("themes/list.json", function (data) {
const list = data.sort(function (a, b) {
@ -18,7 +20,7 @@ async function getThemesList() {
}
let sortedThemesList = null;
async function getSortedThemesList() {
export async function getSortedThemesList() {
if (sortedThemesList == null) {
if (themesList == null) {
await getThemesList();
@ -36,7 +38,7 @@ async function getSortedThemesList() {
}
let funboxList = null;
async function getFunboxList() {
export async function getFunboxList() {
if (funboxList == null) {
return $.getJSON("funbox/list.json", function (data) {
funboxList = data.sort(function (a, b) {
@ -54,7 +56,7 @@ async function getFunboxList() {
}
let fontsList = null;
async function getFontsList() {
export async function getFontsList() {
if (fontsList == null) {
return $.getJSON("js/fonts.json", function (data) {
fontsList = data.sort(function (a, b) {
@ -72,7 +74,7 @@ async function getFontsList() {
}
let languageList = null;
async function getLanguageList() {
export async function getLanguageList() {
if (languageList == null) {
return $.getJSON("languages/list.json", function (data) {
languageList = data;
@ -84,7 +86,12 @@ async function getLanguageList() {
}
let currentLanguage = null;
async function getLanguage(lang) {
export function getCurrentLanguage() {
return currentLanguage;
}
export async function getLanguage(lang) {
try {
if (currentLanguage == null || currentLanguage.name !== lang) {
console.log("getting language json");
@ -96,7 +103,8 @@ async function getLanguage(lang) {
} catch (e) {
console.error(`error getting language`);
console.error(e);
config.language = "english";
//TODO: set config language to english
//config.language = "english";
showNotification(`Error getting language: ${e.message}`, 4000);
await $.getJSON(`languages/english.json`, function (data) {
currentLanguage = data;
@ -105,14 +113,14 @@ async function getLanguage(lang) {
}
}
function setCookie(cname, cvalue, exdays) {
export function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
var expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname) {
export function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(";");
@ -128,7 +136,7 @@ function getCookie(cname) {
return "";
}
function sendVerificationEmail() {
export function sendVerificationEmail() {
showBackgroundLoader();
let cu = firebase.auth().currentUser;
cu.sendEmailVerification()
@ -142,9 +150,8 @@ function sendVerificationEmail() {
console.error(e.message);
});
}
window.sendVerificationEmail = sendVerificationEmail;
function smooth(arr, windowSize, getter = (value) => value, setter) {
export function smooth(arr, windowSize, getter = (value) => value, setter) {
const get = getter;
const result = [];
@ -166,7 +173,7 @@ function smooth(arr, windowSize, getter = (value) => value, setter) {
return result;
}
function stdDev(array) {
export function stdDev(array) {
try {
const n = array.length;
const mean = array.reduce((a, b) => a + b) / n;
@ -178,7 +185,7 @@ function stdDev(array) {
}
}
function mean(array) {
export function mean(array) {
try {
return (
array.reduce((previous, current) => (current += previous)) / array.length
@ -188,7 +195,7 @@ function mean(array) {
}
}
function showNotification(text, time) {
export function showNotification(text, time) {
let noti = $(".notification");
noti.text(text);
noti.css("top", `-${noti.outerHeight()}px`);
@ -221,7 +228,7 @@ function showNotification(text, time) {
);
}
function getReleasesFromGitHub() {
export function getReleasesFromGitHub() {
$.getJSON(
"https://api.github.com/repos/Miodec/monkeytype/releases",
(data) => {
@ -257,19 +264,19 @@ function getReleasesFromGitHub() {
// });
// }
function getLastChar(word) {
export function getLastChar(word) {
return word.charAt(word.length - 1);
}
function capitalizeFirstLetter(str) {
export function capitalizeFirstLetter(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function isASCIILetter(c) {
export function isASCIILetter(c) {
return c.length === 1 && /[a-z]/i.test(c);
}
function kogasa(cov) {
export function kogasa(cov) {
return (
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
);
@ -322,11 +329,11 @@ function hexToHSL(H) {
};
}
function roundTo2(num) {
export function roundTo2(num) {
return Math.round((num + Number.EPSILON) * 100) / 100;
}
function findLineByLeastSquares(values_y) {
export function findLineByLeastSquares(values_y) {
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
@ -372,11 +379,7 @@ function findLineByLeastSquares(values_y) {
return [returnpoint1, returnpoint2];
}
function calculateSlope([[x1, y1], [x2, y2]]) {
return (y1 - y2) / (x1 - x2);
}
function getGibberish() {
export function getGibberish() {
let randLen = Math.floor(Math.random() * 7) + 1;
let ret = "";
for (let i = 0; i < randLen; i++) {
@ -385,7 +388,7 @@ function getGibberish() {
return ret;
}
function secondsToString(sec) {
export function secondsToString(sec) {
const hours = Math.floor(sec / 3600);
const minutes = Math.floor((sec % 3600) / 60);
const seconds = roundTo2((sec % 3600) % 60);
@ -405,7 +408,7 @@ function secondsToString(sec) {
return ret;
}
function getNumbers(len) {
export function getNumbers(len) {
let randLen = Math.floor(Math.random() * len) + 1;
let ret = "";
for (let i = 0; i < randLen; i++) {
@ -415,7 +418,7 @@ function getNumbers(len) {
return ret;
}
function getSpecials() {
export function getSpecials() {
let randLen = Math.floor(Math.random() * 7) + 1;
let ret = "";
let specials = [
@ -449,7 +452,7 @@ function getSpecials() {
return ret;
}
function getASCII() {
export function getASCII() {
let randLen = Math.floor(Math.random() * 10) + 1;
let ret = "";
for (let i = 0; i < randLen; i++) {
@ -458,7 +461,7 @@ function getASCII() {
return ret;
}
function getPositionString(number) {
export function getPositionString(number) {
let numend = "th";
let t = number % 10;
let h = number % 100;
@ -474,7 +477,7 @@ function getPositionString(number) {
return number + numend;
}
function findGetParameter(parameterName) {
export function findGetParameter(parameterName) {
var result = null,
tmp = [];
location.search
@ -487,7 +490,7 @@ function findGetParameter(parameterName) {
return result;
}
function objectToQueryString(obj) {
export function objectToQueryString(obj) {
var str = [];
for (var p in obj)
if (Object.prototype.hasOwnProperty.call(obj, p)) {
@ -496,7 +499,7 @@ function objectToQueryString(obj) {
return str.join("&");
}
function toggleFullscreen(elem) {
export function toggleFullscreen(elem) {
elem = elem || document.documentElement;
if (
@ -526,184 +529,3 @@ function toggleFullscreen(elem) {
}
}
}
function canBailOut() {
return (
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount >= 5000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length >= 5000) ||
(config.mode === "words" && config.words >= 5000) ||
config.words === 0 ||
(config.mode === "time" && (config.time >= 3600 || config.time === 0))
);
}
let simplePopups = {};
window.simplePopups = simplePopups;
class SimplePopup {
constructor(
id,
type,
title,
inputs = [],
text = "",
buttonText = "Confirm",
execFn
) {
this.id = id;
this.type = type;
this.execFn = execFn;
this.title = title;
this.inputs = inputs;
this.text = text;
this.wrapper = $("#simplePopupWrapper");
this.element = $("#simplePopup");
this.buttonText = buttonText;
}
reset() {
this.element.html(`
<div class="title"></div>
<form class="inputs"></form>
<div class="text"></div>
<div class="button"></div>`);
}
init() {
let el = this.element;
el.find("input").val("");
if (el.attr("popupId") !== this.id) {
this.reset();
el.attr("popupId", this.id);
el.find(".title").text(this.title);
el.find(".text").text(this.text);
this.initInputs();
el.find(".button").text(this.buttonText);
}
}
initInputs() {
let el = this.element;
if (this.inputs.length > 0) {
if (this.type === "number") {
this.inputs.forEach((input) => {
el.find(".inputs").append(`
<input type="number" min="1" val="${input.initVal}" placeholder="${input.placeholder}" required>
`);
});
} else if (this.type === "text") {
this.inputs.forEach((input) => {
el.find(".inputs").append(`
<input type="text" val="${input.initVal}" placeholder="${input.placeholder}" required>
`);
});
}
el.find(".inputs").removeClass("hidden");
} else {
el.find(".inputs").addClass("hidden");
}
}
exec() {
let vals = [];
$.each($("#simplePopup input"), (index, el) => {
vals.push($(el).val());
});
this.execFn(...vals);
this.hide();
}
show() {
this.init();
this.wrapper
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 125, () => {
$($("#simplePopup").find("input")[0]).focus();
});
}
hide() {
this.wrapper
.stop(true, true)
.css("opacity", 1)
.removeClass("hidden")
.animate({ opacity: 0 }, 125, () => {
this.wrapper.addClass("hidden");
});
}
}
$("#simplePopupWrapper").click((e) => {
if ($(e.target).attr("id") === "simplePopupWrapper") {
$("#simplePopupWrapper")
.stop(true, true)
.css("opacity", 1)
.removeClass("hidden")
.animate({ opacity: 0 }, 125, () => {
$("#simplePopupWrapper").addClass("hidden");
});
}
});
$(document).on("click", "#simplePopupWrapper .button", (e) => {
let id = $("#simplePopup").attr("popupId");
simplePopups[id].exec();
});
$(document).on("keyup", "#simplePopupWrapper input", (e) => {
if (e.key === "Enter") {
let id = $("#simplePopup").attr("popupId");
simplePopups[id].exec();
}
});
simplePopups.updateEmail = new SimplePopup(
"updateEmail",
"text",
"Update Email",
[
{
placeholder: "Current email",
initVal: "",
},
{
placeholder: "New email",
initVal: "",
},
],
"Don't mess this one up or you won't be able to login!",
"Update",
(previousEmail, newEmail) => {
try {
showBackgroundLoader();
updateEmail({
uid: firebase.auth().currentUser.uid,
previousEmail: previousEmail,
newEmail: newEmail,
}).then((data) => {
hideBackgroundLoader();
if (data.data.resultCode === 1) {
showNotification("Email updated", 2000);
setTimeout(() => {
signOut();
}, 1000);
} else if (data.data.resultCode === -1) {
showNotification("Current email doesn't match", 2000);
} else {
showNotification(
"Something went wrong: " + JSON.stringify(data.data),
7000
);
}
});
} catch (e) {
showNotification("Something went wrong: " + e, 5000);
}
}
);

View file

@ -203,21 +203,6 @@ let customTextIsRandom = false;
let customTextWordCount = 1;
let randomQuote = null;
const testCompleted = firebase.functions().httpsCallable("testCompleted");
const addTag = firebase.functions().httpsCallable("addTag");
const editTag = firebase.functions().httpsCallable("editTag");
const removeTag = firebase.functions().httpsCallable("removeTag");
const updateResultTags = firebase.functions().httpsCallable("updateResultTags");
const saveConfig = firebase.functions().httpsCallable("saveConfig");
const generatePairingCode = firebase
.functions()
.httpsCallable("generatePairingCode");
const saveLbMemory = firebase.functions().httpsCallable("saveLbMemory");
const unlinkDiscord = firebase.functions().httpsCallable("unlinkDiscord");
const verifyUser = firebase.functions().httpsCallable("verifyUser");
const reserveName = firebase.functions().httpsCallable("reserveDisplayName");
const updateEmail = firebase.functions().httpsCallable("updateEmail");
function refreshThemeColorObject() {
let st = getComputedStyle(document.body);
@ -240,7 +225,10 @@ function refreshThemeColorObject() {
function copyResultToClipboard() {
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
showNotification("Sorry, this feature is not supported in Firefox", 4000);
Misc.showNotification(
"Sorry, this feature is not supported in Firefox",
4000
);
} else {
$(".pageTest .ssWatermark").removeClass("hidden");
$(".pageTest .buttons").addClass("hidden");
@ -271,7 +259,7 @@ function copyResultToClipboard() {
])
.then((f) => {
$(".notification").removeClass("hidden");
showNotification("Copied to clipboard", 1000);
Misc.showNotification("Copied to clipboard", 1000);
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
if (firebase.auth().currentUser == null)
@ -279,7 +267,7 @@ function copyResultToClipboard() {
})
.catch((f) => {
$(".notification").removeClass("hidden");
showNotification("Error saving image to clipboard", 2000);
Misc.showNotification("Error saving image to clipboard", 2000);
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
if (firebase.auth().currentUser == null)
@ -289,7 +277,7 @@ function copyResultToClipboard() {
});
} catch (e) {
$(".notification").removeClass("hidden");
showNotification("Error creating image", 2000);
Misc.showNotification("Error creating image", 2000);
$(".pageTest .ssWatermark").addClass("hidden");
$(".pageTest .buttons").removeClass("hidden");
if (firebase.auth().currentUser == null)
@ -300,15 +288,15 @@ function copyResultToClipboard() {
function activateFunbox(funbox, mode) {
if (testActive || resultVisible) {
showNotification(
Misc.showNotification(
"You can only change the funbox before starting a test.",
4000
);
return false;
}
if (currentLanguage.ligatures) {
if (Misc.getCurrentLanguage().ligatures) {
if (funbox == "choo_choo" || funbox == "earthquake") {
showNotification(
Misc.showNotification(
"Current language does not support this funbox mode",
3000
);
@ -424,7 +412,7 @@ async function initWords() {
currentCorrected = "";
currentInput = "";
let language = await getLanguage(config.language);
let language = await Misc.getLanguage(config.language);
if (config.mode === "quote" && quotes === null) {
showBackgroundLoader();
@ -526,16 +514,16 @@ async function initWords() {
}
randomWord = randomcaseword;
} else if (activeFunBox === "gibberish") {
randomWord = getGibberish();
randomWord = Misc.getGibberish();
} else if (activeFunBox === "58008") {
setToggleSettings(false, true);
randomWord = getNumbers(7);
randomWord = Misc.getNumbers(7);
} else if (activeFunBox === "specials") {
setToggleSettings(false, true);
randomWord = getSpecials();
randomWord = Misc.getSpecials();
} else if (activeFunBox === "ascii") {
setToggleSettings(false, true);
randomWord = getASCII();
randomWord = Misc.getASCII();
}
if (config.punctuation && config.mode != "custom") {
@ -543,7 +531,7 @@ async function initWords() {
}
if (config.numbers && config.mode != "custom") {
if (Math.random() < 0.1) {
randomWord = getNumbers(4);
randomWord = Misc.getNumbers(4);
}
}
@ -603,7 +591,8 @@ function emulateLayout(event) {
function emulatedLayoutShouldShiftKey(event, newKeyPreview) {
if (config.capsLockBackspace) return event.shiftKey;
const isCapsLockHeld = event.originalEvent.getModifierState("CapsLock");
if (isCapsLockHeld) return isASCIILetter(newKeyPreview) !== event.shiftKey;
if (isCapsLockHeld)
return Misc.isASCIILetter(newKeyPreview) !== event.shiftKey;
return event.shiftKey;
}
@ -617,7 +606,7 @@ function emulateLayout(event) {
}
if (config.layout === "default") {
//override the caps lock modifier for the default layout if needed
if (config.capsLockBackspace && isASCIILetter(event.key)) {
if (config.capsLockBackspace && Misc.isASCIILetter(event.key)) {
replaceEventKey(
event,
event.shiftKey
@ -698,16 +687,16 @@ function punctuateWord(previousWord, currentWord, index, maxindex) {
if (
index == 0 ||
getLastChar(previousWord) == "." ||
getLastChar(previousWord) == "?" ||
getLastChar(previousWord) == "!"
Misc.getLastChar(previousWord) == "." ||
Misc.getLastChar(previousWord) == "?" ||
Misc.getLastChar(previousWord) == "!"
) {
//always capitalise the first word or if there was a dot
word = capitalizeFirstLetter(word);
word = Misc.capitalizeFirstLetter(word);
} else if (
//10% chance to end a sentence
(Math.random() < 0.1 &&
getLastChar(previousWord) != "." &&
Misc.getLastChar(previousWord) != "." &&
index != maxindex - 2) ||
index == maxindex - 1
) {
@ -721,8 +710,8 @@ function punctuateWord(previousWord, currentWord, index, maxindex) {
}
} else if (
Math.random() < 0.01 &&
getLastChar(previousWord) != "," &&
getLastChar(previousWord) != "."
Misc.getLastChar(previousWord) != "," &&
Misc.getLastChar(previousWord) != "."
) {
//1% chance to add quotes
word = `"${word}"`;
@ -731,21 +720,21 @@ function punctuateWord(previousWord, currentWord, index, maxindex) {
word = word + ":";
} else if (
Math.random() < 0.01 &&
getLastChar(previousWord) != "," &&
getLastChar(previousWord) != "." &&
Misc.getLastChar(previousWord) != "," &&
Misc.getLastChar(previousWord) != "." &&
previousWord != "-"
) {
//1% chance to add a dash
word = "-";
} else if (
Math.random() < 0.01 &&
getLastChar(previousWord) != "," &&
getLastChar(previousWord) != "." &&
getLastChar(previousWord) != ";"
Misc.getLastChar(previousWord) != "," &&
Misc.getLastChar(previousWord) != "." &&
Misc.getLastChar(previousWord) != ";"
) {
//1% chance to add semicolon
word = word + ";";
} else if (Math.random() < 0.2 && getLastChar(previousWord) != ",") {
} else if (Math.random() < 0.2 && Misc.getLastChar(previousWord) != ",") {
//2% chance to add a comma
word += ",";
}
@ -770,10 +759,10 @@ function addWord() {
return;
const language =
config.mode !== "custom"
? currentLanguage
? Misc.getCurrentLanguage()
: {
//borrow the direction of the current language
leftToRight: currentLanguage.leftToRight,
leftToRight: Misc.getCurrentLanguage().leftToRight,
words: customText,
};
const wordset = language.words;
@ -812,13 +801,13 @@ function addWord() {
}
randomWord = randomcaseword;
} else if (activeFunBox === "gibberish") {
randomWord = getGibberish();
randomWord = Misc.getGibberish();
} else if (activeFunBox === "58008") {
randomWord = getNumbers(7);
randomWord = Misc.getNumbers(7);
} else if (activeFunBox === "specials") {
randomWord = getSpecials();
randomWord = Misc.getSpecials();
} else if (activeFunBox === "ascii") {
randomWord = getASCII();
randomWord = Misc.getASCII();
}
if (config.punctuation && config.mode != "custom") {
@ -826,7 +815,7 @@ function addWord() {
}
if (config.numbers && config.mode != "custom") {
if (Math.random() < 0.1) {
randomWord = getNumbers(4);
randomWord = Misc.getNumbers(4);
}
}
@ -888,7 +877,7 @@ $("#restartTestButton, #startTestButton").on("click", function () {
memoryFunboxTimer = Math.round(Math.pow(wordsList.length, 1.2));
memoryFunboxInterval = setInterval(() => {
memoryFunboxTimer -= 1;
showNotification(memoryFunboxTimer);
Misc.showNotification(memoryFunboxTimer);
if (memoryFunboxTimer < 0) {
memoryFunboxInterval = clearInterval(memoryFunboxInterval);
memoryFunboxTimer = null;
@ -965,7 +954,7 @@ function compareInput(showError) {
showResult(true);
}
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
@ -1013,7 +1002,7 @@ function compareInput(showError) {
showResult(true);
}
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
@ -1166,15 +1155,15 @@ function updateTimer() {
"linear"
);
} else if (config.timerStyle === "text") {
let displayTime = secondsToString(config.time - time);
let displayTime = Misc.secondsToString(config.time - time);
if (config.time === 0) {
displayTime = secondsToString(time);
displayTime = Misc.secondsToString(time);
}
$("#timerNumber").html("<div>" + displayTime + "</div>");
} else if (config.timerStyle === "mini") {
let displayTime = secondsToString(config.time - time);
let displayTime = Misc.secondsToString(config.time - time);
if (config.time === 0) {
displayTime = secondsToString(time);
displayTime = Misc.secondsToString(time);
}
$("#miniTimerAndLiveWpm .time").html(displayTime);
}
@ -1449,7 +1438,7 @@ function updateCaretPosition() {
}
if ($(currentLetter).length == 0) return;
const isLanguageLeftToRight = currentLanguage.leftToRight;
const isLanguageLeftToRight = Misc.getCurrentLanguage().leftToRight;
let currentLetterPosLeft = isLanguageLeftToRight
? currentLetter.offsetLeft
: currentLetter.offsetLeft + $(currentLetter).width();
@ -1590,10 +1579,10 @@ function countChars() {
function calculateStats() {
let testSeconds = (testEnd - testStart) / 1000;
let chars = countChars();
let wpm = roundTo2(
let wpm = Misc.roundTo2(
((chars.correctWordChars + chars.correctSpaces) * (60 / testSeconds)) / 5
);
let wpmraw = roundTo2(
let wpmraw = Misc.roundTo2(
((chars.allCorrectChars +
chars.spaces +
chars.incorrectChars +
@ -1601,7 +1590,7 @@ function calculateStats() {
(60 / testSeconds)) /
5
);
let acc = roundTo2(
let acc = Misc.roundTo2(
(accuracyStats.correct /
(accuracyStats.correct + accuracyStats.incorrect)) *
100
@ -1672,33 +1661,33 @@ function showResult(difficultyFailed = false) {
clearTimeout(timer);
let testtime = stats.time;
let afkseconds = keypressPerSecond.filter((x) => x.count == 0).length;
let afkSecondsPercent = roundTo2((afkseconds / testtime) * 100);
let afkSecondsPercent = Misc.roundTo2((afkseconds / testtime) * 100);
$("#result #resultWordsHistory").addClass("hidden");
if (config.alwaysShowDecimalPlaces) {
if (config.alwaysShowCPM == false) {
$("#result .stats .wpm .top .text").text("wpm");
$("#result .stats .wpm .bottom").text(roundTo2(stats.wpm));
$("#result .stats .raw .bottom").text(roundTo2(stats.wpmRaw));
$("#result .stats .wpm .bottom").text(Misc.roundTo2(stats.wpm));
$("#result .stats .raw .bottom").text(Misc.roundTo2(stats.wpmRaw));
$("#result .stats .wpm .bottom").attr(
"aria-label",
roundTo2(stats.wpm * 5) + " cpm"
Misc.roundTo2(stats.wpm * 5) + " cpm"
);
} else {
$("#result .stats .wpm .top .text").text("cpm");
$("#result .stats .wpm .bottom").text(roundTo2(stats.wpm * 5));
$("#result .stats .raw .bottom").text(roundTo2(stats.wpmRaw * 5));
$("#result .stats .wpm .bottom").text(Misc.roundTo2(stats.wpm * 5));
$("#result .stats .raw .bottom").text(Misc.roundTo2(stats.wpmRaw * 5));
$("#result .stats .wpm .bottom").attr(
"aria-label",
roundTo2(stats.wpm) + " wpm"
Misc.roundTo2(stats.wpm) + " wpm"
);
}
$("#result .stats .acc .bottom").text(roundTo2(stats.acc) + "%");
let time = roundTo2(testtime) + "s";
$("#result .stats .acc .bottom").text(Misc.roundTo2(stats.acc) + "%");
let time = Misc.roundTo2(testtime) + "s";
if (testtime > 61) {
time = secondsToString(roundTo2(testtime));
time = Misc.secondsToString(Misc.roundTo2(testtime));
}
$("#result .stats .time .bottom .text").text(time);
$("#result .stats .raw .bottom").removeAttr("aria-label");
@ -1713,7 +1702,7 @@ function showResult(difficultyFailed = false) {
$("#result .stats .wpm .top .text").text("wpm");
$("#result .stats .wpm .bottom").attr(
"aria-label",
stats.wpm + ` (${roundTo2(stats.wpm * 5)} cpm)`
stats.wpm + ` (${Misc.roundTo2(stats.wpm * 5)} cpm)`
);
$("#result .stats .wpm .bottom").text(Math.round(stats.wpm));
$("#result .stats .raw .bottom").text(Math.round(stats.wpmRaw));
@ -1722,7 +1711,7 @@ function showResult(difficultyFailed = false) {
$("#result .stats .wpm .top .text").text("cpm");
$("#result .stats .wpm .bottom").attr(
"aria-label",
stats.wpm * 5 + ` (${roundTo2(stats.wpm)} wpm)`
stats.wpm * 5 + ` (${Misc.roundTo2(stats.wpm)} wpm)`
);
$("#result .stats .wpm .bottom").text(Math.round(stats.wpm * 5));
$("#result .stats .raw .bottom").text(Math.round(stats.wpmRaw * 5));
@ -1733,12 +1722,12 @@ function showResult(difficultyFailed = false) {
$("#result .stats .acc .bottom").attr("aria-label", stats.acc + "%");
let time = Math.round(testtime) + "s";
if (testtime > 61) {
time = secondsToString(Math.round(testtime));
time = Misc.secondsToString(Math.round(testtime));
}
$("#result .stats .time .bottom .text").text(time);
$("#result .stats .time .bottom").attr(
"aria-label",
`${roundTo2(testtime)}s (${afkseconds}s afk ${afkSecondsPercent}%)`
`${Misc.roundTo2(testtime)}s (${afkseconds}s afk ${afkSecondsPercent}%)`
);
}
$("#result .stats .time .bottom .afk").text("");
@ -1803,7 +1792,7 @@ function showResult(difficultyFailed = false) {
let labels = [];
for (let i = 1; i <= wpmHistory.length; i++) {
if (lastSecondNotRound && i === wpmHistory.length) {
labels.push(roundTo2(testtime).toString());
labels.push(Misc.roundTo2(testtime).toString());
} else {
labels.push(i.toString());
}
@ -1832,15 +1821,16 @@ function showResult(difficultyFailed = false) {
Math.round((f.count / 5) * 60)
);
let rawWpmPerSecond = smooth(rawWpmPerSecondRaw, 1);
let rawWpmPerSecond = Misc.smooth(rawWpmPerSecondRaw, 1);
let stddev = stdDev(rawWpmPerSecondRaw);
let avg = mean(rawWpmPerSecondRaw);
let stddev = Misc.stdDev(rawWpmPerSecondRaw);
let avg = Misc.mean(rawWpmPerSecondRaw);
let consistency = roundTo2(kogasa(stddev / avg));
let keyConsistency = roundTo2(
kogasa(
stdDev(keypressStats.spacing.array) / mean(keypressStats.spacing.array)
let consistency = Misc.roundTo2(Misc.kogasa(stddev / avg));
let keyConsistency = Misc.roundTo2(
Misc.kogasa(
Misc.stdDev(keypressStats.spacing.array) /
Misc.mean(keypressStats.spacing.array)
)
);
@ -1849,7 +1839,9 @@ function showResult(difficultyFailed = false) {
}
if (config.alwaysShowDecimalPlaces) {
$("#result .stats .consistency .bottom").text(roundTo2(consistency) + "%");
$("#result .stats .consistency .bottom").text(
Misc.roundTo2(consistency) + "%"
);
$("#result .stats .consistency .bottom").attr(
"aria-label",
`${keyConsistency}% key`
@ -1925,11 +1917,11 @@ function showResult(difficultyFailed = false) {
if (bailout) afkDetected = false;
if (difficultyFailed) {
showNotification("Test failed", 2000);
Misc.showNotification("Test failed", 2000);
} else if (afkDetected) {
showNotification("Test invalid - AFK detected", 2000);
Misc.showNotification("Test invalid - AFK detected", 2000);
} else if (sameWordset) {
showNotification("Test invalid - repeated", 2000);
Misc.showNotification("Test invalid - repeated", 2000);
} else {
let activeTags = [];
try {
@ -2035,7 +2027,7 @@ function showResult(difficultyFailed = false) {
showCrown();
$("#result .stats .wpm .crown").attr(
"aria-label",
"+" + roundTo2(pbDiff)
"+" + Misc.roundTo2(pbDiff)
);
}
localPb = true;
@ -2057,39 +2049,39 @@ function showResult(difficultyFailed = false) {
}
$("#result .stats .leaderboards").removeClass("hidden");
$("#result .stats .leaderboards .bottom").html("checking...");
testCompleted({
CloudFunctions.testCompleted({
uid: firebase.auth().currentUser.uid,
obj: completedEvent,
})
.then((e) => {
accountIconLoading(false);
if (e.data == null) {
showNotification(
Misc.showNotification(
"Unexpected response from the server.",
4000
);
return;
}
if (e.data.resultCode === -1) {
showNotification("Could not save result", 3000);
Misc.showNotification("Could not save result", 3000);
} else if (e.data.resultCode === -2) {
showNotification(
Misc.showNotification(
"Possible bot detected. Result not saved.",
4000
);
} else if (e.data.resultCode === -3) {
showNotification(
Misc.showNotification(
"Could not verify keypress stats. Result not saved.",
4000
);
} else if (e.data.resultCode === -4) {
showNotification(
Misc.showNotification(
"Result data does not make sense. Result not saved.",
4000
);
} else if (e.data.resultCode === -999) {
console.error("internal error: " + e.data.message);
showNotification(
Misc.showNotification(
"Internal error. Result might not be saved. " +
e.data.message,
6000
@ -2170,7 +2162,7 @@ function showResult(difficultyFailed = false) {
"global",
glb.insertedAt
);
let str = getPositionString(glb.insertedAt + 1);
let str = Misc.getPositionString(glb.insertedAt + 1);
globalLbString = `global: ${str}`;
} else {
globalLbDiff = glbMemory - glb.foundAt;
@ -2180,7 +2172,7 @@ function showResult(difficultyFailed = false) {
"global",
glb.foundAt
);
let str = getPositionString(glb.foundAt + 1);
let str = Misc.getPositionString(glb.foundAt + 1);
globalLbString = `global: ${str}`;
}
}
@ -2226,7 +2218,7 @@ function showResult(difficultyFailed = false) {
"daily",
dlb.insertedAt
);
let str = getPositionString(dlb.insertedAt + 1);
let str = Misc.getPositionString(dlb.insertedAt + 1);
dailyLbString = `daily: ${str}`;
} else {
dailyLbDiff = dlbMemory - dlb.foundAt;
@ -2236,7 +2228,7 @@ function showResult(difficultyFailed = false) {
"daily",
dlb.foundAt
);
let str = getPositionString(dlb.foundAt + 1);
let str = Misc.getPositionString(dlb.foundAt + 1);
dailyLbString = `daily: ${str}`;
}
}
@ -2255,13 +2247,13 @@ function showResult(difficultyFailed = false) {
globalLbString + "<br>" + dailyLbString
);
saveLbMemory({
CloudFunctions.saveLbMemory({
uid: firebase.auth().currentUser.uid,
obj: db_getSnapshot().lbMemory,
}).then((d) => {
if (d.data.returnCode === 1) {
} else {
showNotification(
Misc.showNotification(
`Error saving lb memory ${d.data.message}`,
4000
);
@ -2311,7 +2303,7 @@ function showResult(difficultyFailed = false) {
);
} else if (e.data.resultCode === 1) {
if (localPb) {
showNotification(
Misc.showNotification(
"Local PB data is out of sync! Refresh the page to resync it or contact Miodec on Discord.",
15000
);
@ -2321,7 +2313,7 @@ function showResult(difficultyFailed = false) {
})
.catch((e) => {
console.error(e);
showNotification("Could not save result. " + e, 5000);
Misc.showNotification("Could not save result. " + e, 5000);
});
});
});
@ -2334,7 +2326,7 @@ function showResult(difficultyFailed = false) {
notSignedInLastResult = completedEvent;
}
} else {
showNotification("Test invalid", 3000);
Misc.showNotification("Test invalid", 3000);
testInvalid = true;
try {
firebase.analytics().logEvent("testCompletedInvalid", completedEvent);
@ -2541,23 +2533,23 @@ function startTest() {
time == Math.floor(config.time / 3) - 3 ||
time == (config.time / 3) * 2 - 3
) {
showNotification("3", 1000);
Misc.showNotification("3", 1000);
}
if (
time == Math.floor(config.time / 3) - 2 ||
time == Math.floor(config.time / 3) * 2 - 2
) {
showNotification("2", 1000);
Misc.showNotification("2", 1000);
}
if (
time == Math.floor(config.time / 3) - 1 ||
time == Math.floor(config.time / 3) * 2 - 1
) {
showNotification("1", 1000);
Misc.showNotification("1", 1000);
}
if (config.layout !== layouts[index] && layouts[index] !== undefined) {
showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
Misc.showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
}
setLayout(layouts[index]);
setKeymapLayout(layouts[index]);
@ -2618,7 +2610,7 @@ function restartTest(withSameWordset = false, nosave = false) {
customText.length < 1000)
) {
} else {
showNotification(
Misc.showNotification(
"Restart disabled for long tests. Use your mouse to confirm.",
4000
);
@ -2627,7 +2619,7 @@ function restartTest(withSameWordset = false, nosave = false) {
}
if (modeBeforePractise !== null && !withSameWordset) {
showNotification("Reverting to previous settings.", 1500);
Misc.showNotification("Reverting to previous settings.", 1500);
setMode(modeBeforePractise);
modeBeforePractise = null;
}
@ -2688,7 +2680,7 @@ function restartTest(withSameWordset = false, nosave = false) {
!config.customTheme
) {
randomiseTheme();
showNotification(config.theme.replace(/_/g, " "), 1500);
Misc.showNotification(config.theme.replace(/_/g, " "), 1500);
}
}
resultVisible = false;
@ -2774,7 +2766,10 @@ function setCustomText() {
customText = customText.replace(/ +/gm, " ");
customText = customText.split(" ");
if (customText.length >= 10000) {
showNotification("Custom text cannot be longer than 10000 words.", 4000);
Misc.showNotification(
"Custom text cannot be longer than 10000 words.",
4000
);
setMode("time");
customText = "The quick brown fox jumped over the lazy dog".split(" ");
}
@ -2872,7 +2867,7 @@ function changePage(page) {
function setMode(mode, nosave) {
if (mode !== "words" && activeFunBox === "memory") {
showNotification("Memory funbox can only be used with words mode.");
Misc.showNotification("Memory funbox can only be used with words mode.");
return;
}
@ -3289,14 +3284,6 @@ function hideEditTags() {
}
}
function showBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeIn(125);
}
function hideBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeOut(125);
}
function updateTestModesNotice() {
let anim = false;
if ($(".pageTest #testModesNotice").text() === "") anim = true;
@ -3437,29 +3424,30 @@ function tagsEdit() {
hideEditTags();
if (action === "add") {
showBackgroundLoader();
addTag({ uid: firebase.auth().currentUser.uid, name: inputVal }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag added", 2000);
db_getSnapshot().tags.push({
name: inputVal,
id: e.data.id,
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
showNotification("Invalid tag name", 3000);
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
CloudFunctions.addTag({
uid: firebase.auth().currentUser.uid,
name: inputVal,
}).then((e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
Misc.showNotification("Tag added", 2000);
db_getSnapshot().tags.push({
name: inputVal,
id: e.data.id,
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
Misc.showNotification("Invalid tag name", 3000);
} else if (status < -1) {
Misc.showNotification("Unknown error", 3000);
}
);
});
} else if (action === "edit") {
showBackgroundLoader();
editTag({
CloudFunctions.editTag({
uid: firebase.auth().currentUser.uid,
name: inputVal,
tagid: tagid,
@ -3467,7 +3455,7 @@ function tagsEdit() {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag updated", 2000);
Misc.showNotification("Tag updated", 2000);
db_getSnapshot().tags.forEach((tag) => {
if (tag.id === tagid) {
tag.name = inputVal;
@ -3477,32 +3465,33 @@ function tagsEdit() {
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
showNotification("Invalid tag name", 3000);
Misc.showNotification("Invalid tag name", 3000);
} else if (status < -1) {
showNotification("Unknown error", 3000);
Misc.showNotification("Unknown error", 3000);
}
});
} else if (action === "remove") {
showBackgroundLoader();
removeTag({ uid: firebase.auth().currentUser.uid, tagid: tagid }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag removed", 2000);
db_getSnapshot().tags.forEach((tag, index) => {
if (tag.id === tagid) {
db_getSnapshot().tags.splice(index, 1);
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
CloudFunctions.removeTag({
uid: firebase.auth().currentUser.uid,
tagid: tagid,
}).then((e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
Misc.showNotification("Tag removed", 2000);
db_getSnapshot().tags.forEach((tag, index) => {
if (tag.id === tagid) {
db_getSnapshot().tags.splice(index, 1);
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status < -1) {
Misc.showNotification("Unknown error", 3000);
}
);
});
}
}
@ -3891,15 +3880,15 @@ function applyMode2Popup() {
manualRestart = true;
restartTest();
if (val >= 1800) {
showNotification("Stay safe and take breaks!", 3000);
Misc.showNotification("Stay safe and take breaks!", 3000);
} else if (val == 0) {
showNotification(
Misc.showNotification(
"Infinite time! Make sure to use Bail Out from the command line to save your result.",
5000
);
}
} else {
showNotification("Custom time must be at least 1", 3000);
Misc.showNotification("Custom time must be at least 1", 3000);
}
} else if (mode == "words") {
if (val !== null && !isNaN(val) && val >= 0) {
@ -3907,15 +3896,15 @@ function applyMode2Popup() {
manualRestart = true;
restartTest();
if (val > 2000) {
showNotification("Stay safe and take breaks!", 3000);
Misc.showNotification("Stay safe and take breaks!", 3000);
} else if (val == 0) {
showNotification(
Misc.showNotification(
"Infinite words! Make sure to use Bail Out from the command line to save your result.",
5000
);
}
} else {
showNotification("Custom word amount must be at least 1", 3000);
Misc.showNotification("Custom word amount must be at least 1", 3000);
}
}
@ -4029,13 +4018,13 @@ $(document).on("keypress", "#restartTestButton", (event) => {
) {
if (testActive) {
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
restartTest();
} else {
showNotification("Quick restart disabled for long tests", 2000);
Misc.showNotification("Quick restart disabled for long tests", 2000);
}
}
});
@ -4068,7 +4057,7 @@ $(document).on("keypress", "#practiseMissedWordsButton", (event) => {
if (Object.keys(missedWords).length > 0) {
initPractiseMissedWords();
} else {
showNotification("You haven't missed any words.", 2000);
Misc.showNotification("You haven't missed any words.", 2000);
}
}
});
@ -4077,7 +4066,7 @@ $(document.body).on("click", "#practiseMissedWordsButton", (event) => {
if (Object.keys(missedWords).length > 0) {
initPractiseMissedWords();
} else {
showNotification("You haven't missed any words.", 2000);
Misc.showNotification("You haven't missed any words.", 2000);
}
});
@ -4229,13 +4218,13 @@ $(document).keydown((event) => {
) {
if (testActive) {
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
restartTest();
} else {
showNotification("Quick restart disabled for long tests", 2000);
Misc.showNotification("Quick restart disabled for long tests", 2000);
}
} else {
changePage("test");
@ -4393,7 +4382,7 @@ $(document).keydown((event) => {
let outof = wordsList.length;
index = Math.floor((inputHistory.length + 1) / (outof / 3));
if (config.layout !== layouts[index] && layouts[index] !== undefined) {
showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
Misc.showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
}
setLayout(layouts[index]);
setKeymapLayout(layouts[index]);
@ -4457,7 +4446,7 @@ $(document).keydown((event) => {
lastSecondNotRound = true;
showResult(true);
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
return;
@ -4476,7 +4465,7 @@ $(document).keydown((event) => {
lastSecondNotRound = true;
showResult(true);
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
return;
@ -4667,7 +4656,7 @@ $(document).keydown(function (event) {
lastSecondNotRound = true;
showResult(true);
let testNow = performance.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
let testSeconds = Misc.roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
return;
@ -4764,7 +4753,7 @@ if (firebase.app().options.projectId === "monkey-type-dev-67af4") {
if (window.location.hostname === "localhost") {
window.onerror = function (error) {
this.showNotification(error, 3000);
Misc.showNotification(error, 3000);
};
$("#top .logo .top").text("localhost");
$("head title").text($("head title").text() + " (localhost)");
@ -4776,7 +4765,7 @@ if (window.location.hostname === "localhost") {
manualRestart = true;
loadConfigFromCookie();
getReleasesFromGitHub();
Misc.getReleasesFromGitHub();
// getPatreonNames();
$(document).on("mouseenter", "#resultWordsHistory .words .word", (e) => {
@ -4848,9 +4837,9 @@ $(".pageTest #copyWordsListButton").click(async (event) => {
await navigator.clipboard.writeText(
wordsList.slice(0, inputHistory.length).join(" ")
);
showNotification("Copied to clipboard", 1000);
Misc.showNotification("Copied to clipboard", 1000);
} catch (e) {
showNotification("Could not copy to clipboard: " + e, 5000);
Misc.showNotification("Could not copy to clipboard: " + e, 5000);
}
});

View file

@ -261,7 +261,7 @@ async function fillSettingsPage() {
refreshThemeButtons();
let langEl = $(".pageSettings .section.language .buttons").empty();
getLanguageList().then((languages) => {
Misc.getLanguageList().then((languages) => {
languages.forEach((language) => {
langEl.append(
`<div class="language button" language='${language}'>${language.replace(
@ -299,7 +299,7 @@ async function fillSettingsPage() {
let funboxEl = $(".pageSettings .section.funbox .buttons").empty();
funboxEl.append(`<div class="funbox button" funbox='none'>none</div>`);
getFunboxList().then((funboxModes) => {
Misc.getFunboxList().then((funboxModes) => {
funboxModes.forEach((funbox) => {
if (funbox.name === "mirror") {
funboxEl.append(
@ -325,7 +325,7 @@ async function fillSettingsPage() {
});
let fontsEl = $(".pageSettings .section.fontFamily .buttons").empty();
getFontsList().then((fonts) => {
Misc.getFontsList().then((fonts) => {
fonts.forEach((font) => {
fontsEl.append(
`<div class="button" style="font-family:${
@ -350,7 +350,7 @@ function refreshThemeButtons() {
activeThemeName = randomTheme;
}
getSortedThemesList().then((themes) => {
Misc.getSortedThemesList().then((themes) => {
//first show favourites
if (config.favThemes.length > 0) {
favThemesEl.css({ paddingBottom: "1rem" });
@ -456,7 +456,7 @@ function hideCustomThemeShare() {
$("#customThemeShareWrapper input").val()
);
} catch (e) {
showNotification(
Misc.showNotification(
"Something went wrong. Reverting to default custom colors.",
3000
);
@ -503,13 +503,14 @@ $("#shareCustomThemeButton").click((e) => {
);
let url =
"https://monkeytype.com?" + objectToQueryString({ customTheme: share });
"https://monkeytype.com?" +
Misc.objectToQueryString({ customTheme: share });
navigator.clipboard.writeText(url).then(
function () {
showNotification("URL Copied to clipboard", 2000);
Misc.showNotification("URL Copied to clipboard", 2000);
},
function (err) {
showNotification(
Misc.showNotification(
"Something went wrong when copying the URL: " + err,
5000
);
@ -715,7 +716,7 @@ $(
".pageSettings .section.discordIntegration .buttons .generateCodeButton"
).click((e) => {
showBackgroundLoader();
generatePairingCode({ uid: firebase.auth().currentUser.uid })
CloudFunctions.generatePairingCode({ uid: firebase.auth().currentUser.uid })
.then((ret) => {
hideBackgroundLoader();
if (ret.data.status === 1 || ret.data.status === 2) {
@ -731,7 +732,7 @@ $(
})
.catch((e) => {
hideBackgroundLoader();
showNotification("Something went wrong. Error: " + e.message, 4000);
Misc.showNotification("Something went wrong. Error: " + e.message, 4000);
});
});
@ -739,15 +740,20 @@ $(".pageSettings .section.discordIntegration #unlinkDiscordButton").click(
(e) => {
if (confirm("Are you sure?")) {
showBackgroundLoader();
unlinkDiscord({ uid: firebase.auth().currentUser.uid }).then((ret) => {
CloudFunctions.unlinkDiscord({
uid: firebase.auth().currentUser.uid,
}).then((ret) => {
hideBackgroundLoader();
console.log(ret);
if (ret.data.status === 1) {
db_getSnapshot().discordId = null;
showNotification("Accounts unlinked", 2000);
Misc.showNotification("Accounts unlinked", 2000);
updateDiscordSettingsSection();
} else {
showNotification("Something went wrong: " + ret.data.message, 5000);
Misc.showNotification(
"Something went wrong: " + ret.data.message,
5000
);
updateDiscordSettingsSection();
}
});
@ -857,7 +863,7 @@ $(".pageSettings .saveCustomThemeButton").click((e) => {
}
);
setCustomThemeColors(save);
showNotification("Custom theme colors saved", 1000);
Misc.showNotification("Custom theme colors saved", 1000);
});
$(".pageSettings #loadCustomColorsFromPreset").click((e) => {
@ -909,10 +915,10 @@ $("#exportSettingsButton").click((e) => {
let configJSON = JSON.stringify(config);
navigator.clipboard.writeText(configJSON).then(
function () {
showNotification("JSON Copied to clipboard", 2000);
Misc.showNotification("JSON Copied to clipboard", 2000);
},
function (err) {
showNotification(
Misc.showNotification(
"Something went wrong when copying the settings JSON: " + err,
5000
);
@ -940,7 +946,7 @@ function hideSettingsImport() {
try {
applyConfig(JSON.parse($("#settingsImportWrapper input").val()));
} catch (e) {
showNotification(
Misc.showNotification(
"An error occured while importing settings: " + e,
5000
);

165
src/js/simple-popups.js Normal file
View file

@ -0,0 +1,165 @@
let simplePopups = {};
class SimplePopup {
constructor(
id,
type,
title,
inputs = [],
text = "",
buttonText = "Confirm",
execFn
) {
this.id = id;
this.type = type;
this.execFn = execFn;
this.title = title;
this.inputs = inputs;
this.text = text;
this.wrapper = $("#simplePopupWrapper");
this.element = $("#simplePopup");
this.buttonText = buttonText;
}
reset() {
this.element.html(`
<div class="title"></div>
<form class="inputs"></form>
<div class="text"></div>
<div class="button"></div>`);
}
init() {
let el = this.element;
el.find("input").val("");
if (el.attr("popupId") !== this.id) {
this.reset();
el.attr("popupId", this.id);
el.find(".title").text(this.title);
el.find(".text").text(this.text);
this.initInputs();
el.find(".button").text(this.buttonText);
}
}
initInputs() {
let el = this.element;
if (this.inputs.length > 0) {
if (this.type === "number") {
this.inputs.forEach((input) => {
el.find(".inputs").append(`
<input type="number" min="1" val="${input.initVal}" placeholder="${input.placeholder}" required>
`);
});
} else if (this.type === "text") {
this.inputs.forEach((input) => {
el.find(".inputs").append(`
<input type="text" val="${input.initVal}" placeholder="${input.placeholder}" required>
`);
});
}
el.find(".inputs").removeClass("hidden");
} else {
el.find(".inputs").addClass("hidden");
}
}
exec() {
let vals = [];
$.each($("#simplePopup input"), (index, el) => {
vals.push($(el).val());
});
this.execFn(...vals);
this.hide();
}
show() {
this.init();
this.wrapper
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 125, () => {
$($("#simplePopup").find("input")[0]).focus();
});
}
hide() {
this.wrapper
.stop(true, true)
.css("opacity", 1)
.removeClass("hidden")
.animate({ opacity: 0 }, 125, () => {
this.wrapper.addClass("hidden");
});
}
}
$("#simplePopupWrapper").click((e) => {
if ($(e.target).attr("id") === "simplePopupWrapper") {
$("#simplePopupWrapper")
.stop(true, true)
.css("opacity", 1)
.removeClass("hidden")
.animate({ opacity: 0 }, 125, () => {
$("#simplePopupWrapper").addClass("hidden");
});
}
});
$(document).on("click", "#simplePopupWrapper .button", (e) => {
let id = $("#simplePopup").attr("popupId");
simplePopups[id].exec();
});
$(document).on("keyup", "#simplePopupWrapper input", (e) => {
if (e.key === "Enter") {
let id = $("#simplePopup").attr("popupId");
simplePopups[id].exec();
}
});
simplePopups.updateEmail = new SimplePopup(
"updateEmail",
"text",
"Update Email",
[
{
placeholder: "Current email",
initVal: "",
},
{
placeholder: "New email",
initVal: "",
},
],
"Don't mess this one up or you won't be able to login!",
"Update",
(previousEmail, newEmail) => {
try {
showBackgroundLoader();
CloudFunctions.updateEmail({
uid: firebase.auth().currentUser.uid,
previousEmail: previousEmail,
newEmail: newEmail,
}).then((data) => {
hideBackgroundLoader();
if (data.data.resultCode === 1) {
Misc.showNotification("Email updated", 2000);
setTimeout(() => {
signOut();
}, 1000);
} else if (data.data.resultCode === -1) {
Misc.showNotification("Current email doesn't match", 2000);
} else {
Misc.showNotification(
"Something went wrong: " + JSON.stringify(data.data),
7000
);
}
});
} catch (e) {
Misc.showNotification("Something went wrong: " + e, 5000);
}
}
);

View file

@ -93,7 +93,7 @@ async function saveConfigToCookie(noDbCheck = false) {
// expires: d,
// path: "/",
// });
setCookie("config", JSON.stringify(config), 365);
Misc.setCookie("config", JSON.stringify(config), 365);
restartCount = 0;
if (!noDbCheck) await saveConfigToDB();
}
@ -101,19 +101,20 @@ async function saveConfigToCookie(noDbCheck = false) {
async function saveConfigToDB() {
if (firebase.auth().currentUser !== null) {
accountIconLoading(true);
saveConfig({ uid: firebase.auth().currentUser.uid, obj: config }).then(
(d) => {
accountIconLoading(false);
if (d.data.returnCode === 1) {
} else {
showNotification(
`Error saving config to DB! ${d.data.message}`,
4000
);
}
return;
CloudFunctions.saveConfig({
uid: firebase.auth().currentUser.uid,
obj: config,
}).then((d) => {
accountIconLoading(false);
if (d.data.returnCode === 1) {
} else {
Misc.showNotification(
`Error saving config to DB! ${d.data.message}`,
4000
);
}
);
return;
});
}
}
@ -141,14 +142,14 @@ function saveActiveTagsToCookie() {
// expires: d,
// path: "/",
// });
setCookie("activeTags", JSON.stringify(tags), 365);
Misc.setCookie("activeTags", JSON.stringify(tags), 365);
} catch (e) {}
}
function loadConfigFromCookie() {
console.log("loading cookie config");
// let newConfig = $.cookie("config");
let newConfig = getCookie("config");
let newConfig = Misc.getCookie("config");
if (newConfig !== undefined && newConfig !== "") {
try {
newConfig = JSON.parse(newConfig);
@ -294,7 +295,7 @@ function applyConfig(configObj) {
function loadActiveTagsFromCookie() {
// let newTags = $.cookie("activeTags");
let newTags = getCookie("activeTags");
let newTags = Misc.getCookie("activeTags");
if (newTags !== undefined && newTags !== "") {
try {
newTags = JSON.parse(newTags);
@ -1144,7 +1145,7 @@ function setTheme(name, nosave) {
let randomTheme = null;
function randomiseTheme() {
var randomList = themesList.map((t) => {
var randomList = Misc.getThemesList().map((t) => {
return t.name;
});
if (config.randomTheme === "fav" && config.favThemes.length > 0)