Improved file upload

This commit is contained in:
Eduard Urbach 2018-04-15 00:20:53 +02:00
parent 42c72b6174
commit 1ecc3e3fa4
5 changed files with 58 additions and 41 deletions

View File

@ -43,10 +43,10 @@ component InputSelection(id string, value string, label string, placeholder stri
each option in options each option in options
option(value=option.Value)= option.Label 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 .widget-section
label(for=id)= label + ":" 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") Icon("upload")
span Select file span Select file

View File

@ -9,7 +9,7 @@ component EditAnimeImages(anime *arn.Anime)
Icon("picture-o") Icon("picture-o")
span Image 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 .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") img#anime-image-input-preview.anime-cover-image.lazy(data-src=anime.ImageLink("large"), data-webp="true", data-color=anime.AverageColor(), alt="Anime image")

View File

@ -55,7 +55,7 @@ component SettingsPersonal(user *arn.User)
//- //- File upload //- //- File upload
//- if user.Settings().Avatar.Source == "FileSystem" //- 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 .profile-image-container.avatar-preview
if user.HasAvatar() if user.HasAvatar()
@ -71,7 +71,7 @@ component SettingsPersonal(user *arn.User)
Icon("picture-o") Icon("picture-o")
span Cover 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") .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") img#cover-input-preview.profile-cover.lazy(data-src=user.CoverLink("small"), data-webp="true", alt="Cover image")

View File

@ -8,7 +8,7 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
return return
} }
let preview = document.getElementById(button.dataset.previewImageId) as HTMLImageElement let fileType = button.dataset.type
let endpoint = button.dataset.endpoint let endpoint = button.dataset.endpoint
// Click on virtual file input element // Click on virtual file input element
@ -22,18 +22,64 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
return 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!") arn.statusMessage.showError(file.name + " is not an image file!")
return return
} }
// 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) previewImage(file, endpoint, preview)
uploadFile(file, endpoint, arn) }
}
uploadFile(file, fileType, endpoint, arn)
} }
input.click() 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 // Preview image
function previewImage(file: File, endpoint: string, preview: HTMLImageElement) { function previewImage(file: File, endpoint: string, preview: HTMLImageElement) {
let reader = new FileReader() let reader = new FileReader()
@ -54,37 +100,6 @@ function previewImage(file: File, endpoint: string, preview: HTMLImageElement) {
reader.readAsDataURL(file) 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 // Update sidebar avatar
function updateSideBarAvatar(url: string) { function updateSideBarAvatar(url: string) {
let sidebar = document.getElementById("sidebar") let sidebar = document.getElementById("sidebar")

View File

@ -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 // Try to infer the ID type by the field name
if idType == "" { if idType == "" {
switch field.Name { switch field.Name {
case "AnimeID", "MainAnimeID": case "AnimeID":
idType = "Anime" idType = "Anime"
case "CharacterID": 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)) b.WriteString(components.InputSelection(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"), values))
} else if field.Tag.Get("type") == "textarea" { } else if field.Tag.Get("type") == "textarea" {
b.WriteString(components.InputTextArea(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"))) 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 { } else {
b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"))) b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip")))
} }