Fix a bug where, if you used the bookmarklet to upload a file, and you clicked on the back button on the upload tagging page, then you would be taken back to the upload page, which would autosubmit the upload again. Now if you click the back button on the upload tagging page, you'll be taken back to the page where you used the bookmarklet, not the upload page.
152 lines
4.6 KiB
JavaScript
152 lines
4.6 KiB
JavaScript
import Dropzone from 'dropzone';
|
|
import Utility from "../../javascript/src/javascripts/utility.js";
|
|
import capitalize from "lodash/capitalize";
|
|
|
|
export default class FileUploadComponent {
|
|
static initialize() {
|
|
$(".file-upload-component").toArray().forEach(element => {
|
|
new FileUploadComponent($(element));
|
|
});
|
|
}
|
|
|
|
constructor($component) {
|
|
this.$component = $component;
|
|
this.$component.on("ajax:success", e => this.onSubmit(e));
|
|
this.$component.on("ajax:error", e => this.onError(e));
|
|
this.$dropTarget.on("paste.danbooru", e => this.onPaste(e));
|
|
this.dropzone = this.initializeDropzone();
|
|
|
|
// If the source field is pre-filled, then immediately submit the upload.
|
|
if (/^https?:\/\//.test(this.$sourceField.val())) {
|
|
this.$component.find("input[type='submit']").click();
|
|
}
|
|
}
|
|
|
|
initializeDropzone() {
|
|
if (!window.FileReader) {
|
|
this.$dropzone.addClass("hidden");
|
|
this.$component.find("input[type='file']").removeClass("hidden");
|
|
return null;
|
|
}
|
|
|
|
let dropzone = new Dropzone(this.$dropTarget.get(0), {
|
|
url: "/uploads.json",
|
|
paramName: "upload[file]",
|
|
clickable: this.$dropzone.get(0),
|
|
previewsContainer: this.$dropzone.get(0),
|
|
thumbnailHeight: null,
|
|
thumbnailWidth: null,
|
|
addRemoveLinks: false,
|
|
maxFiles: 1,
|
|
maxFilesize: this.maxFileSize,
|
|
maxThumbnailFilesize: this.maxFileSize,
|
|
timeout: 0,
|
|
acceptedFiles: "image/jpeg,image/png,image/gif,video/mp4,video/webm",
|
|
previewTemplate: this.$component.find(".dropzone-preview-template").html(),
|
|
});
|
|
|
|
dropzone.on("complete", file => {
|
|
this.$dropzone.find(".dz-progress").hide();
|
|
});
|
|
|
|
dropzone.on("addedfile", file => {
|
|
this.$dropzone.removeClass("error");
|
|
this.$dropzone.find(".dropzone-hint").hide();
|
|
|
|
// Remove all files except the file just added.
|
|
dropzone.files.forEach(f => {
|
|
if (f !== file) {
|
|
dropzone.removeFile(f);
|
|
}
|
|
});
|
|
});
|
|
|
|
dropzone.on("success", file => {
|
|
this.$dropzone.addClass("success");
|
|
let upload = JSON.parse(file.xhr.response)
|
|
this.pollStatus(upload);
|
|
});
|
|
|
|
dropzone.on("error", (file, msg) => {
|
|
this.$dropzone.addClass("error");
|
|
});
|
|
|
|
return dropzone;
|
|
}
|
|
|
|
onPaste(e) {
|
|
let url = e.originalEvent.clipboardData.getData("text");
|
|
this.$component.find("input[name='upload[source]']:not([disabled])").val(url);
|
|
|
|
if (/^https?:\/\//.test(url)) {
|
|
this.$component.find("input[type='submit']:not([disabled])").click();
|
|
}
|
|
|
|
e.preventDefault();
|
|
}
|
|
|
|
onSubmit(e) {
|
|
let upload = e.originalEvent.detail[0];
|
|
this.pollStatus(upload);
|
|
}
|
|
|
|
// Called after the upload is submitted via AJAX. Polls the upload until it
|
|
// is complete, then redirects to the upload page.
|
|
async pollStatus(upload) {
|
|
this.$component.find("progress").removeClass("hidden");
|
|
this.$component.find("input").attr("disabled", "disabled");
|
|
|
|
while (upload.status === "pending" || upload.status === "processing") {
|
|
await Utility.delay(500);
|
|
upload = await $.get(`/uploads/${upload.id}.json`);
|
|
}
|
|
|
|
if (upload.status === "completed") {
|
|
window.location.replace(`/uploads/${upload.id}`);
|
|
} else {
|
|
this.$dropzone.removeClass("success");
|
|
this.$component.find("progress").addClass("hidden");
|
|
this.$component.find("input").removeAttr("disabled");
|
|
|
|
Utility.error(upload.status);
|
|
}
|
|
}
|
|
|
|
// Called when creating the upload failed because of a validation error (normally, because the source URL was not a real URL).
|
|
async onError(e) {
|
|
let errors = e.originalEvent.detail[0].errors;
|
|
let message = Object.keys(errors).map(attribute => {
|
|
return errors[attribute].map(error => {
|
|
if (attribute === "base") {
|
|
return `${error}`;
|
|
} else {
|
|
return `${capitalize(attribute)} ${error}`;
|
|
}
|
|
});
|
|
}).join("; ");
|
|
|
|
Utility.error(message);
|
|
}
|
|
|
|
get $dropzone() {
|
|
return this.$component.find(".dropzone-container");
|
|
}
|
|
|
|
get $sourceField() {
|
|
return this.$component.find("input[name='upload[source]']");
|
|
}
|
|
|
|
get maxFileSize() {
|
|
return Number(this.$component.attr("data-max-file-size")) / (1024 * 1024);
|
|
}
|
|
|
|
// The element to listen for drag and drop events and paste events. By default,
|
|
// it's the `.file-upload-component` element. If `data-drop-target` is the `body`
|
|
// element, then you can drop images or paste URLs anywhere on the page.
|
|
get $dropTarget() {
|
|
return $(this.$component.attr("data-drop-target") || this.$component);
|
|
}
|
|
}
|
|
|
|
$(FileUploadComponent.initialize);
|