depot/web/fup/fupstatic/js/base.js

167 lines
5.4 KiB
JavaScript

// SPDX-FileCopyrightText: 2021 Luke Granger-Brown <depot@lukegb.com>
//
// SPDX-License-Identifier: Apache-2.0
document.body.classList.add('has-js');
if (document.body.classList.contains('upload-page')) {
const uploadListEl = document.body.querySelector('.upload-list');
const inputFileEl = document.body.querySelector('#file');
const expiryEl = document.body.querySelector('#expiry');
const uploadFile = (file, expiry) => {
const progressEl = document.createElement('li');
progressEl.classList.add('upload-list-element');
uploadListEl.appendChild(progressEl);
const bgEl = document.createElement('div');
bgEl.classList.add('upload-list-background');
progressEl.appendChild(bgEl);
const bgFilenameEl = document.createElement('span');
bgFilenameEl.classList.add('upload-list-filename');
bgFilenameEl.textContent = file.name;
bgEl.appendChild(bgFilenameEl);
const bgSpacerNode = document.createTextNode(' ');
bgEl.appendChild(bgSpacerNode);
const bgPercentEl = document.createElement('span');
bgPercentEl.classList.add('upload-list-progress');
bgPercentEl.textContent = file.size == 0 ? '(unknown)' : '(0%)';
bgEl.appendChild(bgPercentEl);
const barEl = document.createElement('div');
barEl.classList.add('upload-list-bar');
progressEl.appendChild(barEl);
const barContainerEl = document.createElement('div');
barContainerEl.classList.add('upload-list-bar-container');
barEl.appendChild(barContainerEl);
const barFilenameEl = document.createElement('span');
barFilenameEl.classList.add('upload-list-filename');
barFilenameEl.textContent = file.name;
barContainerEl.appendChild(barFilenameEl);
const barSpacerNode = document.createTextNode(' ');
barContainerEl.appendChild(barSpacerNode);
const barPercentEl = document.createElement('span');
barPercentEl.classList.add('upload-list-progress');
barPercentEl.textContent = file.size == 0 ? '(unknown)' : '(0%)';
barContainerEl.appendChild(barPercentEl);
const setPercentText = (txt) => {
barPercentEl.textContent = txt;
bgPercentEl.textContent = txt;
};
const setPercentPercent = (loaded, total) => {
const pct = Math.floor((loaded * 1000) / total) / 10;
setPercentText(`(${pct}%)`);
barEl.style.width = `${pct}%`;
};
const hdrs = new Headers();
hdrs.set('Content-Type', file.type);
hdrs.set('Accept', 'application/json');
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (ev) => {
if (!ev.lengthComputable) {
setPercentText(`(unknown: ${ev.loaded} bytes)`);
} else {
setPercentPercent(ev.loaded, ev.total);
}
});
xhr.upload.addEventListener('load', (ev) => {
setPercentPercent(1, 1);
});
xhr.addEventListener('error', (ev) => {
setPercentText(`(error: ${ev.message})`);
});
xhr.addEventListener('abort', (ev) => {
setPercentText(`(aborted)`);
});
xhr.addEventListener('load', (ev) => {
if (ev.status < 200 || ev.status >= 300) {
setPercentText(`(error: HTTP status ${ev.status} - ${ev.message})`);
return;
}
const respJSON = xhr.response;
while (progressEl.firstChild) {
progressEl.removeChild(progressEl.firstChild);
}
progressEl.classList.add('uploaded');
const linkEl = document.createElement('a');
linkEl.setAttribute('href', respJSON.display_url);
linkEl.textContent = file.name;
progressEl.appendChild(linkEl);
});
xhr.responseType = 'json';
xhr.open('PUT', `/upload/${encodeURIComponent(file.name)}`);
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('Accept', 'application/json');
if (expiry !== "") {
xhr.setRequestHeader('Fup-Expiry', expiry);
}
xhr.send(file);
};
inputFileEl.addEventListener('change', (ev) => {
for (let i = 0; i < inputFileEl.files.length; i++) {
const file = inputFileEl.files[i];
uploadFile(file, expiryEl.value);
}
inputFileEl.value = null;
});
document.body.addEventListener('dragenter', (e) => {
e.preventDefault();
e.stopPropagation();
document.body.classList.add('dragging-over');
}, false);
document.body.addEventListener('dragover', (e) => {
e.preventDefault();
e.stopPropagation();
document.body.classList.add('dragging-over');
}, false);
document.body.addEventListener('dragleave', (e) => {
e.preventDefault();
e.stopPropagation();
document.body.classList.remove('dragging-over');
}, false);
document.body.addEventListener('drop', (e) => {
e.preventDefault();
e.stopPropagation();
document.body.classList.remove('dragging-over');
const dt = e.dataTransfer;
const files = dt.files;
for (const f of files) {
uploadFile(f, expiryEl.value);
}
}, false);
document.body.addEventListener('paste', (e) => {
e.preventDefault();
const clipboardData = e.clipboardData || window.clipboardData;
for (const item of clipboardData.items) {
if (item.kind === 'file') {
uploadFile(item.getAsFile(), expiryEl.value);
} else if (item.kind === 'string') {
item.getAsString((data) => {
// This is a hack, we should do something... more sensible.
const uploadData = new Blob([data], { type: 'text/plain' });
uploadData.name = 'clipboard.txt';
uploadFile(uploadData, expiryEl.value);
});
}
}
});
}