rewrite* most web ui code in typescript

i wanted to split up the web ui components into multiple files, and
figured it'd be a good chance to try out typescript. run make typescript
to compile everything in ts/ and put it in data/static/.

This is less of a rewrite and more of a refactoring, most of it still
works the same but bits have been cleaned up too.

Remaining javascript found in setup.js and form.html
This commit is contained in:
Harvey Tindall
2020-09-21 22:06:27 +01:00
parent 73886fc037
commit 32b8ed4aa2
20 changed files with 1235 additions and 1732 deletions
+61 -65
View File
@@ -1,32 +1,3 @@
const _post = (url: string, data: Object, onreadystatechange: () => void): void => {
let req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = onreadystatechange;
req.send(JSON.stringify(data));
};
const _get = (url: string, data: Object, onreadystatechange: () => void): void => {
let req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = 'json';
req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = onreadystatechange;
req.send(JSON.stringify(data));
};
const rmAttr = (el: HTMLElement, attr: string): void => {
if (el.classList.contains(attr)) {
el.classList.remove(attr);
}
};
const addAttr = (el: HTMLElement, attr: string): void => el.classList.add(attr);
const Focus = (el: HTMLElement): void => rmAttr(el, 'unfocused');
const Unfocus = (el: HTMLElement): void => addAttr(el, 'unfocused');
const checkCheckboxes = (): void => {
const defaultsButton = document.getElementById('accountsTabSetDefaults');
const deleteButton = document.getElementById('accountsTabDelete');
@@ -46,15 +17,12 @@ const checkCheckboxes = (): void => {
}
}
const validateEmail = (email: string): boolean => {
const re = /\S+@\S+\.\S+/;
return re.test(email);
}
const validateEmail = (email: string): boolean => /\S+@\S+\.\S+/.test(email);
const changeEmail = (icon: HTMLElement, id: string): void => {
function changeEmail(icon: HTMLElement, id: string): void {
const iconContent = icon.outerHTML;
icon.setAttribute('class', '');
const entry: HTMLInputElement = icon.nextElementSibling;
const entry = icon.nextElementSibling as HTMLInputElement;
const ogEmail = entry.value;
entry.readOnly = false;
entry.classList.remove('form-control-plaintext');
@@ -62,26 +30,26 @@ const changeEmail = (icon: HTMLElement, id: string): void => {
if (ogEmail == "") {
entry.placeholder = 'Address';
}
const tick = document.createElement('i');
tick.outerHTML = `
const tick = createEl(`
<i class="fa fa-check d-inline-block icon-button text-success" style="margin-left: 0.5rem; margin-right: 0.5rem;"></i>
`;
`);
tick.onclick = (): void => {
const newEmail = entry.value;
if (!validateEmail(newEmail) || newEmail == ogEmail) {
return;
}
cross.remove();
tick.outerHTML = `
const spinner = createEl(`
<div class="spinner-border spinner-border-sm" role="status" style="width: 1rem; height: 1rem; margin-left: 0.5rem;">
<span class="sr-only">Saving...</span>
</div>
`;
`);
tick.replaceWith(spinner);
let send = {};
send[id] = newEmail;
_post("/modifyEmails", send, function (): void {
if (this.readyState == 4) {
if (this.status == '200' || this.status == '204') {
if (this.status == 200 || this.status == 204) {
entry.nextElementSibling.remove();
} else {
entry.value = ogEmail;
@@ -94,10 +62,9 @@ const changeEmail = (icon: HTMLElement, id: string): void => {
entry.classList.add('form-control-plaintext');
entry.placeholder = '';
};
const cross: HTMLElement = document.createElement('i');
cross.outerHTML = `
const cross = createEl(`
<i class="fa fa-close d-inline-block icon-button text-danger"></i>
`;
`);
cross.onclick = (): void => {
tick.remove();
cross.remove();
@@ -114,7 +81,7 @@ const changeEmail = (icon: HTMLElement, id: string): void => {
var jfUsers: Array<Object>;
const populateUsers = (): void => {
function populateUsers(): void {
const acList = document.getElementById('accountsList');
acList.innerHTML = `
<div class="d-flex align-items-center">
@@ -157,7 +124,7 @@ const populateUsers = (): void => {
};
_get("/getUsers", null, function (): void {
if (this.readyState == 4 && this.status == '200') {
if (this.readyState == 4 && this.status == 200) {
jfUsers = this.response['users'];
for (const user of jfUsers) {
let tr = document.createElement('tr');
@@ -170,11 +137,32 @@ const populateUsers = (): void => {
});
}
function populateRadios(): void {
const radioList = document.getElementById('defaultUserRadios');
radioList.textContent = '';
let first = true;
for (const i in jfUsers) {
const user = jfUsers[i];
const radio = document.createElement('div');
radio.classList.add('form-check');
let checked = '';
if (first) {
checked = 'checked';
first = false;
}
radio.innerHTML = `
<input class="form-check-input" type="radio" name="defaultRadios" id="default_${user['id']}" ${checked}>
<label class="form-check-label" for="default_${user['id']}">${user['name']}</label>`;
radioList.appendChild(radio);
}
}
(<HTMLInputElement>document.getElementById('selectAll')).onclick = function (): void {
const checkboxes: NodeListOf<HTMLInputElement> = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]');
for (const i in checkboxes) {
for (let i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = (<HTMLInputElement>this).checked;
}
checkCheckboxes();
};
(<HTMLInputElement>document.getElementById('deleteModalNotify')).onclick = function (): void {
@@ -186,11 +174,11 @@ const populateUsers = (): void => {
}
};
(<HTMLButtonElement>document.getElementById('accountsTabDelete')).onclick =function (): void {
const deleteButton: HTMLButtonElement = this;
(<HTMLButtonElement>document.getElementById('accountsTabDelete')).onclick = function (): void {
const deleteButton = this as HTMLButtonElement;
const checkboxes: NodeListOf<HTMLInputElement> = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]:checked');
let selected: Array<string> = new Array(checkboxes.length);
for (const i in checkboxes){
for (let i = 0; i < checkboxes.length; i++) {
selected[i] = checkboxes[i].id.replace("select_", "");
}
let title = " user";
@@ -203,16 +191,16 @@ const populateUsers = (): void => {
msg += " of account deletion";
document.getElementById('deleteModalTitle').textContent = title;
const dmNotify: HTMLInputElement = document.getElementById('deleteModalNotify')
const dmNotify = document.getElementById('deleteModalNotify') as HTMLInputElement;
dmNotify.checked = false;
document.getElementById('deleteModalNotifyLabel').textContent = msg;
const dmReason: HTMLTextAreaElement = document.getElementById('deleteModalReason')
const dmReason = document.getElementById('deleteModalReason') as HTMLTextAreaElement;
dmReason.value = '';
Unfocus(document.getElementById('deleteModalReasonBox'));
const dmSend: HTMLButtonElement = document.getElementById('deleteModalSend');
const dmSend = document.getElementById('deleteModalSend') as HTMLButtonElement;
dmSend.textContent = 'Delete';
dmSend.onclick = function (): void {
const button: HTMLButtonElement = this;
const button = this as HTMLButtonElement;
const send = {
'users': selected,
'notify': dmNotify.checked,
@@ -220,12 +208,12 @@ const populateUsers = (): void => {
};
_post("/deleteUser", send, function (): void {
if (this.readyState == 4) {
if (this.status == '500') {
if ("error" in req.reponse) {
if (this.status == 500) {
if ("error" in this.reponse) {
button.textContent = 'Failed';
} else {
button.textContent = 'Partial fail (check console)';
console.log(req.response);
console.log(this.response);
}
setTimeout((): void => {
Unfocus(deleteButton);
@@ -248,7 +236,7 @@ const populateUsers = (): void => {
(<HTMLButtonElement>document.getElementById('accountsTabSetDefaults')).onclick = function (): void {
const checkboxes: NodeListOf<HTMLInputElement> = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]:checked');
let userIDs: Array<string> = new Array(checkboxes.length);
for (const i in checkboxes){
for (let i = 0; i < checkboxes.length; i++){
userIDs[i] = checkboxes[i].id.replace("select_", "");
}
if (userIDs.length == 0) {
@@ -281,8 +269,9 @@ const populateUsers = (): void => {
});
(<HTMLButtonElement>document.getElementById('newUserCreate')).onclick = function (): void {
const ogText = this.textContent;
this.innerHTML = `
const button = this as HTMLButtonElement;
const ogText = button.textContent;
button.innerHTML = `
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Creating...
`;
const email: string = (<HTMLInputElement>document.getElementById('newUserEmail')).value;
@@ -299,23 +288,23 @@ const populateUsers = (): void => {
'password': password,
'email': email
};
const button: HTMLButtonElement = this;
_post("/newUserAdmin", send, function (): void {
if (this.readyState == 4) {
rmAttr(button, 'btn-primary');
if (this.status == '200') {
if (this.status == 200) {
addAttr(button, 'btn-success');
button.textContent = 'Success';
setTimeout((): void => {
rmAttr(button, 'btn-success');
addAttr('btn-primary');
addAttr(button, 'btn-primary');
button.textContent = ogText;
newUserModal.hide();
}, 1000);
populateUsers();
} else {
addAttr(button, 'btn-danger');
if ("error" in req.response) {
button.textContent = req.response["error"];
if ("error" in this.response) {
button.textContent = this.response["error"];
} else {
button.textContent = 'Failed';
}
@@ -324,6 +313,7 @@ const populateUsers = (): void => {
addAttr(button, 'btn-primary');
button.textContent = ogText;
}, 2000);
populateUsers();
}
}
});
@@ -337,3 +327,9 @@ const populateUsers = (): void => {
}
newUserModal.show();
};