mirror of
https://github.com/hrfee/jfa-go.git
synced 2025-01-01 05:50:12 +00:00
Compare commits
4 Commits
4deb45df3c
...
25451eb763
Author | SHA1 | Date | |
---|---|---|---|
25451eb763 | |||
dbefb80f63 | |||
|
42dbc04ff9 | ||
|
82c8ef1e4b |
14
css/base.css
14
css/base.css
@ -181,6 +181,18 @@ span.sm:not(.heading) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.flex-form {
|
||||
flex: 1;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.row {
|
||||
flex-direction: column;
|
||||
@ -308,7 +320,7 @@ sup.\~critical, .text-critical {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.block {
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
@ -81,19 +81,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="notification-box"></div>
|
||||
<div class="page-container">
|
||||
<div class="card dark:~d_neutral @low">
|
||||
<div class="row baseline">
|
||||
<span class="col heading">
|
||||
<span class="flex-form heading mr-5">
|
||||
{{ if .passwordReset }}
|
||||
{{ .strings.passwordReset }}
|
||||
{{ else }}
|
||||
{{ .strings.createAccountHeader }}
|
||||
{{ end }}
|
||||
</span>
|
||||
<span class="col subheading">
|
||||
<span class="flex-form subheading">
|
||||
{{ if .passwordReset }}
|
||||
{{ .strings.enterYourPassword }}
|
||||
{{ else }}
|
||||
@ -102,7 +102,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="flex-form">
|
||||
{{ if .userExpiry }}
|
||||
<aside class="col aside sm ~warning" id="user-expiry-message"></aside>
|
||||
{{ end }}
|
||||
@ -112,35 +112,35 @@
|
||||
{{ .strings.username }}
|
||||
<input type="text" class="input ~neutral @high mt-2 mb-4" placeholder="{{ .strings.username }}" id="create-username" aria-label="{{ .strings.username }}">
|
||||
</label>
|
||||
|
||||
|
||||
<label class="label supra" for="create-email">{{ .strings.emailAddress }}</label>
|
||||
<input type="email" class="input ~neutral @high mt-2 mb-4" placeholder="{{ .strings.emailAddress }}" id="create-email" aria-label="{{ .strings.emailAddress }}" value="{{ .email }}">
|
||||
{{ if .telegramEnabled }}
|
||||
<span class="button ~info @low full-width center mb-4" id="link-telegram">{{ .strings.linkTelegram }}</span>
|
||||
<span class="button ~info @low full-width center mb-4" id="link-telegram">{{ .strings.linkTelegram }} {{ if .telegramRequired }}({{ .strings.required }}){{ end }}</span>
|
||||
{{ end }}
|
||||
{{ if .discordEnabled }}
|
||||
<span class="button ~info @low full-width center mb-4" id="link-discord">{{ .strings.linkDiscord }}</span>
|
||||
<span class="button ~info @low full-width center mb-4" id="link-discord">{{ .strings.linkDiscord }} {{ if .discordRequired }}({{ .strings.required }}){{ end }}</span>
|
||||
{{ end }}
|
||||
{{ if .matrixEnabled }}
|
||||
<span class="button ~info @low full-width center mb-4" id="link-matrix">{{ .strings.linkMatrix }}</span>
|
||||
<span class="button ~info @low full-width center mb-4" id="link-matrix">{{ .strings.linkMatrix }} {{ if .matrixRequired }}({{ .strings.required }}){{ end }}</span>
|
||||
{{ end }}
|
||||
{{ if or (.telegramEnabled) (or .discordEnabled .matrixEnabled) }}
|
||||
<div id="contact-via" class="unfocused">
|
||||
<label class="row switch pb-4">
|
||||
<input type="radio" name="contact-via" value="email" class="mr-2"><span>Contact through Email</span>
|
||||
<label class="row switch pb-4 unfocused">
|
||||
<input type="radio" name="contact-via" value="email" id="contact-via-email" class="mr-2"><span>Contact through Email</span>
|
||||
</label>
|
||||
{{ if .telegramEnabled }}
|
||||
<label class="row switch pb-4">
|
||||
<label class="row switch pb-4 unfocused">
|
||||
<input type="radio" name="contact-via" value="telegram" id="contact-via-telegram" class="mr-2"><span>Contact through Telegram</span>
|
||||
</label>
|
||||
{{ end }}
|
||||
{{ if .discordEnabled }}
|
||||
<label class="row switch pb-4">
|
||||
<label class="row switch pb-4 unfocused">
|
||||
<input type="radio" name="contact-via" value="discord" id="contact-via-discord" class="mr-2"><span>Contact through Discord</span>
|
||||
</label>
|
||||
{{ end }}
|
||||
{{ if .matrixEnabled }}
|
||||
<label class="row switch pb-4">
|
||||
<label class="row switch pb-4 unfocused">
|
||||
<input type="radio" name="contact-via" value="matrix" id="contact-via-matrix" class="mr-2"><span>Contact through Matrix</span>
|
||||
</label>
|
||||
{{ end }}
|
||||
@ -149,7 +149,7 @@
|
||||
{{ end }}
|
||||
<label class="label supra" for="create-password">{{ .strings.password }}</label>
|
||||
<input type="password" class="input ~neutral @high mt-2 mb-4" placeholder="{{ .strings.password }}" id="create-password" aria-label="{{ .strings.password }}">
|
||||
|
||||
|
||||
<label class="label supra" for="create-reenter-password">{{ .strings.reEnterPassword }}</label>
|
||||
<input type="password" class="input ~neutral @high mt-2 mb-4" placeholder="{{ .strings.password }}" id="create-reenter-password" aria-label="{{ .strings.reEnterPassword }}">
|
||||
<label>
|
||||
|
@ -23,6 +23,7 @@
|
||||
"linkMatrix": "Link Matrix",
|
||||
"contactDiscord": "Contact through Discord",
|
||||
"theme": "Theme",
|
||||
"refresh": "Refresh"
|
||||
"refresh": "Refresh",
|
||||
"required": "Required"
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@
|
||||
"errorUnknown": "Unknown error.",
|
||||
"errorNoEmail": "Email required.",
|
||||
"errorCaptcha": "Captcha incorrect.",
|
||||
"errorPassword": "Check password requirements.",
|
||||
"errorNoMatch": "Passwords don't match.",
|
||||
"verified": "Account verified."
|
||||
},
|
||||
"validationStrings": {
|
||||
|
128
ts/form.ts
128
ts/form.ts
@ -70,8 +70,11 @@ if (window.telegramEnabled) {
|
||||
setTimeout(window.telegramModal.close, 2000);
|
||||
telegramButton.classList.add("unfocused");
|
||||
document.getElementById("contact-via").classList.remove("unfocused");
|
||||
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
||||
const radio = document.getElementById("contact-via-telegram") as HTMLInputElement;
|
||||
radio.parentElement.classList.remove("unfocused");
|
||||
radio.checked = true;
|
||||
validatorFunc();
|
||||
} else if (!modalClosed) {
|
||||
setTimeout(checkVerified, 1500);
|
||||
}
|
||||
@ -130,8 +133,11 @@ if (window.discordEnabled) {
|
||||
setTimeout(window.discordModal.close, 2000);
|
||||
discordButton.classList.add("unfocused");
|
||||
document.getElementById("contact-via").classList.remove("unfocused");
|
||||
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
||||
const radio = document.getElementById("contact-via-discord") as HTMLInputElement;
|
||||
radio.parentElement.classList.remove("unfocused")
|
||||
radio.checked = true;
|
||||
validatorFunc();
|
||||
} else if (!modalClosed) {
|
||||
setTimeout(checkVerified, 1500);
|
||||
}
|
||||
@ -188,8 +194,11 @@ if (window.matrixEnabled) {
|
||||
matrixPIN = input.value;
|
||||
matrixButton.classList.add("unfocused");
|
||||
document.getElementById("contact-via").classList.remove("unfocused");
|
||||
const radio = document.getElementById("contact-via-discord") as HTMLInputElement;
|
||||
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
||||
const radio = document.getElementById("contact-via-matrix") as HTMLInputElement;
|
||||
radio.parentElement.classList.remove("unfocused");
|
||||
radio.checked = true;
|
||||
validatorFunc();
|
||||
} else {
|
||||
window.notifications.customError("errorInvalidPIN", window.messages["errorInvalidPIN"]);
|
||||
submitButton.classList.add("~critical");
|
||||
@ -227,25 +236,85 @@ if (window.userExpiryEnabled) {
|
||||
const form = document.getElementById("form-create") as HTMLFormElement;
|
||||
const submitButton = form.querySelector("input[type=submit]") as HTMLInputElement;
|
||||
const submitSpan = form.querySelector("span.submit") as HTMLSpanElement;
|
||||
const submitText = submitSpan.textContent;
|
||||
let usernameField = document.getElementById("create-username") as HTMLInputElement;
|
||||
const emailField = document.getElementById("create-email") as HTMLInputElement;
|
||||
if (!window.usernameEnabled) { usernameField.parentElement.remove(); usernameField = emailField; }
|
||||
const passwordField = document.getElementById("create-password") as HTMLInputElement;
|
||||
const rePasswordField = document.getElementById("create-reenter-password") as HTMLInputElement;
|
||||
|
||||
if (window.emailRequired) {
|
||||
emailField.addEventListener("keyup", () => {
|
||||
if (emailField.value.includes("@")) {
|
||||
submitButton.disabled = false;
|
||||
submitSpan.removeAttribute("disabled");
|
||||
} else {
|
||||
submitButton.disabled = true;
|
||||
submitSpan.setAttribute("disabled", "");
|
||||
let captchaVerified = false;
|
||||
let captchaID = "";
|
||||
let captchaInput = document.getElementById("captcha-input") as HTMLInputElement;
|
||||
const captchaCheckbox = document.getElementById("captcha-success") as HTMLSpanElement;
|
||||
let prevCaptcha = "";
|
||||
|
||||
function baseValidator(oncomplete: (valid: boolean) => void): void {
|
||||
let captchaChecked = false;
|
||||
let captchaChange = false;
|
||||
if (window.captcha) {
|
||||
captchaChange = captchaInput.value != prevCaptcha;
|
||||
if (captchaChange) {
|
||||
prevCaptcha = captchaInput.value;
|
||||
_post("/captcha/verify/" + window.code + "/" + captchaID + "/" + captchaInput.value, null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 204) {
|
||||
captchaCheckbox.innerHTML = `<i class="ri-check-line"></i>`;
|
||||
captchaCheckbox.classList.add("~positive");
|
||||
captchaCheckbox.classList.remove("~critical");
|
||||
captchaVerified = true;
|
||||
captchaChecked = true;
|
||||
} else {
|
||||
captchaCheckbox.innerHTML = `<i class="ri-close-line"></i>`;
|
||||
captchaCheckbox.classList.add("~critical");
|
||||
captchaCheckbox.classList.remove("~positive");
|
||||
captchaVerified = false;
|
||||
captchaChecked = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (window.emailRequired) {
|
||||
if (!emailField.value.includes("@")) {
|
||||
oncomplete(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (window.discordEnabled && window.discordRequired && !discordVerified) {
|
||||
oncomplete(false);
|
||||
return;
|
||||
}
|
||||
if (window.telegramEnabled && window.telegramRequired && !telegramVerified) {
|
||||
oncomplete(false);
|
||||
return;
|
||||
}
|
||||
if (window.matrixEnabled && window.matrixRequired && !matrixVerified) {
|
||||
oncomplete(false);
|
||||
return;
|
||||
}
|
||||
if (window.captcha) {
|
||||
if (!captchaChange) {
|
||||
oncomplete(captchaVerified);
|
||||
return;
|
||||
}
|
||||
while (!captchaChecked) {
|
||||
continue;
|
||||
}
|
||||
oncomplete(captchaVerified);
|
||||
} else {
|
||||
oncomplete(true);
|
||||
}
|
||||
}
|
||||
|
||||
var requirements = initValidator(passwordField, rePasswordField, submitButton, submitSpan)
|
||||
let r = initValidator(passwordField, rePasswordField, submitButton, submitSpan, baseValidator);
|
||||
var requirements = r[0];
|
||||
var validatorFunc = r[1] as () => void;
|
||||
|
||||
if (window.emailRequired) {
|
||||
emailField.addEventListener("keyup", validatorFunc)
|
||||
}
|
||||
|
||||
interface respDTO {
|
||||
response: boolean;
|
||||
@ -267,10 +336,6 @@ interface sendDTO {
|
||||
captcha_text?: string;
|
||||
}
|
||||
|
||||
let captchaVerified = false;
|
||||
let captchaID = "";
|
||||
let captchaInput = document.getElementById("captcha-input") as HTMLInputElement;
|
||||
|
||||
const genCaptcha = () => {
|
||||
_get("/captcha/gen/"+window.code, null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
@ -288,27 +353,7 @@ const genCaptcha = () => {
|
||||
if (window.captcha) {
|
||||
genCaptcha();
|
||||
(document.getElementById("captcha-regen") as HTMLSpanElement).onclick = genCaptcha;
|
||||
const input = document.querySelector("input[type=submit]") as HTMLInputElement;
|
||||
const checkbox = document.getElementById("captcha-success") as HTMLSpanElement;
|
||||
captchaInput.onkeyup = () => _post("/captcha/verify/" + window.code + "/" + captchaID + "/" + captchaInput.value, null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 204) {
|
||||
input.disabled = false;
|
||||
input.nextElementSibling.removeAttribute("disabled");
|
||||
checkbox.innerHTML = `<i class="ri-check-line"></i>`;
|
||||
checkbox.classList.add("~positive");
|
||||
checkbox.classList.remove("~critical");
|
||||
} else {
|
||||
input.disabled = true;
|
||||
input.nextElementSibling.setAttribute("disabled", "true");
|
||||
checkbox.innerHTML = `<i class="ri-close-line"></i>`;
|
||||
checkbox.classList.add("~critical");
|
||||
checkbox.classList.remove("~positive");
|
||||
}
|
||||
}
|
||||
}, );
|
||||
input.disabled = true;
|
||||
input.nextElementSibling.setAttribute("disabled", "true");
|
||||
captchaInput.onkeyup = validatorFunc;
|
||||
}
|
||||
|
||||
const create = (event: SubmitEvent) => {
|
||||
@ -361,9 +406,15 @@ const create = (event: SubmitEvent) => {
|
||||
} else {
|
||||
submitSpan.classList.add("~critical");
|
||||
submitSpan.classList.remove("~urge");
|
||||
if (req.response["error"] as string) {
|
||||
submitSpan.textContent = window.messages[req.response["error"]];
|
||||
} else {
|
||||
submitSpan.textContent = window.messages["errorPassword"];
|
||||
}
|
||||
setTimeout(() => {
|
||||
submitSpan.classList.add("~urge");
|
||||
submitSpan.classList.remove("~critical");
|
||||
submitSpan.textContent = submitText;
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
@ -376,17 +427,18 @@ const create = (event: SubmitEvent) => {
|
||||
window.confirmationModal.show();
|
||||
return;
|
||||
}
|
||||
const old = submitSpan.textContent;
|
||||
if (req.response["error"] in window.messages) {
|
||||
submitSpan.textContent = window.messages[req.response["error"]];
|
||||
} else {
|
||||
submitSpan.textContent = req.response["error"];
|
||||
}
|
||||
setTimeout(() => { submitSpan.textContent = old; }, 1000);
|
||||
setTimeout(() => { submitSpan.textContent = submitText; }, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
validatorFunc();
|
||||
|
||||
form.onsubmit = create;
|
||||
|
@ -1,6 +1,7 @@
|
||||
interface valWindow extends Window {
|
||||
validationStrings: pwValStrings;
|
||||
invalidPassword: string;
|
||||
messages: { [key: string]: string };
|
||||
}
|
||||
|
||||
interface pwValString {
|
||||
@ -59,7 +60,7 @@ class Requirement {
|
||||
validate = (count: number) => { this.valid = (count >= this._minCount); }
|
||||
}
|
||||
|
||||
export function initValidator(passwordField: HTMLInputElement, rePasswordField: HTMLInputElement, submitButton: HTMLInputElement, submitSpan: HTMLSpanElement): { [category: string]: Requirement } {
|
||||
export function initValidator(passwordField: HTMLInputElement, rePasswordField: HTMLInputElement, submitButton: HTMLInputElement, submitSpan: HTMLSpanElement, validatorFunc?: (oncomplete: (valid: boolean) => void) => void): ({ [category: string]: Requirement }|(() => void))[] {
|
||||
var defaultPwValStrings: pwValStrings = {
|
||||
length: {
|
||||
singular: "Must have at least {n} character",
|
||||
@ -84,18 +85,30 @@ export function initValidator(passwordField: HTMLInputElement, rePasswordField:
|
||||
}
|
||||
|
||||
const checkPasswords = () => {
|
||||
if (passwordField.value != rePasswordField.value) {
|
||||
rePasswordField.setCustomValidity(window.invalidPassword);
|
||||
submitButton.disabled = true;
|
||||
submitSpan.setAttribute("disabled", "");
|
||||
} else {
|
||||
rePasswordField.setCustomValidity("");
|
||||
submitButton.disabled = false;
|
||||
submitSpan.removeAttribute("disabled");
|
||||
}
|
||||
return passwordField.value == rePasswordField.value;
|
||||
}
|
||||
|
||||
const checkValidity = () => {
|
||||
const pw = checkPasswords();
|
||||
validatorFunc((valid: boolean) => {
|
||||
if (pw && valid) {
|
||||
rePasswordField.setCustomValidity("");
|
||||
submitButton.disabled = false;
|
||||
submitSpan.removeAttribute("disabled");
|
||||
} else if (!pw) {
|
||||
rePasswordField.setCustomValidity(window.invalidPassword);
|
||||
submitButton.disabled = true;
|
||||
submitSpan.setAttribute("disabled", "");
|
||||
} else {
|
||||
rePasswordField.setCustomValidity("");
|
||||
submitButton.disabled = true;
|
||||
submitSpan.setAttribute("disabled", "");
|
||||
}
|
||||
});
|
||||
};
|
||||
rePasswordField.addEventListener("keyup", checkPasswords);
|
||||
passwordField.addEventListener("keyup", checkPasswords);
|
||||
|
||||
rePasswordField.addEventListener("keyup", checkValidity);
|
||||
passwordField.addEventListener("keyup", checkValidity);
|
||||
|
||||
|
||||
// Incredible code right here
|
||||
@ -150,5 +163,5 @@ export function initValidator(passwordField: HTMLInputElement, rePasswordField:
|
||||
}
|
||||
}
|
||||
}
|
||||
return requirements
|
||||
return [requirements, checkValidity]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user