treehouse/static/js/dev/picture-upload.js

150 lines
4.5 KiB
JavaScript
Raw Normal View History

2024-12-08 12:45:29 +01:00
class PictureUpload extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.tabIndex = 0;
this.gotoInit();
this.preview = this.querySelector("img[name='preview']");
this.addEventListener("click", (event) => {
if (event.target == this || event.target.parentElement == this) {
event.preventDefault();
this.focus();
}
});
this.addEventListener("paste", async (event) => {
if (event.clipboardData.items.length != 1) {
console.error("only one item is supported");
return;
}
let item = event.clipboardData.items[0];
await this.paste(item);
});
}
gotoInit() {
this.setState("init");
this.innerHTML = `
<div class="nothing-pasted">
paste or drop an image here to make a picture out of it
</div>
`;
}
async gotoHavePicture(imageType, imageFile) {
this.setState("have-picture");
this.innerHTML = `
<div class="have-picture">
<img name="preview" class="pic" alt="preview">
<p>
<span name="preview-width"></span> × <span name="preview-height"></span> px (<span name="file-size"></span>)
</p>
<p>
<label for="label">label</label>
<input name="label" type="text" placeholder="untitled"></input>
</p>
<p>
<label for="compression">compression</label>
<select name="compression">
<option value="Lossless">lossless</option>
</select>
</p>
<button name="upload">upload</button>
</div>
`;
let preview = this.querySelector("img[name='preview']");
let previewWidth = this.querySelector("[name='preview-width']");
let previewHeight = this.querySelector("[name='preview-height']");
let fileSize = this.querySelector("[name='file-size']");
let label = this.querySelector("[name='label']");
let compression = this.querySelector("[name='compression']");
let upload = this.querySelector("button[name='upload']");
fileSize.textContent = formatSizeSI(imageFile.size);
let url = URL.createObjectURL(imageFile);
preview.src = url;
createImageBitmap(imageFile).then((bitmap) => {
console.log(bitmap);
previewWidth.textContent = bitmap.width.toString();
previewHeight.textContent = bitmap.height.toString();
});
upload.addEventListener("click", async () => {
let params = new URLSearchParams({
label: label.value,
format: imageType,
compression: compression.value,
});
let response = await fetch(`/dev/picture-upload?${params}`, {
method: "POST",
body: imageFile,
});
let json = await response.json();
if (json.error != null) {
console.error(json.error);
} else {
await navigator.clipboard.writeText(json.ulid);
await this.gotoCopiedToClipboard();
}
});
}
async gotoCopiedToClipboard() {
this.setState("copied-to-clipboard");
this.innerHTML = `
<div class="copied-to-clipboard">ulid copied to clipboard; the window will now refresh</div>
`;
}
setState(name) {
this.setAttribute("data-state", name);
}
async paste(item) {
console.log(item);
if (!isSupportedImageType(item.type)) {
console.error("unsupported mime type", item.type);
return;
}
let file = item.getAsFile();
if (file == null) {
console.error("data transfer does not contain a file");
return;
}
await this.gotoHavePicture(item.type, file);
}
}
customElements.define("th-picture-upload", PictureUpload);
function isSupportedImageType(mime) {
return (
mime == "image/png" ||
mime == "image/jpeg" ||
mime == "image/svg+xml" ||
mime == "image/webp"
);
}
function formatSizeSI(bytes) {
return new Intl.NumberFormat(undefined, {
style: "unit",
unit: "byte",
notation: "compact",
unitDisplay: "narrow",
}).format(bytes);
}