2018-04-29 12:47:24 +00:00
/* global swal, axios, Dropzone, ClipboardJS, LazyLoad */
2017-01-14 09:16:47 +00:00
2018-04-29 12:47:24 +00:00
const page = {
// user token
2018-03-28 11:36:28 +00:00
token : localStorage . token ,
2018-04-29 12:47:24 +00:00
// configs from api/check
private : null ,
enableUserAccounts : null ,
maxFileSize : null ,
2018-05-09 08:41:30 +00:00
chunkSize : null ,
2018-04-29 12:47:24 +00:00
// store album id that will be used with upload requests
album : null ,
2018-05-06 14:14:57 +00:00
albumSelect : null ,
2018-05-11 14:34:13 +00:00
previewTemplate : null ,
2018-05-06 14:14:57 +00:00
2018-04-29 12:47:24 +00:00
dropzone : null ,
clipboardJS : null ,
2018-04-29 12:54:55 +00:00
lazyLoad : null
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-05-06 14:14:57 +00:00
page . checkIfPublic = async ( ) => {
const response = await axios . get ( 'api/check' )
2018-01-23 20:06:30 +00:00
. catch ( error => {
2018-01-23 20:41:28 +00:00
console . log ( error )
2018-04-21 13:14:34 +00:00
const button = document . getElementById ( 'loginToUpload' )
2018-05-06 14:14:57 +00:00
button . classList . remove ( 'is-loading' )
2018-04-21 13:14:34 +00:00
button . innerText = 'Error occurred. Reload the page?'
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-05-06 14:14:57 +00:00
if ( ! response ) { return }
page . private = response . data . private
page . enableUserAccounts = response . data . enableUserAccounts
page . maxFileSize = response . data . maxFileSize
2018-05-09 08:41:30 +00:00
page . chunkSize = response . data . chunkSize
2018-05-06 14:14:57 +00:00
page . preparePage ( )
2018-01-23 20:06:30 +00:00
}
2018-04-29 12:47:24 +00:00
page . preparePage = ( ) => {
if ( page . private ) {
if ( page . token ) {
return page . verifyToken ( page . token , true )
2018-01-24 15:31:23 +00:00
} else {
2018-03-28 20:05:01 +00:00
const button = document . getElementById ( 'loginToUpload' )
button . href = 'auth'
2018-05-06 14:14:57 +00:00
button . classList . remove ( 'is-loading' )
2018-04-03 18:54:42 +00:00
2018-04-29 12:47:24 +00:00
if ( page . enableUserAccounts ) {
button . innerText = 'Anonymous upload is disabled. Log in to page.'
2018-04-03 18:54:42 +00:00
} else {
2018-04-29 12:47:24 +00:00
button . innerText = 'Running in private mode. Log in to page.'
2018-04-03 18:54:42 +00:00
}
2018-01-24 15:31:23 +00:00
}
} else {
2018-04-29 12:47:24 +00:00
return page . prepareUpload ( )
2018-01-23 20:06:30 +00:00
}
}
2018-05-06 14:14:57 +00:00
page . verifyToken = async ( token , reloadOnError ) => {
2018-01-23 20:06:30 +00:00
if ( reloadOnError === undefined ) { reloadOnError = false }
2018-05-06 14:14:57 +00:00
const response = await axios . post ( 'api/tokens/verify' , { token } )
2018-01-23 20:06:30 +00:00
. 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-05-06 14:14:57 +00:00
if ( ! response ) { return }
if ( response . data . success === false ) {
await swal ( {
title : 'An error occurred!' ,
text : response . data . description ,
icon : 'error'
} )
if ( reloadOnError ) {
localStorage . removeItem ( 'token' )
location . reload ( )
}
return
}
localStorage . token = token
page . token = token
return page . prepareUpload ( )
2018-01-23 20:06:30 +00:00
}
2018-04-29 12:47:24 +00:00
page . 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
2018-04-29 12:47:24 +00:00
if ( page . token ) {
2018-05-06 14:14:57 +00:00
page . albumSelect = document . getElementById ( 'albumSelect' )
2018-01-23 20:06:30 +00:00
2018-05-06 14:14:57 +00:00
page . albumSelect . addEventListener ( 'change' , ( ) => {
page . album = parseInt ( page . albumSelect . value )
2018-01-23 20:06:30 +00:00
} )
2018-05-06 14:14:57 +00:00
page . prepareAlbums ( )
// Display the album selection
document . getElementById ( 'albumDiv' ) . style . display = 'flex'
2018-01-23 20:06:30 +00:00
}
2018-04-29 12:47:24 +00:00
document . getElementById ( 'maxFileSize' ) . innerHTML = ` Maximum upload size per file is ${ page . maxFileSize } `
2018-01-23 20:06:30 +00:00
document . getElementById ( 'loginToUpload' ) . style . display = 'none'
2018-04-29 12:47:24 +00:00
if ( ! page . token && page . 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
2018-05-11 14:34:13 +00:00
const previewNode = document . querySelector ( '#tpl' )
page . previewTemplate = previewNode . innerHTML
previewNode . parentNode . removeChild ( previewNode )
2018-01-23 20:06:30 +00:00
2018-04-29 12:47:24 +00:00
page . prepareDropzone ( )
2018-05-11 14:34:13 +00:00
const tabs = document . getElementById ( 'tabs' )
if ( tabs ) {
tabs . style . display = 'flex'
const items = tabs . getElementsByTagName ( 'li' )
for ( const item of items ) {
item . addEventListener ( 'click' , function ( ) {
page . setActiveTab ( this . dataset . id )
} )
}
document . getElementById ( 'uploadUrls' ) . addEventListener ( 'click' , function ( ) {
page . uploadUrls ( this )
} )
page . setActiveTab ( 'tab-files' )
} else {
document . getElementById ( 'tab-files' ) . style . display = 'block'
}
2018-01-23 20:06:30 +00:00
}
2018-05-06 14:14:57 +00:00
page . prepareAlbums = async ( ) => {
const option = document . createElement ( 'option' )
option . value = ''
option . innerHTML = 'Upload to album'
option . disabled = true
option . selected = true
page . albumSelect . appendChild ( option )
const response = await axios . get ( 'api/albums' , { headers : { token : page . token } } )
. catch ( error => {
console . log ( error )
return swal ( 'An error occurred!' , 'There was an error with the request, please check the console for more information.' , 'error' )
} )
if ( ! response ) { return }
if ( response . data . success === false ) {
return swal ( 'An error occurred!' , response . data . description , 'error' )
}
const albums = response . data . albums
// If the user doesn't have any albums we don't really need to display
// an album selection
if ( albums . length === 0 ) { return }
// Loop through the albums and create an option for each album
for ( const album of albums ) {
const option = document . createElement ( 'option' )
option . value = album . id
option . innerHTML = album . name
page . albumSelect . appendChild ( option )
}
}
2018-05-11 14:34:13 +00:00
page . setActiveTab = activeId => {
const items = document . getElementById ( 'tabs' ) . getElementsByTagName ( 'li' )
for ( const item of items ) {
const tabId = item . dataset . id
if ( tabId === activeId ) {
item . classList . add ( 'is-active' )
document . getElementById ( tabId ) . style . display = 'block'
} else {
item . classList . remove ( 'is-active' )
document . getElementById ( tabId ) . style . display = 'none'
}
}
}
2018-04-29 12:47:24 +00:00
page . prepareDropzone = ( ) => {
2018-05-11 14:34:13 +00:00
const tabDiv = document . getElementById ( 'tab-files' )
const div = document . createElement ( 'div' )
div . className = 'control is-expanded'
div . innerHTML = `
< div id = "dropzone" class = "button is-danger is-fullwidth is-unselectable" >
< 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 >
< / d i v >
`
tabDiv . getElementsByClassName ( 'dz-container' ) [ 0 ] . appendChild ( div )
2018-01-23 20:06:30 +00:00
2018-05-11 14:34:13 +00:00
const previewsContainer = tabDiv . getElementsByClassName ( 'uploads' ) [ 0 ]
2018-04-29 12:47:24 +00:00
page . dropzone = new Dropzone ( '#dropzone' , {
2018-01-24 15:31:23 +00:00
url : 'api/upload' ,
2018-01-23 20:06:30 +00:00
paramName : 'files[]' ,
2018-04-29 12:47:24 +00:00
maxFilesize : parseInt ( page . maxFileSize ) ,
2018-01-23 20:06:30 +00:00
parallelUploads : 2 ,
uploadMultiple : false ,
2018-05-11 14:34:13 +00:00
previewsContainer ,
previewTemplate : page . previewTemplate ,
2018-01-23 20:06:30 +00:00
createImageThumbnails : false ,
maxFiles : 1000 ,
autoProcessQueue : true ,
2018-04-29 12:47:24 +00:00
headers : { token : page . token } ,
2018-05-09 08:41:30 +00:00
chunking : Boolean ( page . chunkSize ) ,
chunkSize : parseInt ( page . chunkSize ) * 1000000 , // 1000000 B = 1 MB,
2018-03-28 11:36:28 +00:00
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
2018-05-06 14:14:57 +00:00
const response = await axios . post ( 'api/upload/finishchunks' ,
2018-03-28 11:36:28 +00:00
{
2018-04-29 12:47:24 +00:00
files : [ {
uuid : file . upload . uuid ,
original : file . name ,
size : file . size ,
type : file . type ,
count : file . upload . totalChunkCount ,
albumid : page . album
} ]
2018-03-28 11:36:28 +00:00
} ,
2018-05-06 14:14:57 +00:00
{ headers : { token : page . token } } )
2018-03-28 11:36:28 +00:00
. then ( response => response . data )
. catch ( error => {
return {
success : false ,
description : error . toString ( )
}
} )
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.progress' ) . style . display = 'none'
2018-03-28 11:36:28 +00:00
if ( response . success === false ) {
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.error' ) . innerHTML = response . description
2018-03-28 11:36:28 +00:00
}
2018-04-29 12:47:24 +00:00
if ( response . files && response . files [ 0 ] ) {
page . updateTemplate ( file , response . files [ 0 ] )
2018-04-05 10:21:51 +00:00
}
2018-03-28 11:36:28 +00:00
return done ( )
2018-01-23 20:06:30 +00:00
}
} )
2018-04-29 12:47:24 +00:00
page . dropzone . on ( 'addedfile' , file => {
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.name' ) . innerHTML = file . name
2018-03-28 11:36:28 +00:00
} )
// Add the selected albumid, if an album is selected, as a header
2018-04-29 12:47:24 +00:00
page . dropzone . on ( 'sending' , ( file , xhr , formData ) => {
2018-04-05 12:54:24 +00:00
if ( file . upload . chunked ) { return }
2018-04-29 12:47:24 +00:00
if ( page . album ) { xhr . setRequestHeader ( 'albumid' , page . album ) }
2018-03-28 11:36:28 +00:00
} )
2018-01-23 20:06:30 +00:00
// Update the total progress bar
2018-04-29 12:47:24 +00:00
page . 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-04-29 12:47:24 +00:00
page . dropzone . on ( 'success' , ( file , response ) => {
2018-03-28 17:40:50 +00:00
if ( ! response ) { return }
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.progress' ) . style . display = 'none'
// file.previewElement.querySelector('.name').innerHTML = file.name
2018-01-23 20:06:30 +00:00
if ( response . success === false ) {
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.error' ) . innerHTML = response . description
2018-01-23 20:06:30 +00:00
}
2018-04-29 12:47:24 +00:00
if ( response . files && response . files [ 0 ] ) {
page . updateTemplate ( file , response . files [ 0 ] )
2018-04-05 10:21:51 +00:00
}
2018-03-24 19:47:41 +00:00
} )
2018-01-23 20:06:30 +00:00
2018-04-29 12:47:24 +00:00
page . dropzone . on ( 'error' , ( file , error ) => {
2018-05-11 14:34:13 +00:00
file . previewElement . querySelector ( '.progress' ) . style . display = 'none'
file . previewElement . querySelector ( '.name' ) . innerHTML = file . name
file . previewElement . querySelector ( '.error' ) . innerHTML = error
2018-01-23 20:06:30 +00:00
} )
2018-04-29 12:47:24 +00:00
page . prepareShareX ( )
2018-01-23 20:06:30 +00:00
}
2018-05-11 14:34:13 +00:00
page . uploadUrls = async button => {
const tabDiv = document . getElementById ( 'tab-urls' )
if ( ! tabDiv ) { return }
if ( button . classList . contains ( 'is-loading' ) ) { return }
button . classList . add ( 'is-loading' )
const previewsContainer = tabDiv . getElementsByClassName ( 'uploads' ) [ 0 ]
const files = document . getElementById ( 'urls' ) . value
. split ( /\r?\n/ )
. map ( url => {
const previewTemplate = document . createElement ( 'template' )
previewTemplate . innerHTML = page . previewTemplate . trim ( )
const previewElement = previewTemplate . content . firstChild
return {
name : url ,
url ,
previewElement
}
} )
await new Promise ( resolve => {
const post = async i => {
if ( i === files . length ) { return resolve ( ) }
const file = files [ i ]
file . previewElement . querySelector ( '.name' ) . innerHTML = file . name
previewsContainer . appendChild ( file . previewElement )
const response = await axios . post ( 'api/upload' ,
{
urls : [ file . url ]
} ,
{
headers : {
token : page . token ,
albumid : page . album
}
} )
. then ( response => response . data )
. catch ( error => {
return {
success : false ,
description : error . toString ( )
}
} )
file . previewElement . querySelector ( '.progress' ) . style . display = 'none'
if ( response . success ) {
page . updateTemplate ( file , response . files [ 0 ] )
} else {
file . previewElement . querySelector ( '.error' ) . innerHTML = response . description
}
post ( i + 1 )
}
post ( 0 )
} )
button . classList . remove ( 'is-loading' )
}
2018-04-29 12:47:24 +00:00
page . updateTemplate = ( file , response ) => {
if ( ! response . url ) { return }
2018-05-11 14:34:13 +00:00
const a = file . previewElement . querySelector ( '.link > a' )
const clipboard = file . previewElement . querySelector ( '.clipboard-mobile > .clipboard-js' )
2018-04-29 12:47:24 +00:00
a . href = a . innerHTML = clipboard . dataset [ 'clipboardText' ] = response . url
clipboard . parentElement . style . display = 'block'
2018-03-28 20:05:01 +00:00
2018-04-29 12:47:24 +00:00
const exec = /.[\w]+(\?|$)/ . exec ( response . url )
2018-03-28 11:36:28 +00:00
if ( exec && exec [ 0 ] && imageExtensions . includes ( exec [ 0 ] . toLowerCase ( ) ) ) {
2018-05-11 14:34:13 +00:00
const img = file . previewElement . querySelector ( 'img' )
2018-04-29 12:47:24 +00:00
img . setAttribute ( 'alt' , response . name || '' )
img . dataset [ 'src' ] = response . url
img . onerror = function ( ) { this . style . display = 'none' } // hide webp in firefox and ie
2018-05-11 14:34:13 +00:00
page . lazyLoad . update ( file . previewElement . querySelectorAll ( 'img' ) )
2018-03-28 11:36:28 +00:00
}
}
2018-04-29 12:47:24 +00:00
page . prepareShareX = ( ) => {
if ( page . token ) {
2018-03-28 11:36:28 +00:00
const sharexElement = document . getElementById ( 'ShareX' )
2018-04-26 13:14:18 +00:00
const sharexFile =
'{\r\n' +
` "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' +
2018-04-29 12:47:24 +00:00
` "token": " ${ page . token } " \r \n ` +
2018-04-26 13:14:18 +00:00
' },\r\n' +
' "ResponseType": "Text",\r\n' +
' "URL": "$json:files[0].url$",\r\n' +
' "ThumbnailURL": "$json:files[0].url$"\r\n' +
'}'
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-05-06 14:14:57 +00:00
page . createAlbum = async ( ) => {
const div = document . createElement ( 'div' )
div . innerHTML = `
< div class = "field" >
< label class = "label" > Album name < / l a b e l >
< div class = "controls" >
< input id = "_name" class = "input" type = "text" placeholder = "My super album" >
< / d i v >
< / d i v >
< div class = "field" >
< div class = "control" >
< label class = "checkbox" >
< input id = "_download" type = "checkbox" checked >
Enable download
< / l a b e l >
< / d i v >
< / d i v >
< div class = "field" >
< div class = "control" >
< label class = "checkbox" >
< input id = "_public" type = "checkbox" checked >
Enable public link
< / l a b e l >
< / d i v >
< / d i v >
`
const value = await swal ( {
title : 'Create new album' ,
icon : 'info' ,
content : div ,
buttons : {
cancel : true ,
confirm : {
closeModal : false
}
}
} )
if ( ! value ) { return }
const name = document . getElementById ( '_name' ) . value
const response = await axios . post ( 'api/albums' , {
name ,
download : document . getElementById ( '_download' ) . checked ,
public : document . getElementById ( '_public' ) . checked
} , { headers : { token : page . token } } )
. catch ( error => {
console . log ( error )
return swal ( 'An error occurred!' , 'There was an error with the request, please check the console for more information.' , 'error' )
} )
if ( ! response ) { return }
if ( response . data . success === false ) {
return swal ( 'An error occurred!' , response . data . description , 'error' )
}
const option = document . createElement ( 'option' )
option . value = response . data . id
option . innerHTML = name
page . albumSelect . appendChild ( option )
swal ( 'Woohoo!' , 'Album was created successfully' , 'success' )
}
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-04-29 12:47:24 +00:00
page . dropzone . addFile ( file )
2018-01-23 20:06:30 +00:00
}
}
} )
2018-03-28 11:36:28 +00:00
window . onload = ( ) => {
2018-04-29 12:47:24 +00:00
page . checkIfPublic ( )
2018-03-28 20:05:01 +00:00
2018-04-29 12:47:24 +00:00
page . clipboardJS = new ClipboardJS ( '.clipboard-js' )
2018-03-28 20:05:01 +00:00
2018-04-29 12:47:24 +00:00
page . clipboardJS . on ( 'success' , ( ) => {
2018-03-28 20:05:01 +00:00
return swal ( 'Copied!' , 'The link has been copied to clipboard.' , 'success' )
} )
2018-04-29 12:47:24 +00:00
page . clipboardJS . on ( 'error' , event => {
2018-03-28 20:05:01 +00:00
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-04-29 12:47:24 +00:00
page . lazyLoad = new LazyLoad ( )
2018-01-23 20:06:30 +00:00
}