
new file: .gitignore new file: .idea/.gitignore new file: .idea/dataSources.xml new file: .idea/dbr-backend.iml new file: .idea/jsLibraryMappings.xml new file: .idea/misc.xml new file: .idea/modules.xml new file: .idea/vcs.xml new file: go.mod new file: go.sum new file: main.go new file: pb_public/admin/index.html new file: pb_public/admin/upload.html new file: pb_public/css/base.css new file: pb_public/css/bootstrap-grid.css new file: pb_public/css/bootstrap-grid.css.map new file: pb_public/css/bootstrap-grid.min.css new file: pb_public/css/bootstrap-grid.min.css.map new file: pb_public/css/bootstrap-grid.rtl.css new file: pb_public/css/bootstrap-grid.rtl.css.map new file: pb_public/css/bootstrap-grid.rtl.min.css new file: pb_public/css/bootstrap-grid.rtl.min.css.map new file: pb_public/css/bootstrap-reboot.css new file: pb_public/css/bootstrap-reboot.css.map new file: pb_public/css/bootstrap-reboot.min.css new file: pb_public/css/bootstrap-reboot.min.css.map new file: pb_public/css/bootstrap-reboot.rtl.css new file: pb_public/css/bootstrap-reboot.rtl.css.map new file: pb_public/css/bootstrap-reboot.rtl.min.css new file: pb_public/css/bootstrap-reboot.rtl.min.css.map new file: pb_public/css/bootstrap-utilities.css new file: pb_public/css/bootstrap-utilities.css.map new file: pb_public/css/bootstrap-utilities.min.css new file: pb_public/css/bootstrap-utilities.min.css.map new file: pb_public/css/bootstrap-utilities.rtl.css new file: pb_public/css/bootstrap-utilities.rtl.css.map new file: pb_public/css/bootstrap-utilities.rtl.min.css new file: pb_public/css/bootstrap-utilities.rtl.min.css.map new file: pb_public/css/bootstrap.css new file: pb_public/css/bootstrap.css.map new file: pb_public/css/bootstrap.min.css new file: pb_public/css/bootstrap.min.css.map new file: pb_public/css/bootstrap.rtl.css new file: pb_public/css/bootstrap.rtl.css.map new file: pb_public/css/bootstrap.rtl.min.css new file: pb_public/css/bootstrap.rtl.min.css.map new file: pb_public/css/icons/bootstrap-icons.css new file: pb_public/css/icons/fonts/bootstrap-icons.woff new file: pb_public/css/icons/fonts/bootstrap-icons.woff2 new file: pb_public/css/slideshow.css new file: pb_public/css/style.css new file: pb_public/css/upload.css new file: pb_public/css/uploadfile.css new file: pb_public/index.html new file: pb_public/js/api/media.js new file: pb_public/js/bootstrap.bundle.js new file: pb_public/js/bootstrap.bundle.js.map new file: pb_public/js/bootstrap.bundle.min.js new file: pb_public/js/bootstrap.bundle.min.js.map new file: pb_public/js/bootstrap.esm.js new file: pb_public/js/bootstrap.esm.js.map new file: pb_public/js/bootstrap.esm.min.js new file: pb_public/js/bootstrap.esm.min.js.map new file: pb_public/js/bootstrap.js new file: pb_public/js/bootstrap.js.map new file: pb_public/js/bootstrap.min.js new file: pb_public/js/bootstrap.min.js.map new file: pb_public/js/jquery-1.11.0.js new file: pb_public/js/jquery.uploadfile.min.js new file: pb_public/js/multiple-uploader.js new file: pb_public/js/pocketbase/pocketbase.esm.js new file: pb_public/js/pocketbase/pocketbase.umd.js new file: pb_public/js/slideshow.js new file: pb_public/js/upload.js new file: pb_public/js/util.js
166 lines
6.2 KiB
JavaScript
166 lines
6.2 KiB
JavaScript
|
|
class MultipleUploader {
|
|
|
|
#multipleUploader;
|
|
#$imagesUploadInput;
|
|
|
|
constructor( multiUploaderSelector )
|
|
{
|
|
this.#multipleUploader = document.querySelector(multiUploaderSelector);
|
|
this.#$imagesUploadInput = document.createElement('input')
|
|
}
|
|
|
|
init( { maxUpload = 10 , maxSize = 2 , formSelector = 'form' , filesInpName = 'images' } = {} )
|
|
{
|
|
|
|
const form = document.querySelector(formSelector);
|
|
|
|
if (! this.#multipleUploader ) // check if the end user didnt write the multiple uploader div
|
|
throw new Error('The multiple uploader element doesnt exist');
|
|
|
|
if (! form ) // check if there is no form with this selector
|
|
throw new Error('We couldn\'t find a form with this selector: ' + formSelector);
|
|
|
|
// ensure that the form has enctype attribute with the value multipart/form-data
|
|
form.enctype = 'multipart/form-data'
|
|
|
|
if ( document.getElementById('max-upload-number') )
|
|
document.getElementById('max-upload-number').innerHTML = `Upload up to ${ maxUpload } files`;
|
|
|
|
// create multiple file input and make it hidden
|
|
this.#$imagesUploadInput.type = 'file';
|
|
this.#$imagesUploadInput.name = `${filesInpName}[]`;
|
|
this.#$imagesUploadInput.multiple = true;
|
|
this.#$imagesUploadInput.accept = "image/*";
|
|
this.#$imagesUploadInput.style.setProperty('display','none','important');
|
|
// create multiple file input and make it hidden
|
|
|
|
// append the newly created input to the form with the help of the formSelector provided by the user
|
|
document.querySelector(formSelector).append( this.#$imagesUploadInput );
|
|
|
|
this.#multipleUploader.addEventListener("click", (e) => {
|
|
|
|
if ( e.target.className === 'multiple-uploader' || e.target.className === 'mup-msg' || e.target.className === 'mup-main-msg' )
|
|
this.#$imagesUploadInput.click() // trigger the input file to upload images
|
|
|
|
});
|
|
|
|
const self = this;
|
|
|
|
// preview the uploaded images
|
|
this.#$imagesUploadInput.addEventListener("change",function () {
|
|
|
|
if (this.files.length > 0)
|
|
{
|
|
self.#multipleUploader.querySelectorAll('.image-container').forEach( image => image.remove() ); // clear the previous rendered images
|
|
self.#multipleUploader.querySelector('.mup-msg').style.setProperty('display', 'none'); // hide the hint texts inside drop zone
|
|
|
|
// if the length of uploaded images greater than the images uploaded by the user, the maximum uploaded will be considered
|
|
const uploadedImagesCount = this.files.length > maxUpload ? maxUpload : this.files.length;
|
|
const unAcceptableImagesIndices = [];
|
|
|
|
for (let index = 0; index < uploadedImagesCount; index++) {
|
|
|
|
const imageSize = self.#bytesToSize( this.files[ index ].size );
|
|
const isImageSizeAcceptable = self.#checkImageSize( index , imageSize , maxSize , 'MB' );
|
|
|
|
|
|
// appended the newly created image to the multiple uploader
|
|
self.#multipleUploader.innerHTML += `
|
|
<div class="image-container" data-image-index="${ index }" id="mup-image-${ index }" data-acceptable-image="${ +isImageSizeAcceptable }" >
|
|
<div class="image-size"> ${ imageSize['size'] + ' ' + imageSize['unit'] } </div>
|
|
${ !isImageSizeAcceptable ? `<div class="exceeded-size"> greater than ${ maxSize } MB </div>` : '' }
|
|
<img src="${ URL.createObjectURL( this.files[ index ]) }" class="image-preview" alt="" />
|
|
</div>`;
|
|
|
|
if ( ! isImageSizeAcceptable )
|
|
unAcceptableImagesIndices.push( index )
|
|
|
|
}
|
|
|
|
unAcceptableImagesIndices.forEach( (index ) => self.#removeFileFromInput(index, false ))
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// event for deleting uploaded images
|
|
document.addEventListener('click',function(e){
|
|
|
|
if( e.target.className === 'image-container' ) // clicked on remove pseudo element
|
|
{
|
|
const imageIndex = e.target.getAttribute(`data-image-index`)
|
|
const imageIsAcceptable = e.target.getAttribute(`data-acceptable-image`)
|
|
|
|
e.target.remove() // remove the html element from the dom
|
|
|
|
if ( +imageIsAcceptable )
|
|
self.#removeFileFromInput(imageIndex)
|
|
|
|
if ( document.querySelectorAll('.image-container').length === 0 ) // if there are no images
|
|
self.clear();
|
|
|
|
|
|
self.#reorderFilesIndices(); // reorder images indices
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
clear()
|
|
{
|
|
this.#multipleUploader.querySelectorAll('.image-container').forEach( image => image.remove() );
|
|
this.#multipleUploader.querySelectorAll('.mup-msg').forEach( msg => msg.style.setProperty('display', 'flex') );
|
|
this.#$imagesUploadInput.value = [];
|
|
}
|
|
|
|
#removeFileFromInput( deletedIndex )
|
|
{
|
|
// remove the delete file from input
|
|
const dt = new DataTransfer()
|
|
|
|
for (const [ index, file] of Object.entries( this.#$imagesUploadInput.files ))
|
|
{
|
|
if ( index != deletedIndex )
|
|
dt.items.add( file )
|
|
}
|
|
|
|
this.#$imagesUploadInput.files = dt.files
|
|
// remove the delete file from input
|
|
|
|
}
|
|
|
|
#reorderFilesIndices()
|
|
{
|
|
document.querySelectorAll('.image-container').forEach( ( element, index) => {
|
|
element.setAttribute('data-image-index', index.toString() );
|
|
element.setAttribute('id',`mup-image-${ index }`)
|
|
});
|
|
}
|
|
|
|
#checkImageSize( imageIndex, imageSize , maxSize )
|
|
{
|
|
return imageSize['unit'] !== 'MB' || ( imageSize['unit'] === 'MB' && ( imageSize['size'] <= maxSize ) ) ; // return true if acceptable
|
|
}
|
|
|
|
#bytesToSize(bytes)
|
|
{
|
|
const sizes = ['Bytes', 'KB', 'MB']
|
|
|
|
const i = parseInt( Math.floor(Math.log(bytes) / Math.log(1024) ), 10)
|
|
|
|
if (i === 0)
|
|
return {size: bytes , unit: sizes[i] }
|
|
else
|
|
return {size: (bytes / (1024 ** i)).toFixed(1) , unit: sizes[i] }
|
|
|
|
}
|
|
|
|
|
|
}
|