158 lines
6.0 KiB
JavaScript
158 lines
6.0 KiB
JavaScript
class EventFileList extends Shadow {
|
||
constructor(existingAttachments, onDeleteExisting = null, onDeleteNew = null, onPreview = null) {
|
||
super();
|
||
this.existingAttachments = existingAttachments ?? [];
|
||
this.newFiles = [];
|
||
this.objectURLs = new Map();
|
||
this.onDeleteExisting = onDeleteExisting;
|
||
this.onDeleteNew = onDeleteNew;
|
||
this.onPreview = onPreview;
|
||
}
|
||
|
||
update(files) {
|
||
this.newFiles.push(...Array.from(files));
|
||
this.rerender();
|
||
}
|
||
|
||
removeExisting(fileId) {
|
||
this.existingAttachments = this.existingAttachments.filter(f => f.id !== fileId);
|
||
this.rerender();
|
||
}
|
||
|
||
removeNew(index) {
|
||
const file = this.newFiles[index];
|
||
if (this.objectURLs.has(file)) {
|
||
URL.revokeObjectURL(this.objectURLs.get(file));
|
||
this.objectURLs.delete(file);
|
||
}
|
||
this.newFiles.splice(index, 1);
|
||
this.rerender();
|
||
}
|
||
|
||
commitNew(insertedFiles) {
|
||
this.newFiles.forEach(file => {
|
||
if (this.objectURLs.has(file)) {
|
||
URL.revokeObjectURL(this.objectURLs.get(file));
|
||
this.objectURLs.delete(file);
|
||
}
|
||
});
|
||
this.newFiles = [];
|
||
this.existingAttachments = [...this.existingAttachments, ...insertedFiles];
|
||
this.rerender();
|
||
}
|
||
|
||
getObjectURL(file) {
|
||
if (!this.objectURLs.has(file)) {
|
||
this.objectURLs.set(file, URL.createObjectURL(file));
|
||
}
|
||
return this.objectURLs.get(file);
|
||
}
|
||
|
||
render() {
|
||
const hasFiles = this.existingAttachments.length > 0 || this.newFiles.length > 0;
|
||
this.style.display = hasFiles ? "flex" : "none";
|
||
this.style.padding = "1em";
|
||
this.style.paddingTop = "0.5em";
|
||
this.style.boxSizing = "border-box";
|
||
|
||
VStack(() => {
|
||
this.existingAttachments.forEach(file => {
|
||
const isImage = file.type?.startsWith("image/");
|
||
const url = `${config.SERVER}/db/images/events/${file.name}`
|
||
const row = HStack(() => {
|
||
if (isImage) {
|
||
img(`${config.UI}/db/images/events/${file.name}`, "1.5em", "1.5em")
|
||
.objectFit("cover")
|
||
.borderRadius(3, px)
|
||
.flexShrink(0)
|
||
} else {
|
||
span("📎")
|
||
}
|
||
span(file.original_name ?? file.name)
|
||
.overflow("hidden")
|
||
.textOverflow("ellipsis")
|
||
.whiteSpace("nowrap")
|
||
.flex(1)
|
||
|
||
span(file.size_bytes != null ? `${(file.size_bytes / 1024).toFixed(1)} KB` : "")
|
||
.opacity(0.5)
|
||
.flexShrink(0)
|
||
.fontSize(0.85, rem)
|
||
.width("5em")
|
||
|
||
if (this.onDeleteExisting) {
|
||
span("×")
|
||
.color("var(--quillred)")
|
||
.opacity(0.7)
|
||
.fontSize(1.2, em)
|
||
.fontWeight("600")
|
||
.flexShrink(0)
|
||
.cursor("pointer")
|
||
.padding(0.5, em)
|
||
.margin(-0.5, em)
|
||
.onTap((e) => { e?.stopPropagation(); if (window.isMobile() === true) this.onDeleteExisting(file.id) })
|
||
.onClick((done, e) => { e?.stopPropagation(); if (done && window.isMobile() === false) this.onDeleteExisting(file.id) })
|
||
}
|
||
})
|
||
.alignItems("center")
|
||
.gap(0.5, em)
|
||
if (this.onPreview) {
|
||
row.cursor("pointer")
|
||
.onClick((done) => { if (done) this.onPreview(file, url) })
|
||
}
|
||
})
|
||
|
||
this.newFiles.forEach((file, index) => {
|
||
const isImage = file.type.startsWith("image/");
|
||
const url = this.getObjectURL(file)
|
||
const row = HStack(() => {
|
||
if (isImage) {
|
||
img(url, "1.5em", "1.5em")
|
||
.objectFit("cover")
|
||
.borderRadius(3, px)
|
||
.flexShrink(0)
|
||
} else {
|
||
span("📎")
|
||
}
|
||
span(file.name)
|
||
.overflow("hidden")
|
||
.textOverflow("ellipsis")
|
||
.whiteSpace("nowrap")
|
||
.flex(1)
|
||
|
||
span(`${(file.size / 1024).toFixed(1)} KB`)
|
||
.opacity(0.5)
|
||
.flexShrink(0)
|
||
.fontSize(0.85, rem)
|
||
.width("5em")
|
||
|
||
if (this.onDeleteNew) {
|
||
span("×")
|
||
.color("var(--quillred)")
|
||
.opacity(0.7)
|
||
.fontSize(1.2, em)
|
||
.fontWeight("600")
|
||
.flexShrink(0)
|
||
.cursor("pointer")
|
||
.padding(0.5, em)
|
||
.margin(-0.5, em)
|
||
.onTap((e) => { e?.stopPropagation(); if (window.isMobile() === true) this.onDeleteNew(index) })
|
||
.onClick((done, e) => { e?.stopPropagation(); if (done && window.isMobile() === false) this.onDeleteNew(index) })
|
||
}
|
||
})
|
||
.alignItems("center")
|
||
.gap(0.5, em)
|
||
if (this.onPreview) {
|
||
row.cursor("pointer")
|
||
.onClick((done) => { if (done) this.onPreview(file, url) })
|
||
}
|
||
})
|
||
})
|
||
.gap(1, em)
|
||
.color("var(--text)")
|
||
.fontSize(0.85, rem)
|
||
.fontFamily("Arial")
|
||
}
|
||
}
|
||
register(EventFileList)
|