76 lines
2.3 KiB
HTML
76 lines
2.3 KiB
HTML
<!--
|
|
Profile picture upload widget.
|
|
Drop into a Content: block.
|
|
|
|
Client-side, this only checks that the file is *some* readable image -
|
|
no type or dimension restriction, since the server now accepts any
|
|
recognizable image format, center-crops it to square, downscales to
|
|
32x32, and always transcodes to GIF. The username is derived from the
|
|
session cookie server-side, never from the client.
|
|
-->
|
|
<div id="pfp-upload">
|
|
<img id="pfp-preview" src="/Images/default_pfp.gif" alt="Profile picture preview"
|
|
style="width:64px; height:64px; image-rendering:pixelated; display:block; margin-bottom:8px; border:1px solid #888;">
|
|
|
|
<input type="file" id="pfp-file" accept="image/*">
|
|
|
|
<p id="pfp-status" style="margin-top:8px;"></p>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const fileInput = document.getElementById("pfp-file");
|
|
const preview = document.getElementById("pfp-preview");
|
|
const status = document.getElementById("pfp-status");
|
|
|
|
function setStatus(msg, isError) {
|
|
status.textContent = msg;
|
|
status.style.color = isError ? "#c0392b" : "#2c7a2c";
|
|
}
|
|
|
|
fileInput.addEventListener("change", async () => {
|
|
const file = fileInput.files[0];
|
|
if (!file) return;
|
|
|
|
setStatus("Checking image...", false);
|
|
|
|
let objectUrl;
|
|
try {
|
|
// Just confirm the browser can decode it as an image at all - the
|
|
// actual format whitelist, cropping, and resizing happens server-side.
|
|
await new Promise((resolve, reject) => {
|
|
objectUrl = URL.createObjectURL(file);
|
|
const img = new Image();
|
|
img.onload = () => resolve();
|
|
img.onerror = () => reject(new Error("That doesn't look like a readable image."));
|
|
img.src = objectUrl;
|
|
});
|
|
|
|
// Looks good locally - show the preview immediately.
|
|
preview.src = objectUrl;
|
|
|
|
setStatus("Uploading...", false);
|
|
|
|
const response = await fetch("/upload?name=profileimages", {
|
|
method: "POST",
|
|
credentials: "same-origin", // send the session cookie
|
|
body: file,
|
|
});
|
|
|
|
const text = await response.text();
|
|
|
|
if (!response.ok) {
|
|
setStatus("Upload failed: " + text, true);
|
|
return;
|
|
}
|
|
|
|
setStatus("Profile picture updated!", false);
|
|
} catch (err) {
|
|
setStatus(err.message || "Something went wrong.", true);
|
|
} finally {
|
|
fileInput.value = "";
|
|
}
|
|
});
|
|
})();
|
|
</script>
|