diff --git a/.firebaserc_example b/.firebaserc_example new file mode 100644 index 000000000..0de16a603 --- /dev/null +++ b/.firebaserc_example @@ -0,0 +1,5 @@ + { + "projects": { + "default": "your-firebase-project-id" + } + } diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 94a467522..1fe9cd7b1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,4 +1,4 @@ -Adding a language or a theme? Make sure to edit the `list.json` file as well, otherwise, it will not work! +Adding a language or a theme? Make sure to edit the `_list.json` file as well, otherwise, it will not work! Please reference any issues related to your pull request. diff --git a/.prettierignore b/.prettierignore index f568baa07..44e1ccc46 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,10 +1,10 @@ *.min.js layouts.js -english_quotes.json +quotes/english.json chartjs-plugin-*.js sound/* node_modules css/balloon.css css/fa.css css/style.min.css -list.json \ No newline at end of file +_list.json diff --git a/functions/index.js b/functions/index.js index a037df129..38539a0b8 100644 --- a/functions/index.js +++ b/functions/index.js @@ -1,9 +1,11 @@ const functions = require("firebase-functions"); const admin = require("firebase-admin"); let key = "./serviceAccountKey.json"; +let origin = "http://localhost:5000"; if (process.env.GCLOUD_PROJECT === "monkey-type") { key = "./serviceAccountKey_live.json"; + origin = "https://monkeytype.com"; } var serviceAccount = require(key); @@ -133,14 +135,36 @@ exports.clearName = functions.auth.user().onDelete((user) => { db.collection("users").doc(user.uid).delete(); }); -exports.checkNameAvailability = functions.https.onCall( +exports.checkNameAvailability = functions.https.onRequest( async (request, response) => { + response.set("Access-Control-Allow-Origin", origin); + if (request.method === "OPTIONS") { + // Send response to OPTIONS requests + response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); + response.set( + "Access-Control-Allow-Headers", + "Authorization,Content-Type" + ); + response.set("Access-Control-Max-Age", "3600"); + response.status(204).send(""); + return; + } + request = request.body.data; + // 1 - available // -1 - unavailable (taken) // -2 - not valid name // -999 - unknown error try { - if (!isUsernameValid(request.name)) return -2; + if (!isUsernameValid(request.name)) { + response.status(200).send({ + data: { + resultCode: -2, + message: "Username is not valid", + }, + }); + return; + } let takendata = await db .collection("takenNames") @@ -150,9 +174,21 @@ exports.checkNameAvailability = functions.https.onCall( takendata = takendata.data(); if (takendata !== undefined && takendata.taken) { - return -1; + response.status(200).send({ + data: { + resultCode: -1, + message: "Username is taken", + }, + }); + return; } else { - return 1; + response.status(200).send({ + data: { + resultCode: 1, + message: "Username is available", + }, + }); + return; } // return getAllNames().then((data) => { @@ -167,8 +203,17 @@ exports.checkNameAvailability = functions.https.onCall( // return available; // }); } catch (e) { - console.log(e.message); - return -999; + console.error( + `Error while checking name availability for ${request.name}:` + + e.message + ); + response.status(200).send({ + data: { + resultCode: -999, + message: "Unexpected error: " + e, + }, + }); + return; } } ); @@ -456,7 +501,7 @@ function checkIfPB(uid, obj, userdata) { } } -async function checkIfTagPB(uid, obj) { +async function checkIfTagPB(uid, obj, userdata) { if (obj.tags.length === 0) { return []; } @@ -471,24 +516,152 @@ async function checkIfTagPB(uid, obj) { dbtags.push(data); } }); - } catch (e) { + } catch { return []; } - let wpm = obj.wpm; + let ret = []; for (let i = 0; i < dbtags.length; i++) { - let dbtag = dbtags[i]; - if (dbtag.pb === undefined || dbtag.pb < wpm) { - //no pb found, meaning this one is a pb - await db.collection(`users/${uid}/tags`).doc(dbtag.id).update({ - pb: wpm, + let pbs = null; + try { + pbs = dbtags[i].personalBests; + if (pbs === undefined) { + throw new Error("pb is undefined"); + } + } catch (e) { + //undefined personal best = new personal best + db.collection(`users/${uid}/tags`) + .doc(dbtags[i].id) + .set( + { + personalBests: { + [obj.mode]: { + [obj.mode2]: [ + { + language: obj.language, + difficulty: obj.difficulty, + punctuation: obj.punctuation, + wpm: obj.wpm, + acc: obj.acc, + raw: obj.rawWpm, + timestamp: Date.now(), + consistency: obj.consistency, + }, + ], + }, + }, + }, + { merge: true } + ) + .then((e) => { + ret.push(dbtags[i].id); + }); + continue; + } + let toUpdate = false; + let found = false; + try { + if (pbs[obj.mode][obj.mode2] === undefined) { + pbs[obj.mode][obj.mode2] = []; + } + pbs[obj.mode][obj.mode2].forEach((pb) => { + if ( + pb.punctuation === obj.punctuation && + pb.difficulty === obj.difficulty && + pb.language === obj.language + ) { + //entry like this already exists, compare wpm + found = true; + if (pb.wpm < obj.wpm) { + //new pb + pb.wpm = obj.wpm; + pb.acc = obj.acc; + pb.raw = obj.rawWpm; + pb.timestamp = Date.now(); + pb.consistency = obj.consistency; + toUpdate = true; + } else { + //no pb + return false; + } + } }); - ret.push(dbtag.id); + //checked all pbs, nothing found - meaning this is a new pb + if (!found) { + pbs[obj.mode][obj.mode2].push({ + language: obj.language, + difficulty: obj.difficulty, + punctuation: obj.punctuation, + wpm: obj.wpm, + acc: obj.acc, + raw: obj.rawWpm, + timestamp: Date.now(), + consistency: obj.consistency, + }); + toUpdate = true; + } + } catch (e) { + // console.log(e); + pbs[obj.mode] = {}; + pbs[obj.mode][obj.mode2] = [ + { + language: obj.language, + difficulty: obj.difficulty, + punctuation: obj.punctuation, + wpm: obj.wpm, + acc: obj.acc, + raw: obj.rawWpm, + timestamp: Date.now(), + consistency: obj.consistency, + }, + ]; + toUpdate = true; + } + + if (toUpdate) { + db.collection(`users/${uid}/tags`) + .doc(dbtags[i].id) + .update({ personalBests: pbs }); + ret.push(dbtags[i].id); } } return ret; } +//old +// async function checkIfTagPB(uid, obj) { +// if (obj.tags.length === 0) { +// return []; +// } +// let dbtags = []; +// let restags = obj.tags; +// try { +// let snap = await db.collection(`users/${uid}/tags`).get(); +// snap.forEach((doc) => { +// if (restags.includes(doc.id)) { +// let data = doc.data(); +// data.id = doc.id; +// dbtags.push(data); +// } +// }); +// } catch (e) { +// return []; +// } +// let wpm = obj.wpm; +// let ret = []; +// for (let i = 0; i < dbtags.length; i++) { +// let dbtag = dbtags[i]; +// if (dbtag.pb === undefined || dbtag.pb < wpm) { +// //no pb found, meaning this one is a pb +// await db.collection(`users/${uid}/tags`).doc(dbtag.id).update({ +// pb: wpm, +// }); +// ret.push(dbtag.id); +// } +// } +// return ret; +// } + exports.clearTagPb = functions.https.onCall((request, response) => { try { return db @@ -588,14 +761,14 @@ function validateResult(result) { } exports.requestTest = functions.https.onRequest((request, response) => { - response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Origin", origin); response.set("Access-Control-Allow-Headers", "*"); response.set("Access-Control-Allow-Credentials", "true"); response.status(200).send({ data: "test" }); }); exports.getPatreons = functions.https.onRequest(async (request, response) => { - response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Origin", origin); response.set("Access-Control-Allow-Headers", "*"); response.set("Access-Control-Allow-Credentials", "true"); if (request.method === "OPTIONS") { @@ -629,7 +802,7 @@ exports.getPatreons = functions.https.onRequest(async (request, response) => { }); exports.verifyUser = functions.https.onRequest(async (request, response) => { - response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Origin", origin); response.set("Access-Control-Allow-Headers", "*"); response.set("Access-Control-Allow-Credentials", "true"); if (request.method === "OPTIONS") { @@ -1002,7 +1175,7 @@ async function incrementTimeSpentTyping(uid, res, userData) { } exports.testCompleted = functions.https.onRequest(async (request, response) => { - response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Origin", origin); if (request.method === "OPTIONS") { // Send response to OPTIONS requests response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); @@ -1055,7 +1228,13 @@ exports.testCompleted = functions.https.onRequest(async (request, response) => { return; } - if (obj.wpm <= 0 || obj.wpm > 350 || obj.acc < 50 || obj.acc > 100) { + if ( + obj.wpm <= 0 || + obj.wpm > 350 || + obj.acc < 50 || + obj.acc > 100 || + obj.consistency > 100 + ) { response.status(200).send({ data: { resultCode: -1 } }); return; } @@ -1426,12 +1605,12 @@ exports.addTag = functions.https.onCall((request, response) => { console.error( `error while creating tag for user ${request.uid}: ${e.message}` ); - return { resultCode: -999 }; + return { resultCode: -999, message: e.message }; }); } } catch (e) { console.error(`error adding tag for ${request.uid} - ${e}`); - return { resultCode: -999 }; + return { resultCode: -999, message: e.message }; } }); @@ -1456,12 +1635,12 @@ exports.editTag = functions.https.onCall((request, response) => { console.error( `error while updating tag for user ${request.uid}: ${e.message}` ); - return { resultCode: -999 }; + return { resultCode: -999, message: e.message }; }); } } catch (e) { console.error(`error updating tag for ${request.uid} - ${e}`); - return { resultCode: -999 }; + return { resultCode: -999, message: e.message }; } }); @@ -1522,7 +1701,7 @@ exports.updateResultTags = functions.https.onCall((request, response) => { } } catch (e) { console.error(`error updating tags by ${request.uid} - ${e}`); - return { resultCode: -999 }; + return { resultCode: -999, message: e }; } }); @@ -1984,7 +2163,7 @@ class Leaderboard { // }); exports.unlinkDiscord = functions.https.onRequest((request, response) => { - response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Origin", origin); if (request.method === "OPTIONS") { // Send response to OPTIONS requests response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); diff --git a/gulpfile.js b/gulpfile.js index e4f1bda03..e73ad8398 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -93,6 +93,7 @@ const refactoredSrc = [ "./src/js/layouts.js", "./src/js/monkey.js", "./src/js/result-filters.js", + "./src/js/notification-center.js", ]; //legacy files diff --git a/src/js/account.js b/src/js/account.js index 997d40c89..c646a1ff9 100644 --- a/src/js/account.js +++ b/src/js/account.js @@ -24,7 +24,7 @@ function signIn() { changePage("test"); }) .catch(function (error) { - Misc.showNotification(error.message, 5000); + Notifications.add(error.message, -1); $(".pageLogin .preloader").addClass("hidden"); }); }); @@ -41,7 +41,7 @@ function signIn() { changePage("test"); }) .catch(function (error) { - Misc.showNotification(error.message, 5000); + Notifications.add(error.message, -1); $(".pageLogin .preloader").addClass("hidden"); }); }); @@ -59,27 +59,27 @@ function signUp() { let passwordVerify = $(".pageLogin .register input")[3].value; if (password != passwordVerify) { - Misc.showNotification("Passwords do not match", 3000); + 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 === -1) { - Misc.showNotification("Name unavailable", 3000); + if (d.data.resultCode === -1) { + Notifications.add("Name unavailable", -1); $(".pageLogin .preloader").addClass("hidden"); $(".pageLogin .register .button").removeClass("disabled"); return; - } else if (d.data === -2) { - Misc.showNotification( + } else if (d.data.resultCode === -2) { + Notifications.add( "Name cannot contain special characters or contain more than 14 characters. Can include _ . and -", - 8000 + -1 ); $(".pageLogin .preloader").addClass("hidden"); $(".pageLogin .register .button").removeClass("disabled"); return; - } else if (d.data === 1) { + } else if (d.data.resultCode === 1) { firebase .auth() .createUserWithEmailAndPassword(email, password) @@ -106,7 +106,7 @@ function signUp() { ); usr.sendEmailVerification(); clearGlobalStats(); - Misc.showNotification("Account created", 2000); + Notifications.add("Account created", 1, 3); $("#menu .icon-button.account .text").text(nname); try { firebase.analytics().logEvent("accountCreated", usr.uid); @@ -144,15 +144,19 @@ function signUp() { .delete() .then(function () { // User deleted. - Misc.showNotification( - "An error occured. Account not created.", - 2000 + 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); }); }); @@ -160,10 +164,14 @@ function signUp() { .catch(function (error) { // Handle Errors here. $(".pageLogin .register .button").removeClass("disabled"); - var errorMessage = error.message; - Misc.showNotification(errorMessage, 5000); + Notifications.add(error.message, -1); $(".pageLogin .preloader").addClass("hidden"); }); + } else { + Notifications.add( + "Something went wrong when checking name: " + d.data.message, + -1 + ); } }); } @@ -173,7 +181,7 @@ function signOut() { .auth() .signOut() .then(function () { - Misc.showNotification("Signed out", 2000); + Notifications.add("Signed out", 0, 2); clearGlobalStats(); hideAccountSettingsSection(); updateAccountLoginButton(); @@ -181,7 +189,7 @@ function signOut() { db_setSnapshot(null); }) .catch(function (error) { - Misc.showNotification(error.message, 5000); + Notifications.add(error.message, -1); }); } @@ -221,13 +229,15 @@ firebase.auth().onAuthStateChanged(function (user) { $(".pageAccount .group.createdDate").text(text); if (verifyUserWhenLoggedIn !== null) { - Misc.showNotification("Verifying", 1000); + Notifications.add("Verifying", 0, 3); verifyUserWhenLoggedIn.uid = user.uid; CloudFunctions.verifyUser(verifyUserWhenLoggedIn).then((data) => { - Misc.showNotification(data.data.message, 3000); if (data.data.status === 1) { + Notifications.add(data.data.message, 1); db_getSnapshot().discordId = data.data.did; updateDiscordSettingsSection(); + } else { + Notifications.add(data.data.message, -1); } }); } @@ -237,11 +247,11 @@ firebase.auth().onAuthStateChanged(function (user) { try { theme = theme.split(","); config.customThemeColors = theme; - Misc.showNotification("Custom theme applied.", 1000); + Notifications.add("Custom theme applied.", 1); } catch (e) { - Misc.showNotification( + Notifications.add( "Something went wrong. Reverting to default custom colors.", - 3000 + 0 ); config.customThemeColors = defaultConfig.customThemeColors; } @@ -366,9 +376,9 @@ function getAccountDataAndInit() { .catch((e) => { accountIconLoading(false); console.error(e); - Misc.showNotification( - "Error downloading user data. Refresh to try again. If error persists contact Miodec.", - 5000 + Notifications.add( + "Error downloading user data - refresh to try again. Client likely could not connect to the backend, if error persists contact Miodec.", + -1 ); $("#top #menu .account .icon").html(''); $("#top #menu .account").css("opacity", 1); @@ -1004,9 +1014,9 @@ function toggleFilter(group, filter) { ResultFilters.toggleFilter(group, filter); ResultFilters.save(); } catch (e) { - Misc.showNotification( + Notifications.add( "Something went wrong toggling filter. Reverting to defaults", - 3000 + 0 ); console.log("toggling filter error"); console.error(e); @@ -1851,9 +1861,9 @@ function refreshAccountPage() { filteredResults.push(result); } catch (e) { - Misc.showNotification( + Notifications.add( "Something went wrong when filtering. Resetting filters.", - 5000 + 0 ); console.log(result); console.error(e); @@ -2206,7 +2216,7 @@ function refreshAccountPage() { swapElements($(".pageAccount .preloader"), $(".pageAccount .content"), 250); } if (db_getSnapshot() === null) { - Misc.showNotification(`Missing account data. Please refresh.`, 5000); + Notifications.add(`Missing account data. Please refresh.`, -1); $(".pageAccount .preloader").html("Missing account data. Please refresh."); } else if (db_getSnapshot().results === undefined) { db_getUserResults().then((d) => { @@ -2224,7 +2234,7 @@ function refreshAccountPage() { cont(); } catch (e) { console.error(e); - Misc.showNotification(`Something went wrong: ${e}`, 5000); + Notifications.add(`Something went wrong: ${e}`, -1); } } } @@ -2326,7 +2336,7 @@ $("#resultEditTagsPanel .confirmButton").click((f) => { }).then((r) => { hideBackgroundLoader(); if (r.data.resultCode === 1) { - Misc.showNotification("Tags updated.", 3000); + Notifications.add("Tags updated.", 1, 2); db_getSnapshot().results.forEach((result) => { if (result.id === resultid) { result.tags = newtags; @@ -2377,7 +2387,7 @@ $("#resultEditTagsPanel .confirmButton").click((f) => { ); } } else { - Misc.showNotification("Error updating tags", 3000); + Notifications.add("Error updating tags: " + r.data.message, -1); } }); }); @@ -2425,11 +2435,11 @@ $(".pageLogin #forgotPasswordButton").click((e) => { .sendPasswordResetEmail(email) .then(function () { // Email sent. - Misc.showNotification("Email sent", 2000); + Notifications.add("Email sent", 1, 2); }) .catch(function (error) { // An error happened. - Misc.showNotification(error.message, 5000); + Notifications.add(error.message, -1); }); } }); diff --git a/src/js/commandline.js b/src/js/commandline.js index bb5520215..3335b6640 100644 --- a/src/js/commandline.js +++ b/src/js/commandline.js @@ -1,11 +1,15 @@ function canBailOut() { return ( (config.mode === "custom" && - customTextIsRandom && - customTextWordCount >= 5000) || + customText.isWordRandom && + customText.word >= 5000) || (config.mode === "custom" && - !customTextIsRandom && - customText.length >= 5000) || + !customText.isWordRandom && + !customText.isTimeRandom && + customText.text.length >= 5000) || + (config.mode === "custom" && + customText.isTimeRandom && + customText.time >= 3600) || (config.mode === "words" && config.words >= 5000) || config.words === 0 || (config.mode === "time" && (config.time >= 3600 || config.time === 0)) || @@ -885,7 +889,7 @@ let commandsEnableAds = { display: "off", exec: () => { setEnableAds("off"); - Misc.showNotification("Don't forget to refresh the page!", 3000); + Notifications.add("Don't forget to refresh the page!", 0); }, }, { @@ -893,7 +897,7 @@ let commandsEnableAds = { display: "on", exec: () => { setEnableAds("on"); - Misc.showNotification("Don't forget to refresh the page!", 3000); + Notifications.add("Don't forget to refresh the page!", 0); }, }, { @@ -901,7 +905,7 @@ let commandsEnableAds = { display: "Sellout", exec: () => { setEnableAds("max"); - Misc.showNotification("Don't forget to refresh the page!", 3000); + Notifications.add("Don't forget to refresh the page!", 0); }, }, ], diff --git a/src/js/db.js b/src/js/db.js index bdf8d53b6..37be3d0ef 100644 --- a/src/js/db.js +++ b/src/js/db.js @@ -45,6 +45,9 @@ export async function db_getUserSnapshot() { data.docs.forEach((doc) => { let tag = doc.data(); tag.id = doc.id; + if (tag.personalBests === undefined) { + tag.personalBests = {}; + } snap.tags.push(tag); }); snap.tags = snap.tags.sort((a, b) => { @@ -305,14 +308,27 @@ export async function db_saveLocalPB( } } -export async function db_getLocalTagPB(tagId) { +export async function db_getLocalTagPB( + tagId, + mode, + mode2, + punctuation, + language, + difficulty +) { function cont() { let ret = 0; + let filteredtag = dbSnapshot.tags.filter((t) => t.id === tagId)[0]; try { - ret = dbSnapshot.tags.filter((t) => t.id === tagId)[0].pb; - if (ret == undefined) { - ret = 0; - } + filteredtag.personalBests[mode][mode2].forEach((pb) => { + if ( + pb.punctuation == punctuation && + pb.difficulty == difficulty && + pb.language == language + ) { + ret = pb.wpm; + } + }); return ret; } catch (e) { return ret; @@ -320,22 +336,114 @@ export async function db_getLocalTagPB(tagId) { } let retval; - if (dbSnapshot != null) { + if (dbSnapshot == null) { + retval = 0; + } else { retval = cont(); } return retval; } -export async function db_saveLocalTagPB(tagId, wpm) { +export async function db_saveLocalTagPB( + tagId, + mode, + mode2, + punctuation, + language, + difficulty, + wpm, + acc, + raw, + consistency +) { function cont() { - dbSnapshot.tags.forEach((tag) => { - if (tag.id === tagId) { - tag.pb = wpm; + let filteredtag = dbSnapshot.tags.filter((t) => t.id === tagId)[0]; + try { + let found = false; + if (filteredtag.personalBests[mode][mode2] === undefined) { + filteredtag.personalBests[mode][mode2] = []; } - }); + filteredtag.personalBests[mode][mode2].forEach((pb) => { + if ( + pb.punctuation == punctuation && + pb.difficulty == difficulty && + pb.language == language + ) { + found = true; + pb.wpm = wpm; + pb.acc = acc; + pb.raw = raw; + pb.timestamp = Date.now(); + pb.consistency = consistency; + } + }); + if (!found) { + //nothing found + filteredtag.personalBests[mode][mode2].push({ + language: language, + difficulty: difficulty, + punctuation: punctuation, + wpm: wpm, + acc: acc, + raw: raw, + timestamp: Date.now(), + consistency: consistency, + }); + } + } catch (e) { + //that mode or mode2 is not found + filteredtag.personalBests[mode] = {}; + filteredtag.personalBests[mode][mode2] = [ + { + language: language, + difficulty: difficulty, + punctuation: punctuation, + wpm: wpm, + acc: acc, + raw: raw, + timestamp: Date.now(), + consistency: consistency, + }, + ]; + } } if (dbSnapshot != null) { cont(); } } + +// export async function db_getLocalTagPB(tagId) { +// function cont() { +// let ret = 0; +// try { +// ret = dbSnapshot.tags.filter((t) => t.id === tagId)[0].pb; +// if (ret == undefined) { +// ret = 0; +// } +// return ret; +// } catch (e) { +// return ret; +// } +// } + +// let retval; +// if (dbSnapshot != null) { +// retval = cont(); +// } +// return retval; +// } + +// export async function db_saveLocalTagPB(tagId, wpm) { +// function cont() { +// dbSnapshot.tags.forEach((tag) => { +// if (tag.id === tagId) { +// tag.pb = wpm; +// } +// }); +// } + +// if (dbSnapshot != null) { +// cont(); +// } +// } diff --git a/src/js/exports.js b/src/js/exports.js index 8f8082626..369fd5ce6 100644 --- a/src/js/exports.js +++ b/src/js/exports.js @@ -7,3 +7,4 @@ global.sendVerificationEmail = Misc.sendVerificationEmail; //these exports are just for debugging in the browser global.snapshot = db_getSnapshot; global.config = config; +global.addnotif = Notifications.add; diff --git a/src/js/global-dependencies.js b/src/js/global-dependencies.js index dc414488a..2ce2dfd6a 100644 --- a/src/js/global-dependencies.js +++ b/src/js/global-dependencies.js @@ -25,4 +25,5 @@ import * as Misc from "./misc"; import * as CloudFunctions from "./cloud-functions"; import layouts from "./layouts"; import * as Monkey from "./monkey"; +import * as Notifications from "./notification-center"; import * as ResultFilters from "./result-filters"; diff --git a/src/js/leaderboards.js b/src/js/leaderboards.js index bbfe21874..2a7feb6a9 100644 --- a/src/js/leaderboards.js +++ b/src/js/leaderboards.js @@ -217,7 +217,8 @@ function updateLeaderboards() { } }) .catch((e) => { - Misc.showNotification("Something went wrong", 3000); + hideBackgroundLoader(); + Notifications.add("Something went wrong: " + e.message, -1); }); } diff --git a/src/js/misc.js b/src/js/misc.js index 2e8d4c240..92a4cf5dd 100644 --- a/src/js/misc.js +++ b/src/js/misc.js @@ -50,7 +50,7 @@ function hexToHSL(H) { let themesList = null; export async function getThemesList() { if (themesList == null) { - return $.getJSON("themes/list.json", function (data) { + return $.getJSON("themes/_list.json", function (data) { const list = data.sort(function (a, b) { const nameA = a.name.toLowerCase(); const nameB = b.name.toLowerCase(); @@ -87,7 +87,7 @@ export async function getSortedThemesList() { let funboxList = null; export async function getFunboxList() { if (funboxList == null) { - return $.getJSON("funbox/list.json", function (data) { + return $.getJSON("funbox/_list.json", function (data) { funboxList = data.sort(function (a, b) { const nameA = a.name.toLowerCase(); const nameB = b.name.toLowerCase(); @@ -105,7 +105,7 @@ export async function getFunboxList() { let fontsList = null; export async function getFontsList() { if (fontsList == null) { - return $.getJSON("js/fonts.json", function (data) { + return $.getJSON("fonts/_list.json", function (data) { fontsList = data.sort(function (a, b) { const nameA = a.name.toLowerCase(); const nameB = b.name.toLowerCase(); @@ -123,7 +123,7 @@ export async function getFontsList() { let languageList = null; export async function getLanguageList() { if (languageList == null) { - return $.getJSON("languages/list.json", function (data) { + return $.getJSON("languages/_list.json", function (data) { languageList = data; return languageList; }); @@ -135,7 +135,7 @@ export async function getLanguageList() { let challengeList = null; export async function getChallengeList() { if (challengeList == null) { - return $.getJSON("challenges/list.json", function (data) { + return $.getJSON("challenges/_list.json", function (data) { challengeList = data; return challengeList; }); diff --git a/src/js/notification-center.js b/src/js/notification-center.js new file mode 100644 index 000000000..c0f3be1fe --- /dev/null +++ b/src/js/notification-center.js @@ -0,0 +1,131 @@ +const notificationHistory = []; +let id = 0; +class Notification { + constructor(message, level, duration, customTitle, customIcon) { + this.message = message; + this.level = level; + if (duration == undefined) { + if (level === -1) { + this.duration = 0; + } else { + this.duration = 3000; + } + } else { + this.duration = duration * 1000; + } + this.customTitle = customTitle; + this.customIcon = customIcon; + this.id = id++; + } + //level + //0 - notice + //1 - good + //-1 - bad + show() { + let cls = "notice"; + let icon = ``; + let title = "Notice"; + if (this.level === 1) { + cls = "good"; + icon = ``; + title = "Success"; + } else if (this.level === -1) { + cls = "bad"; + icon = ``; + title = "Error"; + console.error(this.message); + } + + if (this.customTitle != undefined) { + title = this.customTitle; + } + + if (this.customIcon != undefined) { + icon = ``; + } + + // moveCurrentToHistory(); + let oldHeight = $("#notificationCenter .history").height(); + $("#notificationCenter .history").prepend(` + +