Merge branch 'monkeytypegame:master' into master

This commit is contained in:
Shibin Thomas 2022-05-25 01:04:57 +05:30 committed by GitHub
commit bacea3a078
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 239 additions and 136 deletions

View file

@ -301,6 +301,8 @@ export function signIn(): void {
authListener();
LoginPage.showPreloader();
LoginPage.disableInputs();
LoginPage.disableSignUpButton();
LoginPage.disableSignInButton();
const email = ($(".pageLogin .login input")[0] as HTMLInputElement).value;
const password = ($(".pageLogin .login input")[1] as HTMLInputElement).value;
@ -343,6 +345,8 @@ export function signIn(): void {
Notifications.add(message, -1);
LoginPage.hidePreloader();
LoginPage.enableInputs();
LoginPage.enableSignInButton();
LoginPage.updateSignupButton();
});
});
}
@ -351,6 +355,8 @@ export async function signInWithGoogle(): Promise<void> {
UpdateConfig.setChangedBeforeDb(false);
LoginPage.showPreloader();
LoginPage.disableInputs();
LoginPage.disableSignUpButton();
LoginPage.disableSignInButton();
authListener();
const persistence = $(".pageLogin .login #rememberMe input").prop("checked")
? browserLocalPersistence
@ -380,6 +386,8 @@ export async function signInWithGoogle(): Promise<void> {
Notifications.add(message, -1);
LoginPage.hidePreloader();
LoginPage.enableInputs();
LoginPage.enableSignInButton();
LoginPage.updateSignupButton();
});
}
@ -509,6 +517,7 @@ export function signOut(): void {
async function signUp(): Promise<void> {
LoginPage.disableInputs();
LoginPage.disableSignUpButton();
LoginPage.showPreloader();
const nname = ($(".pageLogin .register input")[0] as HTMLInputElement).value;
const email = ($(".pageLogin .register input")[1] as HTMLInputElement).value;
@ -523,6 +532,7 @@ async function signUp(): Promise<void> {
if (nname === "" || email === "" || emailVerify === "" || password === "") {
LoginPage.hidePreloader();
LoginPage.enableInputs();
LoginPage.updateSignupButton();
Notifications.add("Please fill in all fields", 0);
return;
}
@ -534,16 +544,16 @@ async function signUp(): Promise<void> {
) {
Notifications.add("Invalid email", 0, 3);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
return;
}
if (email !== emailVerify) {
Notifications.add("Emails do not match", 0, 3);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
return;
}
@ -551,8 +561,8 @@ async function signUp(): Promise<void> {
if (password.length < 8) {
Notifications.add("Password must be at least 8 characters", 0, 3);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
return;
}
@ -566,16 +576,16 @@ async function signUp(): Promise<void> {
3
);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
return;
}
if (password !== passwordVerify) {
Notifications.add("Passwords do not match", 0, 3);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
return;
}
@ -634,8 +644,8 @@ async function signUp(): Promise<void> {
const message = Misc.createErrorMessage(e, "Failed to create account");
Notifications.add(message, -1);
LoginPage.hidePreloader();
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
LoginPage.enableInputs();
LoginPage.updateSignupButton();
signOut();
return;
}

View file

@ -615,6 +615,9 @@ function handleTab(event: JQuery.KeyDownEvent, popupVisible: boolean): void {
// dont do anything special
if (modalVisible) return;
// dont do anything on login so we can tab betweeen inputs
if (ActivePage.get() === "login") return;
// change page if not on test page
if (ActivePage.get() !== "test") {
PageController.change("test");

View file

@ -6,18 +6,20 @@ interface InputIndicatorOption {
}
export class InputIndicator {
private inputElement: JQuery<HTMLElement>;
private parentElement: JQuery<HTMLElement>;
private options: Record<string, InputIndicatorOption>;
private currentStatus: keyof typeof this.options | null;
constructor(
parentElement: JQuery<HTMLElement>,
inputElement: JQuery<HTMLElement>,
options: Record<string, InputIndicatorOption>
) {
if (!parentElement.hasClass("inputAndIndicator")) {
throw new Error("Parent element must have class 'inputAndIndicator'");
}
this.parentElement = parentElement;
this.inputElement = inputElement;
$(this.inputElement).wrap(`<div class="inputAndIndicator"></div>`);
this.parentElement = $(this.inputElement).parent(".inputAndIndicator");
this.options = options;
this.currentStatus = null;
let indicator = `<div class="statusIndicator">`;
@ -45,16 +47,20 @@ export class InputIndicator {
indicator += `</div>`;
parentElement.append(indicator);
this.parentElement.append(indicator);
}
hide(): void {
this.parentElement.find(".statusIndicator div").addClass("hidden");
this.currentStatus = null;
$(this.inputElement).css("padding-right", "0.5rem");
}
show(optionId: keyof typeof this.options, messageOverride?: string): void {
this.hide();
this.currentStatus = optionId;
const indicator = this.parentElement.find(`[data-option-id="${optionId}"]`);
indicator.removeClass("hidden");
@ -67,5 +73,11 @@ export class InputIndicator {
}
indicator.attr("aria-label", messageOverride);
}
$(this.inputElement).css("padding-right", "2.1rem");
}
get(): keyof typeof this.options | null {
return this.currentStatus;
}
}

View file

@ -4,13 +4,27 @@ import Page from "./page";
import * as Notifications from "../elements/notifications";
import { InputIndicator } from "../elements/input-indicator";
export function enableSignUpButton(): void {
$(".page.pageLogin .register.side .button").removeClass("disabled");
}
export function disableSignUpButton(): void {
$(".page.pageLogin .register.side .button").addClass("disabled");
}
export function enableSignInButton(): void {
$(".page.pageLogin .login.side .button").removeClass("disabled");
}
export function disableSignInButton(): void {
$(".page.pageLogin .login.side .button").addClass("disabled");
}
export function enableInputs(): void {
$(".pageLogin .button").removeClass("disabled");
$(".pageLogin input").prop("disabled", false);
}
export function disableInputs(): void {
$(".pageLogin .button").addClass("disabled");
$(".pageLogin input").prop("disabled", true);
}
@ -22,56 +36,77 @@ export function hidePreloader(): void {
$(".pageLogin .preloader").addClass("hidden");
}
export const updateSignupButton = (): void => {
if (
nameIndicator.get() !== "available" ||
emailIndicator.get() !== "valid" ||
verifyEmailIndicator.get() !== "match" ||
passwordIndicator.get() !== "good" ||
verifyPasswordIndicator.get() !== "match"
) {
disableSignUpButton();
} else {
enableSignUpButton();
}
};
const checkNameDebounced = debounce(1000, async () => {
const val = $(
".page.pageLogin .register.side .usernameInput"
).val() as string;
if (!val) return;
if (!val) {
updateSignupButton();
return;
}
const response = await Ape.users.getNameAvailability(val);
if (response.status === 200) {
nameIndicator.show("available", response.message);
return;
}
if (response.status == 422) {
} else if (response.status === 422) {
nameIndicator.show("unavailable", response.message);
return;
}
if (response.status == 409) {
} else if (response.status === 409) {
nameIndicator.show("taken", response.message);
return;
}
if (response.status !== 200) {
} else {
nameIndicator.show("unavailable", response.message);
return Notifications.add(
Notifications.add(
"Failed to check name availability: " + response.message,
-1
);
}
});
const checkEmailsMatch = (): void => {
const email = $(".page.pageLogin .register.side .emailInput").val();
const verifyEmail = $(
".page.pageLogin .register.side .verifyEmailInput"
).val();
verifyEmailIndicator.show(email === verifyEmail ? "match" : "mismatch");
};
updateSignupButton();
});
const checkEmail = (): void => {
const emailRegex =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const email = $(".page.pageLogin .register.side .emailInput").val() as string;
if (emailRegex.test(email)) {
emailIndicator.show("valid");
} else {
emailIndicator.show("invalid");
}
emailIndicator.show(emailRegex.test(email) ? "valid" : "invalid");
updateSignupButton();
};
const checkEmailsMatch = (): void => {
const email = $(".page.pageLogin .register.side .emailInput").val();
const verifyEmail = $(
".page.pageLogin .register.side .verifyEmailInput"
).val();
if (email === verifyEmail) {
verifyEmailIndicator.show("match");
} else {
verifyEmailIndicator.show("mismatch");
}
updateSignupButton();
};
const checkPassword = (): void => {
passwordIndicator.show("good");
const password = $(
".page.pageLogin .register.side .passwordInput"
).val() as string;
@ -80,20 +115,20 @@ const checkPassword = (): void => {
if (password.length < 8) {
passwordIndicator.show("short", "Password must be at least 8 characters");
return;
} else {
const hasCapital = password.match(/[A-Z]/);
const hasNumber = password.match(/[\d]/);
const hasSpecial = password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/);
if (!hasCapital || !hasNumber || !hasSpecial) {
passwordIndicator.show(
"weak",
"Password must contain at least one capital letter, number, and special character"
);
} else {
passwordIndicator.show("good", "Password is good");
}
}
const hasCapital = password.match(/[A-Z]/);
const hasNumber = password.match(/[\d]/);
const hasSpecial = password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/);
if (!hasCapital || !hasNumber || !hasSpecial) {
passwordIndicator.show(
"weak",
"Password must contain at least one capital letter, number, and special character"
);
return;
}
passwordIndicator.show("good", "Password is good");
updateSignupButton();
};
const checkPasswordsMatch = (): void => {
@ -101,13 +136,17 @@ const checkPasswordsMatch = (): void => {
const verifyPassword = $(
".page.pageLogin .register.side .verifyPasswordInput"
).val();
verifyPasswordIndicator.show(
password === verifyPassword ? "match" : "mismatch"
);
if (password === verifyPassword) {
verifyPasswordIndicator.show("match");
} else {
verifyPasswordIndicator.show("mismatch");
}
updateSignupButton();
};
const nameIndicator = new InputIndicator(
$(".page.pageLogin .register.side .username.inputAndIndicator"),
$(".page.pageLogin .register.side input.usernameInput"),
{
available: {
icon: "fa-check",
@ -130,7 +169,7 @@ const nameIndicator = new InputIndicator(
);
const emailIndicator = new InputIndicator(
$(".page.pageLogin .register.side .email.inputAndIndicator"),
$(".page.pageLogin .register.side input.emailInput"),
{
valid: {
icon: "fa-check",
@ -144,7 +183,7 @@ const emailIndicator = new InputIndicator(
);
const verifyEmailIndicator = new InputIndicator(
$(".page.pageLogin .register.side .verifyEmail.inputAndIndicator"),
$(".page.pageLogin .register.side input.verifyEmailInput"),
{
match: {
icon: "fa-check",
@ -158,7 +197,7 @@ const verifyEmailIndicator = new InputIndicator(
);
const passwordIndicator = new InputIndicator(
$(".page.pageLogin .register.side .password.inputAndIndicator"),
$(".page.pageLogin .register.side input.passwordInput"),
{
good: {
icon: "fa-check",
@ -176,7 +215,7 @@ const passwordIndicator = new InputIndicator(
);
const verifyPasswordIndicator = new InputIndicator(
$(".page.pageLogin .register.side .verifyPassword.inputAndIndicator"),
$(".page.pageLogin .register.side input.verifyPasswordInput"),
{
match: {
icon: "fa-check",

View file

@ -40,7 +40,10 @@ export function show(): void {
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, () => {
if ($("#cookiePopupWrapper").outerHeight(true) === 0) {
if (
$("#cookiePopupWrapper").is(":visible") === false ||
$("#cookiePopupWrapper").outerHeight(true) === 0
) {
visible = false;
} else {
visible = true;

View file

@ -153,28 +153,25 @@ $("#googleSignUpPopupWrapper").on("mousedown", (e) => {
}
});
const nameIndicator = new InputIndicator(
$("#googleSignUpPopup .inputAndIndicator"),
{
available: {
icon: "fa-check",
level: 1,
},
unavailable: {
icon: "fa-times",
level: -1,
},
taken: {
icon: "fa-times",
level: -1,
},
checking: {
icon: "fa-circle-notch",
spinIcon: true,
level: 0,
},
}
);
const nameIndicator = new InputIndicator($("#googleSignUpPopup input"), {
available: {
icon: "fa-check",
level: 1,
},
unavailable: {
icon: "fa-times",
level: -1,
},
taken: {
icon: "fa-times",
level: -1,
},
checking: {
icon: "fa-circle-notch",
spinIcon: true,
level: 0,
},
});
const checkNameDebounced = debounce(1000, async () => {
const val = $("#googleSignUpPopup input").val() as string;

View file

@ -5,49 +5,39 @@
<div class="register side">
<div class="title">register</div>
<form action="" autocomplete="nope">
<div class="inputAndIndicator username">
<input
type="text"
class="usernameInput"
placeholder="username"
autocomplete="new-username"
/>
</div>
<div class="inputAndIndicator email">
<input
type="email"
class="emailInput"
placeholder="email"
autocomplete="new-email"
/>
</div>
<div class="inputAndIndicator verifyEmail">
<input
type="email"
class="verifyEmailInput"
placeholder="verify email"
autocomplete="verify-email"
/>
</div>
<div class="inputAndIndicator password">
<input
type="password"
class="passwordInput"
placeholder="password"
autocomplete="new-password"
name="new-password"
/>
</div>
<div class="inputAndIndicator verifyPassword">
<input
type="password"
class="verifyPasswordInput"
placeholder="verify password"
autocomplete="verify-password"
name="verify-password"
/>
</div>
<div class="button">
<input
type="text"
class="usernameInput"
placeholder="username"
autocomplete="new-username"
/>
<input
type="email"
class="emailInput"
placeholder="email"
autocomplete="new-email"
/>
<input
type="email"
class="verifyEmailInput"
placeholder="verify email"
autocomplete="verify-email"
/>
<input
type="password"
class="passwordInput"
placeholder="password"
autocomplete="new-password"
name="new-password"
/>
<input
type="password"
class="verifyPasswordInput"
placeholder="verify password"
autocomplete="verify-password"
name="verify-password"
/>
<div class="button disabled">
<i class="fas fa-user-plus"></i>
Sign Up
</div>

View file

@ -474,9 +474,7 @@
<div id="googleSignUpPopup">
<div class="title">Account name</div>
<div class="text">You need to choose a username before continuing</div>
<div class="inputAndIndicator">
<input type="text" placeholder="username" />
</div>
<input type="text" placeholder="username" />
<div class="button disabled">Sign up</div>
</div>
</div>

View file

@ -331,7 +331,8 @@
"code_matlab",
"code_sql",
"code_perl",
"code_php"
"code_php",
"code_vim"
]
},
{

View file

@ -186,6 +186,7 @@
,"code_sql"
,"code_perl"
,"code_php"
,"code_vim"
,"hindi"
,"hindi_1k"
,"macedonian"

View file

@ -0,0 +1,49 @@
{
"name": "code_vim",
"leftToRight": true,
"noLazyMode": true,
"words": [
":e",
":w",
":q",
":q!",
":wq",
":wq!",
":x",
":x!",
":sav",
"u",
"k",
"j",
"h",
"l",
"e",
"b",
"0",
"G",
"gg",
"L",
"[[",
"[{",
"y",
"p",
"dd",
"yy",
"y$",
"D",
":e.",
":Sex",
":Sex!",
":browse e",
":ls",
":cd..",
":args",
"gf",
":tabnew",
"gt",
":tabfirst",
":tablast",
":new",
":split"
]
}

View file

@ -42,7 +42,7 @@
"ამბებისა",
"ჰიმნი",
"ხაზს",
"ყველანარი",
"ყველანარი",
"რაიონი",
"ძეგლი",
"აღნიშნავდეს",