166 lines
4.6 KiB
TypeScript
166 lines
4.6 KiB
TypeScript
class DropIndicator {
|
|
private element: HTMLElement;
|
|
private visible: boolean = false;
|
|
private start: EventTarget;
|
|
|
|
constructor() {
|
|
this.element = document.getElementById("drop-indicator");
|
|
|
|
this.element.addEventListener("animationend", () => {
|
|
if (this.element.classList.contains("closing")) {
|
|
this.element.classList.remove("closing");
|
|
this.element.classList.add("invisible");
|
|
} else if (this.element.classList.contains("opening")) {
|
|
this.element.classList.remove("opening");
|
|
}
|
|
});
|
|
}
|
|
|
|
public onDragEnter(event: DragEvent) {
|
|
this.start = event.target;
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.show();
|
|
}
|
|
|
|
public onDragLeave(event: DragEvent) {
|
|
if (this.start === event.target) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.hide(true);
|
|
}
|
|
}
|
|
|
|
show() {
|
|
if (this.visible) {
|
|
return;
|
|
}
|
|
|
|
this.element.classList.remove("invisible");
|
|
this.element.classList.add("opening");
|
|
this.visible = true;
|
|
}
|
|
|
|
hide(animated: boolean) {
|
|
if (!this.visible) {
|
|
return;
|
|
}
|
|
|
|
if (animated) {
|
|
this.element.classList.add("closing");
|
|
} else {
|
|
this.element.classList.add("invisible");
|
|
}
|
|
|
|
this.visible = false;
|
|
}
|
|
}
|
|
|
|
let DROP_INDICATOR: DropIndicator = null;
|
|
function getDropIndicator(): DropIndicator {
|
|
if (!DROP_INDICATOR) {
|
|
DROP_INDICATOR = new DropIndicator();
|
|
}
|
|
|
|
return DROP_INDICATOR;
|
|
}
|
|
|
|
document.body.addEventListener("parcelUploadDeleted", () => {
|
|
htmx.trigger("#upload-stats-container", "refresh");
|
|
});
|
|
|
|
document.body.addEventListener("parcelUploadChanged", (event: CustomEvent) => {
|
|
const row = document.getElementById("upload-row-" + event.detail.value);
|
|
const page = row.dataset.page;
|
|
const order = row.dataset.order;
|
|
const asc = row.dataset.asc;
|
|
|
|
htmx.ajax(
|
|
"get",
|
|
"/uploads/list/" + page + "?order=" + order + "&asc=" + asc,
|
|
{
|
|
target: "#upload-row-" + event.detail.value,
|
|
select: "#upload-row-" + event.detail.value,
|
|
swap: "outerHTML",
|
|
},
|
|
);
|
|
});
|
|
|
|
// Always prevent the default action.
|
|
document.body.addEventListener("dragover", (event: DragEvent) => {
|
|
event.preventDefault();
|
|
});
|
|
|
|
document.body.addEventListener("dragenter", (event: DragEvent) => {
|
|
// First we want to see if we already have a `<parcel-upload-form>` in the DOM. If we do, then we
|
|
// don't need to do anything here, as the form handles this event.
|
|
if (document.querySelector("parcel-upload-form")) {
|
|
return;
|
|
}
|
|
|
|
getDropIndicator().onDragEnter(event);
|
|
});
|
|
|
|
document.body.addEventListener("dragleave", (event: DragEvent) => {
|
|
// As with 'handleDragOver', we're not going to operate if we have a `<parcel-upload-form>` in the
|
|
// DOM, as that'll handle the event.
|
|
if (document.querySelector("parcel-upload-form")) {
|
|
return;
|
|
}
|
|
|
|
getDropIndicator().onDragLeave(event);
|
|
});
|
|
|
|
document.body.addEventListener("drop", (event: DragEvent) => {
|
|
// The user has dropped some files directly into the index page. First off, we want to see if
|
|
// there is already a `<parcel-upload-form>` that can handle that for us.
|
|
if (document.querySelector("parcel-upload-form")) {
|
|
return;
|
|
}
|
|
|
|
// First we want to prevent the default process for the event.
|
|
event.preventDefault();
|
|
|
|
// Hide the drop indicator, but don't animate.
|
|
getDropIndicator().hide(false);
|
|
|
|
const files = [...event.dataTransfer.items]
|
|
.filter((item) => item.kind === "file")
|
|
.map((item) => item.getAsFile());
|
|
|
|
// There is no form, present, so we need to load one. We can do that with HTMX. We tell the upload
|
|
// form not to bother animating in.
|
|
htmx
|
|
.ajax("get", "/uploads/new?immediate=true", {
|
|
target: "body",
|
|
swap: "beforeend",
|
|
})
|
|
.then(() => {
|
|
// Now we can get at the `<upload-form>` and tell it about our dropped files. However the
|
|
// event receiver will not mount immediately: whilst HTMX things things are on their way to
|
|
// being settled, we would still have to wait for the upload form to populate and connect
|
|
// itself together.
|
|
|
|
let count = 0;
|
|
|
|
const interval = window.setInterval(() => {
|
|
const receiver = document.querySelector(
|
|
"parcel-upload-form > .event-receiver",
|
|
);
|
|
if (receiver) {
|
|
window.clearInterval(interval);
|
|
receiver.dispatchEvent(
|
|
new CustomEvent("parcelDrop", {
|
|
detail: { files },
|
|
}),
|
|
);
|
|
} else if (count > 10) {
|
|
console.error("Failed to find event receiver in upload form");
|
|
window.clearInterval(interval);
|
|
} else {
|
|
count++;
|
|
}
|
|
}, 100);
|
|
});
|
|
});
|