176 lines
5.3 KiB
HTML
176 lines
5.3 KiB
HTML
<div id="new-upload-container" class="flex flex-col md:flex-row gap-4">
|
|
<div class="panel thin gap-2">
|
|
<h1 class="heading">New upload</h1>
|
|
|
|
<form id="upload-form" class="form" _="on submit halt the event then call handleUploadSubmit(me)">
|
|
<input type="file" class="field" name="file" multiple _="on change call handleUploadFieldChange(event)">
|
|
<div class="progress-container flex flex-row gap-2 hidden">
|
|
<progress id="progress" value="0" max="100" class="grow"></progress>
|
|
<div class="text-right" style="min-width: 8rem"></div>
|
|
</div>
|
|
<div class="buttons end mt-4">
|
|
<button type="submit" class="button" disabled>
|
|
{% include "icons/lucide/upload.svg" %}
|
|
Upload file
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="panel thin gap-2">
|
|
<div class="flex flex-row justify-between align-middle mb-auto">
|
|
<h1 class="heading">Available space</h1>
|
|
<div>
|
|
<button
|
|
id="space-refresh"
|
|
type="button"
|
|
class="button"
|
|
hx-trigger="click,refresh-event"
|
|
hx-get="/uploads/new"
|
|
hx-target="#new-upload-container"
|
|
hx-select="#new-upload-container"
|
|
hx-swap="outerHTML">
|
|
{% include "icons/lucide/refresh-cw.svg" %}
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-col gap-2">
|
|
<div class="flex flex-row gap-2 justify-end">
|
|
<div>Used</div>
|
|
<div>{{ stats.size | filesizeformat }}</div>
|
|
<div>
|
|
/
|
|
{% if user.limit %}
|
|
{{ user.limit | filesizeformat }}
|
|
{% else %}
|
|
∞
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<progress value="{{ stats.size }}" max="{{ user.limit | default(value = 0) }}" class=""></progress>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function handleUploadFieldChange(event) {
|
|
console.log("Number of selected files changed to", event.target.files.length);
|
|
const form = document.querySelector("#upload-form");
|
|
form.querySelector("button[type='submit']").disabled = event.target.files.length === 0;
|
|
}
|
|
|
|
function handleUploadSubmit(form) {
|
|
const input = form.querySelector("input[type='file']");
|
|
const submit = form.querySelector("button[type='submit']");
|
|
const progressContainer = form.querySelector(".progress-container");
|
|
const progressElement = progressContainer.querySelector("progress");
|
|
const progressText = progressContainer.querySelector("div");
|
|
|
|
function getErrorElement() {
|
|
const existing = form.querySelector("#upload-form > #error");
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
|
|
const element = document.createElement("DIV");
|
|
element.classNames.add("text-danger");
|
|
form.appendChild(element);
|
|
|
|
return element;
|
|
}
|
|
|
|
function setError(message) {
|
|
progressContainer.classList.add("hidden")
|
|
getErrorElement().innerHTML = message;
|
|
}
|
|
|
|
submit.disabled = true;
|
|
progressElement.value = 0;
|
|
progressText.innerHTML = "";
|
|
|
|
let total_files = 0, total_size = 0;
|
|
const form_data = new FormData();
|
|
|
|
for (let field of form.elements) {
|
|
if (field.tagName !== "INPUT") {
|
|
continue;
|
|
}
|
|
|
|
if (field.type === "file") {
|
|
for (let file of field.files) {
|
|
total_files += 1;
|
|
total_size += file.size;
|
|
form_data.append("file", file);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (total_files === 0) {
|
|
console.warn("No files selected, not submitting form");
|
|
return;
|
|
}
|
|
|
|
let factor = 1, unit, digits = 0;
|
|
if (total_size > 1024 * 1024 * 1024) {
|
|
unit = "gigabyte";
|
|
factor = 1024 * 1024 * 1024;
|
|
digits = 2;
|
|
} else if (total_size > 1024 * 1024) {
|
|
unit = "megabyte";
|
|
factor = 1024 * 1024;
|
|
} else if (total_size > 1024) {
|
|
unit = "kilobyte";
|
|
factor = 1024;
|
|
} else {
|
|
unit = "byte";
|
|
factor = 1;
|
|
}
|
|
|
|
let formatter = new Intl.NumberFormat(undefined, {
|
|
style: "unit",
|
|
unit: unit,
|
|
unitDisplay: "short",
|
|
minimumFractionDigits: digits,
|
|
maximumFractionDigits: digits,
|
|
});
|
|
|
|
const request = new XMLHttpRequest();
|
|
|
|
request.addEventListener("load", (event) => {
|
|
console.log("Upload finished");
|
|
htmx.trigger("#space-refresh", "refresh-event", {});
|
|
htmx.trigger("#upload-refresh", "refresh-event", {});
|
|
|
|
input.value = null;
|
|
progressElement.value = 0;
|
|
progressText.innerHTML = "";
|
|
progressContainer.classList.add("hidden");
|
|
submit.disabled = true;
|
|
});
|
|
|
|
request.addEventListener("error", (event) => {
|
|
console.error("Failed to upload file", event);
|
|
setError("Encountered an error uploading the file");
|
|
});
|
|
|
|
request.addEventListener("abort", (event) => {
|
|
console.warn("Upload was aborted", event);
|
|
setError("Upload was aborted");
|
|
});
|
|
|
|
request.upload.addEventListener("progress", (event) => {
|
|
const amount = Math.round(event.loaded / total_size * 100.0);
|
|
progressElement.value = amount;
|
|
progressText.innerHTML =
|
|
formatter.format(event.loaded / factor) + " / " +
|
|
formatter.format(total_size / factor);
|
|
})
|
|
|
|
progressContainer.classList.remove("hidden");
|
|
|
|
console.log("Starting upload of", total_files, "files with a total size of", total_size, "bytes");
|
|
request.open("POST", "/uploads");
|
|
request.send(form_data);
|
|
}
|
|
</script>
|