2018-01-23 20:06:30 +00:00
/* eslint-disable no-unused-expressions */
2018-03-28 20:05:01 +00:00
/* global swal, axios, Dropzone, ClipboardJS */
2017-01-14 09:16:47 +00:00
2018-03-28 11:36:28 +00:00
const upload = {
2018-04-03 18:54:42 +00:00
private : undefined ,
enableUserAccounts : undefined ,
2018-03-28 11:36:28 +00:00
token : localStorage . token ,
maxFileSize : undefined ,
chunkedUploads : undefined ,
// Add the album let to the upload so we can store the album id in there
album : undefined ,
2018-03-28 20:05:01 +00:00
dropzone : undefined ,
clipboardJS : undefined
2018-03-28 11:36:28 +00:00
}
2018-01-23 20:06:30 +00:00
2018-03-28 11:36:28 +00:00
const imageExtensions = [ '.webp' , '.jpg' , '.jpeg' , '.bmp' , '.gif' , '.png' ]
2018-01-23 20:06:30 +00:00
2018-03-28 11:36:28 +00:00
upload . checkIfPublic = ( ) => {
2018-01-24 15:31:23 +00:00
axios . get ( 'api/check' )
2018-01-23 20:06:30 +00:00
. then ( response => {
2018-04-03 18:54:42 +00:00
upload . private = response . data . private
upload . enableUserAccounts = response . data . enableUserAccounts
2018-01-23 20:06:30 +00:00
upload . maxFileSize = response . data . maxFileSize
2018-03-28 11:36:28 +00:00
upload . chunkedUploads = response . data . chunkedUploads
2018-01-23 20:06:30 +00:00
upload . preparePage ( )
} )
. catch ( error => {
2018-01-23 20:41:28 +00:00
console . log ( error )
2018-03-30 02:39:53 +00:00
return swal ( 'An error occurred!' , 'There was an error with the request, please check the console for more information.' , 'error' )
2018-01-23 20:06:30 +00:00
} )
}
2018-03-28 11:36:28 +00:00
upload . preparePage = ( ) => {
2018-04-03 18:54:42 +00:00
if ( upload . private ) {
2018-01-24 15:31:23 +00:00
if ( upload . token ) {
return upload . verifyToken ( upload . token , true )
} else {
2018-03-28 20:05:01 +00:00
const button = document . getElementById ( 'loginToUpload' )
button . href = 'auth'
button . className = button . className . replace ( ' is-loading' , '' )
2018-04-03 18:54:42 +00:00
if ( upload . enableUserAccounts ) {
button . innerText = 'Anonymous upload is disabled. Log in to upload.'
} else {
button . innerText = 'Running in private mode. Log in to upload.'
}
2018-01-24 15:31:23 +00:00
}
} else {
return upload . prepareUpload ( )
2018-01-23 20:06:30 +00:00
}
}
2018-03-28 11:36:28 +00:00
upload . verifyToken = ( token , reloadOnError ) => {
2018-01-23 20:06:30 +00:00
if ( reloadOnError === undefined ) { reloadOnError = false }
2018-04-05 10:52:57 +00:00
axios . post ( 'api/tokens/verify' , { token } )
2018-01-23 20:06:30 +00:00
. then ( response => {
if ( response . data . success === false ) {
swal ( {
2018-03-30 02:39:53 +00:00
title : 'An error occurred!' ,
2018-01-23 20:06:30 +00:00
text : response . data . description ,
2018-03-19 16:51:39 +00:00
icon : 'error'
} ) . then ( ( ) => {
2018-01-23 20:06:30 +00:00
if ( reloadOnError ) {
localStorage . removeItem ( 'token' )
location . reload ( )
}
} )
return
}
localStorage . token = token
upload . token = token
return upload . prepareUpload ( )
} )
. catch ( error => {
2018-01-23 20:41:28 +00:00
console . log ( error )
2018-03-30 02:39:53 +00:00
return swal ( 'An error occurred!' , 'There was an error with the request, please check the console for more information.' , 'error' )
2018-01-23 20:06:30 +00:00
} )
}
2018-03-28 11:36:28 +00:00
upload . prepareUpload = ( ) => {
2018-01-23 20:06:30 +00:00
// I think this fits best here because we need to check for a valid token before we can get the albums
if ( upload . token ) {
2018-03-28 11:36:28 +00:00
const select = document . getElementById ( 'albumSelect' )
2018-01-23 20:06:30 +00:00
select . addEventListener ( 'change' , ( ) => {
2018-04-05 12:54:24 +00:00
upload . album = parseInt ( select . value )
2018-01-23 20:06:30 +00:00
} )
2018-01-24 15:31:23 +00:00
axios . get ( 'api/albums' , { headers : { token : upload . token } } )
2018-01-23 20:06:30 +00:00
. then ( res => {
2018-03-28 11:36:28 +00:00
const albums = res . data . albums
2018-01-23 20:06:30 +00:00
// If the user doesn't have any albums we don't really need to display
// an album selection
2018-03-28 17:40:50 +00:00
if ( albums . length === 0 ) { return }
2018-01-23 20:06:30 +00:00
// Loop through the albums and create an option for each album
2018-04-05 10:52:57 +00:00
for ( const album of albums ) {
2018-03-28 11:36:28 +00:00
const opt = document . createElement ( 'option' )
2018-04-05 10:52:57 +00:00
opt . value = album . id
opt . innerHTML = album . name
2018-01-23 20:06:30 +00:00
select . appendChild ( opt )
}
// Display the album selection
document . getElementById ( 'albumDiv' ) . style . display = 'block'
} )
. catch ( e => {
2018-01-23 20:41:28 +00:00
console . log ( e )
2018-03-30 02:39:53 +00:00
return swal ( 'An error occurred!' , 'There was an error with the request, please check the console for more information.' , 'error' )
2018-01-23 20:06:30 +00:00
} )
}
2018-03-28 11:36:28 +00:00
const div = document . createElement ( 'div' )
2018-01-23 20:06:30 +00:00
div . id = 'dropzone'
2018-04-13 16:20:57 +00:00
div . className = 'button is-unselectable'
2018-03-28 20:05:01 +00:00
div . innerHTML = `
< span class = "icon" >
< i class = "icon-upload-cloud" > < / i >
< / s p a n >
< span > Click here or drag and drop files < / s p a n >
`
2018-01-23 20:06:30 +00:00
div . style . display = 'flex'
document . getElementById ( 'maxFileSize' ) . innerHTML = ` Maximum upload size per file is ${ upload . maxFileSize } `
document . getElementById ( 'loginToUpload' ) . style . display = 'none'
2018-04-03 18:54:42 +00:00
if ( upload . token === undefined && upload . enableUserAccounts ) {
2018-03-28 11:36:28 +00:00
document . getElementById ( 'loginLinkText' ) . innerHTML = 'Create an account and keep track of your uploads'
}
2018-01-23 20:06:30 +00:00
document . getElementById ( 'uploadContainer' ) . appendChild ( div )
upload . prepareDropzone ( )
}
2018-03-28 11:36:28 +00:00
upload . prepareDropzone = ( ) => {
const previewNode = document . querySelector ( '#template' )
2018-01-23 20:06:30 +00:00
previewNode . id = ''
2018-03-28 11:36:28 +00:00
const previewTemplate = previewNode . parentNode . innerHTML
2018-01-23 20:06:30 +00:00
previewNode . parentNode . removeChild ( previewNode )
2018-03-28 11:36:28 +00:00
upload . dropzone = new Dropzone ( 'div#dropzone' , {
2018-01-24 15:31:23 +00:00
url : 'api/upload' ,
2018-01-23 20:06:30 +00:00
paramName : 'files[]' ,
2018-03-28 11:36:28 +00:00
maxFilesize : parseInt ( upload . maxFileSize ) ,
2018-01-23 20:06:30 +00:00
parallelUploads : 2 ,
uploadMultiple : false ,
previewsContainer : 'div#uploads' ,
2018-03-28 20:05:01 +00:00
previewTemplate ,
2018-01-23 20:06:30 +00:00
createImageThumbnails : false ,
maxFiles : 1000 ,
autoProcessQueue : true ,
headers : { token : upload . token } ,
2018-03-28 11:36:28 +00:00
chunking : upload . chunkedUploads . enabled ,
chunkSize : parseInt ( upload . chunkedUploads . maxSize ) * 1000000 , // 1000000 B = 1 MB,
parallelChunkUploads : false , // when set to true, sometimes it often hangs with hundreds of parallel uploads
chunksUploaded : async ( file , done ) => {
file . previewElement . querySelector ( '.progress' ) . setAttribute ( 'value' , 100 )
2018-04-03 18:54:42 +00:00
file . previewElement . querySelector ( '.progress' ) . innerHTML = '100%'
2018-03-28 11:36:28 +00:00
// The API supports an array of multiple files
const response = await axios . post (
'api/upload/finishchunks' ,
{
files : [
{
uuid : file . upload . uuid ,
original : file . name ,
size : file . size ,
type : file . type ,
2018-04-05 12:54:24 +00:00
count : file . upload . totalChunkCount ,
albumid : upload . album
2018-03-28 11:36:28 +00:00
}
]
} ,
{
headers : { token : upload . token }
} )
. then ( response => response . data )
. catch ( error => {
return {
success : false ,
description : error . toString ( )
}
} )
file . previewTemplate . querySelector ( '.progress' ) . style . display = 'none'
if ( response . success === false ) {
file . previewTemplate . querySelector ( '.error' ) . innerHTML = response . description
}
2018-04-05 10:21:51 +00:00
if ( response . files && response . files [ 0 ] && response . files [ 0 ] . url ) {
upload . appendLink ( file , response . files [ 0 ] . url )
upload . showThumbnail ( file , response . files [ 0 ] . url )
}
2018-03-28 11:36:28 +00:00
return done ( )
2018-01-23 20:06:30 +00:00
}
} )
2018-03-28 11:36:28 +00:00
upload . dropzone . on ( 'addedfile' , file => {
document . getElementById ( 'uploads' ) . style . display = 'block'
} )
// Add the selected albumid, if an album is selected, as a header
upload . dropzone . on ( 'sending' , ( file , xhr , formData ) => {
2018-04-05 12:54:24 +00:00
if ( file . upload . chunked ) { return }
2018-03-28 17:40:50 +00:00
if ( upload . album ) { xhr . setRequestHeader ( 'albumid' , upload . album ) }
2018-03-28 11:36:28 +00:00
} )
2018-01-23 20:06:30 +00:00
// Update the total progress bar
2018-03-28 11:36:28 +00:00
upload . dropzone . on ( 'uploadprogress' , ( file , progress , bytesSent ) => {
2018-03-28 17:40:50 +00:00
if ( file . upload . chunked && progress === 100 ) { return }
2018-01-23 20:06:30 +00:00
file . previewElement . querySelector ( '.progress' ) . setAttribute ( 'value' , progress )
file . previewElement . querySelector ( '.progress' ) . innerHTML = ` ${ progress } % `
} )
2018-03-28 11:36:28 +00:00
upload . dropzone . on ( 'success' , ( file , response ) => {
2018-03-28 17:40:50 +00:00
if ( ! response ) { return }
2018-03-24 19:47:41 +00:00
file . previewTemplate . querySelector ( '.progress' ) . style . display = 'none'
2018-01-23 20:06:30 +00:00
if ( response . success === false ) {
2018-03-28 11:36:28 +00:00
file . previewTemplate . querySelector ( '.error' ) . innerHTML = response . description
2018-01-23 20:06:30 +00:00
}
2018-04-05 10:21:51 +00:00
if ( response . files && response . files [ 0 ] && response . files [ 0 ] . url ) {
upload . appendLink ( file , response . files [ 0 ] . url )
upload . showThumbnail ( file , response . files [ 0 ] . url )
}
2018-03-24 19:47:41 +00:00
} )
2018-01-23 20:06:30 +00:00
2018-03-28 11:36:28 +00:00
upload . dropzone . on ( 'error' , ( file , error ) => {
2018-01-23 20:06:30 +00:00
file . previewTemplate . querySelector ( '.progress' ) . style . display = 'none'
2018-03-28 11:36:28 +00:00
file . previewTemplate . querySelector ( '.error' ) . innerHTML = error
2018-01-23 20:06:30 +00:00
} )
upload . prepareShareX ( )
}
2018-03-28 20:05:01 +00:00
upload . appendLink = ( file , url ) => {
const a = file . previewTemplate . querySelector ( '.link > a' )
2018-03-28 20:12:11 +00:00
const clipboard = file . previewTemplate . querySelector ( '.clipboard-mobile > .clipboard-js' )
2018-03-28 20:05:01 +00:00
2018-03-28 20:12:11 +00:00
a . href = a . innerHTML = clipboard . dataset [ 'clipboardText' ] = url
2018-03-28 20:28:40 +00:00
a . parentElement . style = clipboard . parentElement . style = ''
2018-03-28 20:05:01 +00:00
}
2018-03-28 11:36:28 +00:00
upload . showThumbnail = ( file , url ) => {
const exec = /.[\w]+(\?|$)/ . exec ( url )
if ( exec && exec [ 0 ] && imageExtensions . includes ( exec [ 0 ] . toLowerCase ( ) ) ) {
upload . dropzone . emit ( 'thumbnail' , file , url )
}
}
upload . prepareShareX = ( ) => {
2018-01-23 20:06:30 +00:00
if ( upload . token ) {
2018-03-28 11:36:28 +00:00
const sharexElement = document . getElementById ( 'ShareX' )
const sharexFile = ` { \r \n \
2018-01-23 18:00:55 +00:00
"Name" : "${location.hostname}" , \ r \ n \
"DestinationType" : "ImageUploader, FileUploader" , \ r \ n \
"RequestType" : "POST" , \ r \ n \
"RequestURL" : "${location.origin}/api/upload" , \ r \ n \
"FileFormName" : "files[]" , \ r \ n \
"Headers" : { \ r \ n \
"token" : "${upload.token}" \ r \ n \
2017-10-06 06:40:06 +00:00
} , \ r \ n \
2018-01-23 18:00:55 +00:00
"ResponseType" : "Text" , \ r \ n \
"URL" : "$json:files[0].url$" , \ r \ n \
"ThumbnailURL" : "$json:files[0].url$" \ r \ n \
2018-01-23 20:06:30 +00:00
} `
2018-03-28 11:36:28 +00:00
const sharexBlob = new Blob ( [ sharexFile ] , { type : 'application/octet-binary' } )
2018-01-23 20:06:30 +00:00
sharexElement . setAttribute ( 'href' , URL . createObjectURL ( sharexBlob ) )
sharexElement . setAttribute ( 'download' , ` ${ location . hostname } .sxcu ` )
}
}
2017-01-17 03:37:54 +00:00
2018-01-23 18:00:55 +00:00
// Handle image paste event
window . addEventListener ( 'paste' , event => {
2018-03-28 11:36:28 +00:00
const items = ( event . clipboardData || event . originalEvent . clipboardData ) . items
for ( const index in items ) {
const item = items [ index ]
2018-01-23 20:06:30 +00:00
if ( item . kind === 'file' ) {
2018-03-28 11:36:28 +00:00
const blob = item . getAsFile ( )
2018-01-23 20:06:30 +00:00
console . log ( blob . type )
2018-03-28 11:36:28 +00:00
const file = new File ( [ blob ] , ` pasted-image. ${ blob . type . match ( /(?:[^/]*\/)([^;]*)/ ) [ 1 ] } ` )
2018-01-23 20:06:30 +00:00
file . type = blob . type
console . log ( file )
2018-03-28 11:36:28 +00:00
upload . dropzone . addFile ( file )
2018-01-23 20:06:30 +00:00
}
}
} )
2018-03-28 11:36:28 +00:00
window . onload = ( ) => {
2018-01-23 20:06:30 +00:00
upload . checkIfPublic ( )
2018-03-28 20:05:01 +00:00
upload . clipboardJS = new ClipboardJS ( '.clipboard-js' )
upload . clipboardJS . on ( 'success' , ( ) => {
return swal ( 'Copied!' , 'The link has been copied to clipboard.' , 'success' )
} )
upload . clipboardJS . on ( 'error' , event => {
console . error ( event )
2018-03-30 02:39:53 +00:00
return swal ( 'An error occurred!' , 'There was an error when trying to copy the link to clipboard, please check the console for more information.' , 'error' )
2018-03-28 20:05:01 +00:00
} )
2018-01-23 20:06:30 +00:00
}