Convert frontend js to ts
This commit is contained in:
parent
83ab56b4ac
commit
aa8735cf23
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"bundles": {
|
"bundles": {
|
||||||
"app": "ts/app.ts",
|
"app": "ts/app.ts",
|
||||||
"fm": "js/fm.js",
|
"fm": "ts/fm.ts",
|
||||||
"url-shrinker": "js/url-shrinker.js",
|
"url-shrinker": "ts/url-shrinker.ts",
|
||||||
"layout": "sass/layout.scss",
|
"layout": "sass/layout.scss",
|
||||||
"error": "sass/error.scss",
|
"error": "sass/error.scss",
|
||||||
"logo": "img/logo.svg",
|
"logo": "img/logo.svg",
|
||||||
|
131
assets/js/fm.js
131
assets/js/fm.js
@ -1,131 +0,0 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const form = document.getElementById('upload-form');
|
|
||||||
if (!form) return;
|
|
||||||
const upload = document.getElementById('file-upload');
|
|
||||||
const uploadLink = document.getElementById('file-upload-link');
|
|
||||||
|
|
||||||
const uploadField = document.getElementById('field-upload');
|
|
||||||
|
|
||||||
const neverExpireCheckbox = document.getElementById('field-never_expire');
|
|
||||||
const expireAfterDaysField = document.getElementById('field-expire_after_days');
|
|
||||||
|
|
||||||
const autogenUrlCheckbox = document.getElementById('field-autogen_url');
|
|
||||||
const slugField = document.getElementById('field-slug');
|
|
||||||
|
|
||||||
neverExpireCheckbox.addEventListener('change', () => {
|
|
||||||
expireAfterDaysField.disabled = neverExpireCheckbox.checked;
|
|
||||||
});
|
|
||||||
|
|
||||||
autogenUrlCheckbox.addEventListener('change', () => {
|
|
||||||
slugField.disabled = autogenUrlCheckbox.checked;
|
|
||||||
});
|
|
||||||
|
|
||||||
let uploadForm;
|
|
||||||
|
|
||||||
form.addEventListener('submit', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!uploadForm || uploadForm.isFinished()) {
|
|
||||||
uploadForm = new UploadForm(form, upload, uploadLink, uploadField.files[0].name);
|
|
||||||
uploadForm.updateView();
|
|
||||||
uploadForm.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function UploadForm(form, upload, uploadLink, fileName) {
|
|
||||||
this.form = form;
|
|
||||||
this.upload = upload;
|
|
||||||
this.uploadLink = uploadLink;
|
|
||||||
this.fileName = fileName;
|
|
||||||
this.progressBar = this.upload.querySelector('.progress-bar');
|
|
||||||
this.progressBarContent = this.progressBar.querySelector('.content');
|
|
||||||
this.status = this.upload.querySelector('.status');
|
|
||||||
this.speed = this.status.querySelector('.speed');
|
|
||||||
this.finished = false;
|
|
||||||
|
|
||||||
this.xferSpeed = [];
|
|
||||||
this.lastTransferTime = null;
|
|
||||||
|
|
||||||
this.xhr = new XMLHttpRequest();
|
|
||||||
this.xhr.responseType = 'json';
|
|
||||||
this.xhr.upload.addEventListener('progress', e => {
|
|
||||||
if (e.lengthComputable) {
|
|
||||||
this.progressBar.classList.remove('undefined');
|
|
||||||
let percent = ((e.loaded / e.total) * 100).toFixed(2) + '%';
|
|
||||||
this.progressBar.style = `--progress: ${percent}`;
|
|
||||||
this.progressBarContent.innerText = percent;
|
|
||||||
this.updateSpeed(e.loaded);
|
|
||||||
} else {
|
|
||||||
this.progressBar.classList.add('undefined');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.xhr.upload.addEventListener('loadstart', () => {
|
|
||||||
this.status.classList.remove('hidden');
|
|
||||||
});
|
|
||||||
this.xhr.addEventListener('load', () => {
|
|
||||||
this.finished = true;
|
|
||||||
let response = this.xhr.response;
|
|
||||||
console.log('done', response);
|
|
||||||
if (response.status === 'error') {
|
|
||||||
if (response.messages) {
|
|
||||||
this.restoreView();
|
|
||||||
window.applyFormMessages(this.form, response.messages);
|
|
||||||
}
|
|
||||||
} else if (response.url) {
|
|
||||||
this.status.innerHTML = 'Done!';
|
|
||||||
this.uploadLink.querySelector('.content').innerText = response.url;
|
|
||||||
this.uploadLink.classList.remove('hidden');
|
|
||||||
} else {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.xhr.addEventListener('error', (e) => {
|
|
||||||
this.finished = true;
|
|
||||||
console.error('error', e);
|
|
||||||
this.status.innerHTML = 'Error; upload was interrupted.';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
UploadForm.prototype.isFinished = function () {
|
|
||||||
return this.finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
UploadForm.prototype.updateView = function () {
|
|
||||||
this.upload.querySelector('.name').innerText = this.fileName;
|
|
||||||
this.form.classList.add('hidden');
|
|
||||||
this.upload.classList.remove('hidden');
|
|
||||||
this.status.innerHTML = `Uploading @ <span class="speed">--</span>`;
|
|
||||||
this.speed = this.status.querySelector('.speed');
|
|
||||||
}
|
|
||||||
|
|
||||||
UploadForm.prototype.restoreView = function () {
|
|
||||||
this.status.classList.add('hidden');
|
|
||||||
this.upload.classList.add('hidden');
|
|
||||||
this.form.classList.remove('hidden');
|
|
||||||
};
|
|
||||||
|
|
||||||
UploadForm.prototype.start = function () {
|
|
||||||
const formData = new FormData(this.form);
|
|
||||||
this.xhr.open('POST', this.form.action);
|
|
||||||
this.xhr.send(formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const units = ['K', 'M', 'G', 'T'];
|
|
||||||
UploadForm.prototype.updateSpeed = function (loaded) {
|
|
||||||
const time = new Date().getTime();
|
|
||||||
if (this.lastTransferTime) {
|
|
||||||
this.xferSpeed.push((loaded - this.lastLoaded) / (time - this.lastTransferTime));
|
|
||||||
|
|
||||||
if (this.xferSpeed.length > 100) this.xferSpeed = this.xferSpeed.slice(1);
|
|
||||||
|
|
||||||
let speed = this.xferSpeed.reduce((v, c) => v + c) / this.xferSpeed.length;
|
|
||||||
let unit = 0;
|
|
||||||
while (speed >= 1000 && unit < units.length - 1) {
|
|
||||||
speed /= 1000;
|
|
||||||
unit++;
|
|
||||||
}
|
|
||||||
this.speed.innerText = (speed).toFixed(2) + units[unit] + 'Bps';
|
|
||||||
}
|
|
||||||
this.lastTransferTime = time;
|
|
||||||
this.lastLoaded = loaded;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const form = document.getElementById('url-shrink-form');
|
|
||||||
if (!form) return;
|
|
||||||
|
|
||||||
const autogenUrlCheckbox = document.getElementById('field-autogen_url');
|
|
||||||
const slugField = document.getElementById('field-slug');
|
|
||||||
|
|
||||||
autogenUrlCheckbox.addEventListener('change', () => {
|
|
||||||
slugField.disabled = autogenUrlCheckbox.checked;
|
|
||||||
});
|
|
||||||
});
|
|
171
assets/ts/fm.ts
Normal file
171
assets/ts/fm.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import {applyFormMessages} from "./forms";
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const form = document.querySelector<HTMLFormElement>('#upload-form');
|
||||||
|
if (!form) return;
|
||||||
|
const upload = document.getElementById('file-upload');
|
||||||
|
const uploadLink = document.querySelector<HTMLLinkElement>('#file-upload-link');
|
||||||
|
|
||||||
|
const uploadField = document.querySelector<HTMLInputElement>('#field-upload');
|
||||||
|
|
||||||
|
const neverExpireCheckbox = document.querySelector<HTMLInputElement>('#field-never_expire');
|
||||||
|
const expireAfterDaysField = document.querySelector<HTMLInputElement>('#field-expire_after_days');
|
||||||
|
|
||||||
|
const autogenUrlCheckbox = document.querySelector<HTMLInputElement>('#field-autogen_url');
|
||||||
|
const slugField = document.querySelector<HTMLInputElement>('#field-slug');
|
||||||
|
|
||||||
|
if (expireAfterDaysField) {
|
||||||
|
neverExpireCheckbox?.addEventListener('change', () => {
|
||||||
|
expireAfterDaysField.disabled = neverExpireCheckbox.checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slugField) {
|
||||||
|
autogenUrlCheckbox?.addEventListener('change', () => {
|
||||||
|
slugField.disabled = autogenUrlCheckbox.checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let uploadForm: UploadForm | undefined;
|
||||||
|
|
||||||
|
form.addEventListener('submit', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (upload && uploadLink && uploadField && uploadField.files && (!uploadForm || uploadForm.isFinished())) {
|
||||||
|
uploadForm = new UploadForm(form, upload, uploadLink, uploadField.files[0].name);
|
||||||
|
uploadForm.updateView();
|
||||||
|
uploadForm.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const units = ['K', 'M', 'G', 'T'];
|
||||||
|
|
||||||
|
class UploadForm {
|
||||||
|
private finished: boolean = false;
|
||||||
|
private readonly progressBar: HTMLElement | null;
|
||||||
|
private readonly progressBarContent: HTMLElement | null;
|
||||||
|
private readonly status: HTMLElement | null;
|
||||||
|
private speed: HTMLElement | null;
|
||||||
|
private xferSpeed: number[] = [];
|
||||||
|
private lastTransferTime: number | null = null;
|
||||||
|
private lastLoaded: number = 0;
|
||||||
|
|
||||||
|
private xhr: XMLHttpRequest;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private form: HTMLFormElement,
|
||||||
|
private upload: HTMLElement,
|
||||||
|
private uploadLink: HTMLLinkElement,
|
||||||
|
private fileName: string,
|
||||||
|
) {
|
||||||
|
this.progressBar = this.upload.querySelector('.progress-bar');
|
||||||
|
this.progressBarContent = this.progressBar?.querySelector('.content') || null;
|
||||||
|
this.status = this.upload.querySelector('.status');
|
||||||
|
this.speed = this.status?.querySelector('.speed') || null;
|
||||||
|
|
||||||
|
if (!this.progressBar)
|
||||||
|
throw new Error('Invalid html');
|
||||||
|
|
||||||
|
this.xhr = new XMLHttpRequest();
|
||||||
|
this.xhr.responseType = 'json';
|
||||||
|
this.xhr.upload.addEventListener('progress', e => {
|
||||||
|
if (this.progressBar && this.progressBarContent) {
|
||||||
|
if (e.lengthComputable) {
|
||||||
|
this.progressBar.classList.remove('undefined');
|
||||||
|
const percent = (e.loaded / e.total * 100).toFixed(2) + '%';
|
||||||
|
this.progressBar.style.setProperty('--progress', `${percent}`);
|
||||||
|
this.progressBarContent.innerText = percent;
|
||||||
|
this.updateSpeed(e.loaded);
|
||||||
|
} else {
|
||||||
|
this.progressBar.classList.add('undefined');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.xhr.upload.addEventListener('loadstart', () => {
|
||||||
|
this.status?.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
this.xhr.addEventListener('load', () => {
|
||||||
|
this.finished = true;
|
||||||
|
const response = this.xhr.response;
|
||||||
|
console.log('done', response);
|
||||||
|
if (response.status === 'error') {
|
||||||
|
if (response.messages) {
|
||||||
|
this.restoreView();
|
||||||
|
applyFormMessages(this.form, response.messages);
|
||||||
|
}
|
||||||
|
} else if (response.url) {
|
||||||
|
if (this.status) {
|
||||||
|
this.status.innerHTML = 'Done!';
|
||||||
|
}
|
||||||
|
const uploadLinkContent = this.uploadLink.querySelector<HTMLElement>('.content');
|
||||||
|
if (uploadLinkContent) {
|
||||||
|
uploadLinkContent.innerText = response.url;
|
||||||
|
}
|
||||||
|
this.uploadLink.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.xhr.addEventListener('error', (e) => {
|
||||||
|
this.finished = true;
|
||||||
|
console.error('error', e);
|
||||||
|
if (this.status) {
|
||||||
|
this.status.innerHTML = 'Error; upload was interrupted.';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFinished(): boolean {
|
||||||
|
return this.finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateView(): void {
|
||||||
|
const uploadName = this.upload.querySelector<HTMLElement>('.name');
|
||||||
|
if (uploadName) {
|
||||||
|
uploadName.innerText = this.fileName;
|
||||||
|
}
|
||||||
|
this.form.classList.add('hidden');
|
||||||
|
this.upload.classList.remove('hidden');
|
||||||
|
if (this.status) {
|
||||||
|
this.status.innerHTML = `Uploading @ <span class="speed">--</span>`;
|
||||||
|
this.speed = this.status.querySelector('.speed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public restoreView(): void {
|
||||||
|
if (this.status) {
|
||||||
|
this.status.classList.add('hidden');
|
||||||
|
}
|
||||||
|
this.upload.classList.add('hidden');
|
||||||
|
this.form.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(): void {
|
||||||
|
const formData = new FormData(this.form);
|
||||||
|
this.xhr.open('POST', this.form.action);
|
||||||
|
this.xhr.send(formData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSpeed(loaded: number): void {
|
||||||
|
const time = new Date().getTime();
|
||||||
|
if (this.lastTransferTime) {
|
||||||
|
this.xferSpeed.push((loaded - this.lastLoaded) / (time - this.lastTransferTime));
|
||||||
|
|
||||||
|
if (this.xferSpeed.length > 100) this.xferSpeed = this.xferSpeed.slice(1);
|
||||||
|
|
||||||
|
let speed = this.xferSpeed.reduce((v, c) => v + c) / this.xferSpeed.length;
|
||||||
|
let unit = 0;
|
||||||
|
while (speed >= 1000 && unit < units.length - 1) {
|
||||||
|
speed /= 1000;
|
||||||
|
unit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.speed) {
|
||||||
|
this.speed.innerText = speed.toFixed(2) + units[unit] + 'Bps';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.lastTransferTime = time;
|
||||||
|
this.lastLoaded = loaded;
|
||||||
|
}
|
||||||
|
}
|
13
assets/ts/url-shrinker.ts
Normal file
13
assets/ts/url-shrinker.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const form = document.getElementById('url-shrink-form');
|
||||||
|
if (!form) return;
|
||||||
|
|
||||||
|
const autogenUrlCheckbox = document.querySelector<HTMLInputElement>('#field-autogen_url');
|
||||||
|
const slugField = document.querySelector<HTMLInputElement>('#field-slug');
|
||||||
|
|
||||||
|
if (slugField) {
|
||||||
|
autogenUrlCheckbox?.addEventListener('change', () => {
|
||||||
|
slugField.disabled = autogenUrlCheckbox.checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user