From 1ecc3e3fa45e42be773bd25ba3209280750e6c5f Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sun, 15 Apr 2018 00:20:53 +0200 Subject: [PATCH] Improved file upload --- mixins/Input.pixy | 4 +- pages/editanime/images.pixy | 2 +- pages/settings/settings.pixy | 4 +- scripts/Actions/Upload.ts | 85 +++++++++++++++++++++--------------- utils/editform/editform.go | 4 +- 5 files changed, 58 insertions(+), 41 deletions(-) diff --git a/mixins/Input.pixy b/mixins/Input.pixy index 0c7d2ae9..c405e5b8 100644 --- a/mixins/Input.pixy +++ b/mixins/Input.pixy @@ -43,10 +43,10 @@ component InputSelection(id string, value string, label string, placeholder stri each option in options option(value=option.Value)= option.Label -component InputImage(id string, label string, endpoint string) +component InputFileUpload(id string, label string, uploadType string, endpoint string) .widget-section label(for=id)= label + ":" - button.action(data-action="selectFile", data-trigger="click", data-preview-image-id=id + "-preview", data-endpoint=endpoint) + button.action(id=id, data-action="selectFile", data-trigger="click", data-endpoint=endpoint, data-type=uploadType) Icon("upload") span Select file diff --git a/pages/editanime/images.pixy b/pages/editanime/images.pixy index d479bdfe..08b08384 100644 --- a/pages/editanime/images.pixy +++ b/pages/editanime/images.pixy @@ -9,7 +9,7 @@ component EditAnimeImages(anime *arn.Anime) Icon("picture-o") span Image - InputImage("anime-image-input", "File", "/api/upload/anime/" + anime.ID + "/image") + InputFileUpload("anime-image-input", "File", "image", "/api/upload/anime/" + anime.ID + "/image") .anime-image-container img#anime-image-input-preview.anime-cover-image.lazy(data-src=anime.ImageLink("large"), data-webp="true", data-color=anime.AverageColor(), alt="Anime image") \ No newline at end of file diff --git a/pages/settings/settings.pixy b/pages/settings/settings.pixy index 444af53f..472c48cb 100644 --- a/pages/settings/settings.pixy +++ b/pages/settings/settings.pixy @@ -55,7 +55,7 @@ component SettingsPersonal(user *arn.User) //- //- File upload //- if user.Settings().Avatar.Source == "FileSystem" - InputImage("avatar-input", "File", "/api/upload/avatar") + InputFileUpload("avatar-input", "File", "image", "/api/upload/avatar") .profile-image-container.avatar-preview if user.HasAvatar() @@ -71,7 +71,7 @@ component SettingsPersonal(user *arn.User) Icon("picture-o") span Cover - InputImage("cover-input", "File", "/api/upload/cover") + InputFileUpload("cover-input", "File", "image", "/api/upload/cover") .cover-preview(title="Recommended: 1920 x 450 | PNG or JPG") img#cover-input-preview.profile-cover.lazy(data-src=user.CoverLink("small"), data-webp="true", alt="Cover image") diff --git a/scripts/Actions/Upload.ts b/scripts/Actions/Upload.ts index ef21d4fb..bb0e83e3 100644 --- a/scripts/Actions/Upload.ts +++ b/scripts/Actions/Upload.ts @@ -8,7 +8,7 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) { return } - let preview = document.getElementById(button.dataset.previewImageId) as HTMLImageElement + let fileType = button.dataset.type let endpoint = button.dataset.endpoint // Click on virtual file input element @@ -22,18 +22,64 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) { return } - if(!file.type.startsWith("image/")) { + // Check mime type for images + if(fileType === "image" && !file.type.startsWith("image/")) { arn.statusMessage.showError(file.name + " is not an image file!") return } - previewImage(file, endpoint, preview) - uploadFile(file, endpoint, arn) + // Check mime type for videos + if(fileType === "video" && !file.type.startsWith("video/webm")) { + arn.statusMessage.showError(file.name + " is not a WebM video file!") + return + } + + // Preview image + if(fileType === "image") { + let preview = document.getElementById(button.id + "-preview") as HTMLImageElement + + if(preview) { + previewImage(file, endpoint, preview) + } + } + + uploadFile(file, fileType, endpoint, arn) } input.click() } +// Upload file +function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNotifier) { + let reader = new FileReader() + + reader.onloadend = async () => { + arn.statusMessage.showInfo(`Uploading ${fileType}...`, 60000) + + let response = await fetch(endpoint, { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/octet-stream" + }, + body: reader.result + }) + + if(endpoint === "/api/upload/avatar") { + let newURL = await response.text() + updateSideBarAvatar(newURL) + } + + if(response.ok) { + arn.statusMessage.showInfo(`Successfully uploaded your new ${fileType}.`) + } else { + arn.statusMessage.showError(`Failed uploading your new ${fileType}.`) + } + } + + reader.readAsArrayBuffer(file) +} + // Preview image function previewImage(file: File, endpoint: string, preview: HTMLImageElement) { let reader = new FileReader() @@ -54,37 +100,6 @@ function previewImage(file: File, endpoint: string, preview: HTMLImageElement) { reader.readAsDataURL(file) } -// Upload file -function uploadFile(file: File, endpoint: string, arn: AnimeNotifier) { - let reader = new FileReader() - - reader.onloadend = async () => { - arn.statusMessage.showInfo("Uploading image...", 60000) - - let response = await fetch(endpoint, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/octet-stream" - }, - body: reader.result - }) - - if(endpoint === "/api/upload/avatar") { - let newURL = await response.text() - updateSideBarAvatar(newURL) - } - - if(response.ok) { - arn.statusMessage.showInfo("Successfully uploaded your new image.") - } else { - arn.statusMessage.showError("Failed uploading your new image.") - } - } - - reader.readAsArrayBuffer(file) -} - // Update sidebar avatar function updateSideBarAvatar(url: string) { let sidebar = document.getElementById("sidebar") diff --git a/utils/editform/editform.go b/utils/editform/editform.go index ddfcc444..5b6cda5c 100644 --- a/utils/editform/editform.go +++ b/utils/editform/editform.go @@ -120,7 +120,7 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i // Try to infer the ID type by the field name if idType == "" { switch field.Name { - case "AnimeID", "MainAnimeID": + case "AnimeID": idType = "Anime" case "CharacterID": @@ -141,6 +141,8 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i b.WriteString(components.InputSelection(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"), values)) } else if field.Tag.Get("type") == "textarea" { b.WriteString(components.InputTextArea(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"))) + } else if field.Tag.Get("type") == "upload" { + b.WriteString(components.InputFileUpload(idPrefix+field.Name, field.Name, field.Tag.Get("filetype"), field.Tag.Get("endpoint"))) } else { b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"))) }