Javascript parameter to function that loads with page, Uppy File Upload - javascript

Uppy is used for uploading files by drag & drop interface.
I want to pass a value input given by user from html interface
but the javascript is already processed before the user gives his input.
if i use .onchange() with the userinput then it does not destroy/clear the previously created file drop area but creates too many new file drop areas inside #drag-drop-area
<input id="userinput" value="Car">
<div id="#drag-drop-area"></div>
var userinput = document.getElementById("userinput").value
var URL = 'example.com/post-submit/?category='+userinput;
var uppy = Uppy.Core()
.use(Uppy.Dashboard, {
inline: true,
target: '#drag-drop-area',
inputName: 'imageFile[]',
height:"250px",
width:"100%"
})
.use(Uppy.XHRUpload, {endpoint: URL", headers: {
'X-CSRF-Token': " {{csrf_token()}} "}
})
uppy.on('complete', (result) => {
console.log('Upload complete! ', result.successful)
})

Related

Dropzone check if files names exists before processing queue

I am using dropzone for uploading files which I save with some meta data in a database in the backend.
When a user tries to upload a bulk of files I want to check if he has already uploaded a file with this name and warn him with an alert with an option to continue ot stop.
So I disabled the autoProcessQueue.
I am also listening for addedfile event, I get the name, I perform an ajax to check if it exists in the database and return true or false, good.
Let's say the user tries to upload 40 files which all already exist, I don't want 40 warnings that this file already exists, I want one notification printing all 40 filenames.
I was looking for addedfile but for multiple files, I didn't found a solution.
Here is my code for now
This is where I'm stuck
How can I know when I've checked every file ?
$(document).ready(function() {
#if(isset($checkRoute))
function filenameExists(name) {
$.ajax({
type: 'GET',
url: '{{ $checkRoute }}',
data: {
name: name
}
})
.done(function(res) {
// returns true or false
return res
})
.fail(function(err) {
console.log(err)
})
}
#endif
let existingFilenames = []
let fileCount = 0
$('#{{ $element_id }}').dropzone({
url: "{{ $upload }}", // Set the url for your upload script location
paramName: "documents", // The name that will be used to transfer the file
maxFiles: 100,
maxFilesize: 100, // MB
parallelUploads: 100,
timeout: 240000,
addRemoveLinks: true,
acceptedFiles: "application/msword, application/vnd.ms-excel, application/pdf, image/*, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, image/*",
uploadMultiple: true,
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
init: function() {
#if(isset($checkRoute))
this.on('addedfile', function(file) {
console.log(this.getAcceptedFiles())
fileCount++
if (filenameExists(file.name)) {
console.log(file.name)
existingFilenames.push(file.name)
}
})
#endif
},
autoProcessQueue: false,
sendingmultiple: function (files) {
// Begin loading
KTApp.blockPage({
overlayColor: '#000000',
type: 'v2',
state: 'success',
message: '{{ __('documents_uploading') }}'
});
},
queuecomplete: function () {
// End loading
KTApp.unblockPage();
$.notify({
// options
message: '{{ __('documents_upload_success') }}'
}, {
// settings
type: 'success',
placement: {
from: "top",
align: "center"
},
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
});
window.location.replace("{{ $redirect }}");
}
});
});
Another thing that concerns me is how will I process the queue at the press of the button in the notification.
I had a similar problem as i wanted to provide the user with a dropdown of different upload directories on the server.
As each directory has a different ruleset of acceptedFiles, the static option acceptedFiles was out of the question.
Instead i used a combination of listening to the drop event on dropzone init and to "extend" the accept function:
The drop event gets the total number of files dropped and stores it in droppedFilesCounter. It also initializes/resets a global Object dzCustomFeedback and clears the "feedback" area from prior feedback.
The extended accept function, which is called for by each dropped file checks which upload directory is currently selected and compares the current file extension against the configured accepted ones.
If there is a match the done() function "bubbles" an "all clear".
Otherwise the file is removed from the preview list (or actually never makes it into it) and the global dzCustomFeedback Object cumulates error-messages of the type invalidFileTypes for all files accordingly.
Once all files have been run through the accept function (droppedFilesCounter == 0) and some feedback messages have been prepared the prepareFeedback function is called, which basically populates a jQuery <div> container with the cumulated content of dzCustomFeedback.
init: function() {
var myDropzone = this;
myDropzone.on("drop", function(event) {
if(typeof event.dataTransfer.files == 'object')
{
droppedFilesCounter = event.dataTransfer.files.length;
}
dzCustomFeedback = {};
jQuery('#dz-feedback').empty();
});
},
accept: function(file, done) {
/ * Erweiterung der vordefinierten accept Function * /
customTypeSelector = document.getElementById("selectUploadFolder");
var currentAcceptedFiles = customTypeAcceptedFiles[customTypeSelector.options[customTypeSelector.selectedIndex].value]
var currentFileExtension = file.name.split(".").pop()
droppedFilesCounter--;
if (typeof customTypeAcceptedFiles[customTypeSelector.options[customTypeSelector.selectedIndex].value] == "object"
&&
jQuery.inArray(currentFileExtension, currentAcceptedFiles["extensions"] ) >= 0) {
//accepted file
done();
}
else {
//Unaccepted file revert
this.removeFile(file);
if(typeof dzCustomFeedback["invalidFileTypes"] == "undefined")
{
dzCustomFeedback["invalidFileTypes"] = {
"msg": [
uploadDndConf["textElements"]["invalidFileTypesUploadFolder"].replace("{{uploadFolder}}", currentAcceptedFiles["label"])
, currentAcceptedFiles["extensions"].join()
]
, "type": "error"
, "filesIgnored": {} };
}
dzCustomFeedback["invalidFileTypes"]["filesIgnored"][file.name] = file;
done(this.options.dictInvalidFileType);
}
if(droppedFilesCounter == 0 && !jQuery.isEmptyObject(dzCustomFeedback))
{
prepareFeedback(dzCustomFeedback);
}
},

After image uploaded through dropzone, access parent div

I am confuse i dont know how to access parent div. Let me summarize it!
Actually i have multiple dropzone which i initialize using class '.abc'
above each dropzone there is input where i put image name for uploading. here is my code
$('.kt_dropzone_1').dropzone({
url: base_url + 'product/uploadPic', // Set the url for your upload script location
paramName: "file", // The name that will be used to transfer the
maxFiles: 1,
maxFilesize: 5, // MB
addRemoveLinks: true,
accept: function (file, done) {
done();
},
success: function (file, response) {
alert($(this).attr('data-abc')); // undefined
alert($(this).parent().parent.html()); // undefined
},
});
here is html this is in looop so consider it multiple
<input type="hidden" class="img-upload" name="old" value=""/>
<div class="col-md-12 pull-left">
<div class="dropzone dropzone-default kt_dropzone_1">
<div class="dropzone-msg dz-message needsclick">
<h3 class="dropzone-msg-title">Drop files here or click to upload.</h3>
<span class="dropzone-msg-desc">This is just a demo
dropzone. Selected files are <strong>not</strong>
actually uploaded.</span>
</div>
</div>
</div>
i try use custom attribute to pass input id dynamic still not work
i dont know how to get current div object to access parent html or input or div
I could suggest you small changes for this. Move input type hidden inside of
and just above the dropzone div.
Now to refer the correct dropzone please give a try to following updated code.
$('.kt_dropzone_1').dropzone({
var this_dropzone = $(this);
url: base_url + 'product/uploadPic', // Set the url for your upload script location
paramName: "file", // The name that will be used to transfer the
maxFiles: 1,
maxFilesize: 5, // MB
addRemoveLinks: true,
accept: function (file, done) {
done();
},
success: function (file, response) {
this_dropzone.closest("div").find(".img-upload").attr('data-abe', 'value to be set');
this_dropzone.closest("div").find(".img-upload").val('you can set anyvalue here');
},
});
This should work as you want!

TinyMce how to upload multiple Images in a Post into same upload folder and how to stop imagetools to create Blob

I have 2 Problems I can't seem to find a solution for. I use
Laravel 5.6
Vue JS Component
TinyMCE 4.9.1
I have crated a vueJs Component for my Form which includes TinyMce and it all seems to work so far. On the Server side I create a folder for each Post I create and the Folder Name gets saved in the Post Table so when I delete a Post the Folder with all the Photos should be deleted.
First of all, I have a understanding Problem. I thought that if I set automatic_uploads: false,
the Photo would not be uploaded straight away, but it does. If that would not happen, then my first Problem would be fixed, because all Photos would be uploaded at the same time.
Lets supply the Sourcecode for a better understanding:
my vueJs Component
<template>
<div>
<form method="post" action="" #submit.prevent="onSubmit">
<fieldset class="add-form"><legend class="add-form">
<h3>Article Details</h3></legend>
<label class="required" for="fname">Headline</label>
<input class="form-control" v-model="post.title" id="fname">
<span class="invalid-feedback" v-text="errors.get('title')"></span>
<input class="form-control" v-model="folder" id="folder">
<tinymce v-model="post.body"
:plugins="myPlugins"
:toolbar ="myToolbar1"
:init="myInit"
>
</tinymce>
<script>
import Editor from '#tinymce/tinymce-vue';
// Import TinyMCE
import tinymce from 'tinymce/tinymce';
// A theme is also required
import 'tinymce/themes/modern/theme';
export default{
components: {
'tinymce': Editor // <- Important part
},
data () {
return {
name: 'app',
folder: null,
myModel:'',
theme: "modern",
myToolbar1: 'undo redo | bold italic underline forecolor backcolor | alignleft aligncenter alignright alignjustify | hr bullist numlist outdent indent | link image table | code preview',
myPlugins: "link image code preview imagetools table lists textcolor hr wordcount",
myInit: {
setup: function(editor){
automatic_uploads: false,
editor.on('NodeChange', function (e) {
if(e.element.tagName === "IMG"){
//e.element.setAttribute("data-original", e.element.currentSrc);
// e.element.setAttribute("src", newSrc);
}
});
},
images_dataimg_filter: function(img) {
return false;
return img.hasAttribute('internal-blob');
},
convert_urls : false,
height:500,
automatic_uploads: false,
images_upload_base_path: '/../../',
relative_urls : false,
// override default upload handler to simulate successful upload
images_upload_handler: function (blobInfo, success, failure) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '/memberarea/api/upload-image');
var token = document.head.querySelector("[name=csrf-token]").content;
xhr.setRequestHeader("X-CSRF-Token", token);
xhr.onload = function() {
var json;
var folder2;
if (xhr.status != 200) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
this.folder = json.folder;
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
}
},
result:[],
"post": {
title: '',
teaser:'',
body: '',
tags:[],
},
errors: new Errors(),
availableTags:'',
tags:[],
}},
computed: {},
mounted: function () {
this.getTags();
},
methods: {
getTags(){
axios.get('/api/tags/id')
.then((response) => {
this.availableTags = response.data;
})
.catch(function () {
});
},
onSubmit(){
{
let uri = '/admin/news/save-post';
var input = this.post;
axios.post(uri, input)
.then((response) => {
window.location.href = response.data.redirect;
})
.catch(error => this.errors.record(error.response.data.errors));
}
}
}
}
The Image Controller to upload the Image:
public function uploadImages()
{
$folder = uniqid();
if (!\Storage::exists($folder)) {
\Storage::disk('posts')->makeDirectory($folder);
}
$imgpath = \Storage::disk('posts')->put($folder,request()->file('file'));
return \Response::json(['folder' => $folder, 'location' => '/storage/uploads/posts/'.$imgpath]);
}
I have now got the following Problem. I select a Photo, a Folder gets created the Photo uploaded. If I add another Photo a new Folder gets created instead of uploading it into the same Folder. So I thought to return the Foldername from the Upload Function back to the Component, save it in a hidden Input Field and sent it back to the Upload Method again, unfortunately I fail already to set the Value into the Hidden Input Field. Question now, how can that be solved best? any suggestion welcome.
Second Problem, I integrated the imagetools Plugin, but as soon I use it it turns the Image into a Blob. again I do not understand the instructions correctly, but I thought by adding below it would switch this off, but no luck. So I might have an Image saved as a Blob and at the same time saved in a Folder and the next time only the Path is saved in the database. How can I solve this?
images_dataimg_filter: function(img) {
return false;
// return img.hasAttribute('internal-blob');
},
For your first problem, according to tinymce documentation automatic_upload will do nothing if images_upload_url is not specified. If you implement images_upload_url upload will get triggered whenever you call editor.uploadImages().

Quill editor + VueJS2 image upload: Base64 image to URL

Using editor from here: https://github.com/surmon-china/vue-quill-editor
I want to save images from Quill editor to MySQL database, but bigger images in base64 are too long to insert.
I tried to write custom image handler, so that it auto uploads image to server and server returns image URL but now I'm stuck.
Here is my current HTML:
<quill-editor v-model="content"
:options="editorOption"
#onEditorBlur($event)"
#onEditorFocus($event)"
#onEditorReady($event)"
#onEditorChange($event)">
</quill-editor>
Adding image handler to editor like this:
onEditorReady(editor) {
editor.getModule('toolbar').addHandler('image', this.imageHandler);
console.log('editor ready!', editor);
},
And my own handler:
imageHandler(image, callback){
console.log(image); // Always true
console.log(callback); // Always undefined
// Should get image in here somehow..
var sendData = {
image: 'SomethingShouldBeInHere',
};
// Send image to server,
// Server will return link to image
axios.put('/testImageUpload', sendData)
.then(function(cbData) {
// In here should add image tag to editor somehow..
})
.catch(function (error) {
console.log(error);
});
},
I tried this: Add support for custom image handler
But it doesn't work, since image is always true and callback is undefined.
Tried this too: Quill imageHandler Demo
It has same problems first link.
Currently server is hardcoded to return "http://localhost/images/php.jpg"
If possible I would not use any libraries (jQuery, dropzone, etc)
I thought I can perhaps check if image was inserted in onEditorChange(), then send request to server, get URL, search for this base64 in editor and replace it with URL, but it doesn't seem right.
set handlers in your options like this
editorOption: {
modules: {
toolbar: {
container: [['image'], ...],
handlers: {
'image': function(){
document.getElementById('getFile').click()
}
}
}
}
}
methods: {
uploadFunction(e){
//you can get images data in e.target.files
//an single example for using formData to post to server
var form = new FormData()
form.append('file[]', e.target.files[0])
//do your post
}
}
<template>
<quill-editor v-model="content"
:options="editorOption"
#change="oneEditorChange($event)">
</quill-editor>
<input type="file" id="getFile" #change="uploadFunction($event)" />
</template>
This my source code....
//Template
<input type="file" #change="uploadFunction" id="file" hidden>
<quill-editor
v-model="model"
:options="editorOption"
ref="quillEdit">
</quill-editor>
and script
//script
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import Quill from "quill";
import { quillEditor } from "vue-quill-editor";
import ImageResize from "quill-image-resize-module";
import axios from '~/plugins/axios'
export default {
data() {
model: '',
selectedFile : '',
editorOption: {
// some quill options
modules: {
toolbar: {
container: [["bold", "image"]],
handlers: {
image: function() {
document.getElementById('file').click()
}
}
},
imageResize: {
modules: ["Resize", "DisplaySize", "Toolbar"]
}
}
},
},
methods: {
uploadFunction(e){
this.selectedFile = e.target.files[0];
var form = new FormData();
form.append("file", this.selectedFile);
form.append("name", this.selectedFile.name);
//upload image to server
axios.post('media-save', form,{
'headers': {
'Content-Type': "multipart/form-data"
}
})
.then(r => {
console.log('success')
//this code to set your position cursor
const range = this.$refs.quillEdit.quill.getSelection()
//this code to set image on your server to quill editor
this.$refs.quillEdit.quill.insertEmbed(range.index , 'image', `http://your.api/${r}`)
})
.catch(e => {
console.log('error')
}
}
}

Implement dropzone in mvc razor form

I have a mvc form with multiple fields that are calling custom edit views.
I need to implement dropzone instead of the standard file import control.
I cant figure out how to get the file names and pass them together with the dropzone. I am searching the internet for 2 days and no results.
The form looks like this:
#using (Html.BeginForm("contr", "action", new { themeid = ViewBag.ThemeId, #class = "dropzone"}, FormMethod.Post, new { #enctype = "multipart/form-data" }))
At the end I have an Edit view that contains the dropzone div:
<div id="fileInput" class="dropzone">
<div class="fallback">
<input name="files" type="file" multiple />
</div>
</div>
Function for the dropzone:
function initDropzone() {
new Dropzone('#fileInput', {
url: '#',
autoProcessQueue: false,
uploadMultiple: true,
addRemoveLinks: true,
autoDiscover: false,
parallelUploads: 100,
dictDefaultMessage: "Click or drop files to upload",
init: function () {
var myDropzone = this;
$('#submit-all').click(function (e) {
$(".dz-progress").show();
myDropzone.processQueue();
});
myDropzone.on('success', function () {
myDropzone.removeAllFiles();
//$('#name').val('');
});
myDropzone.on("sending", function (file, xhr, formData) {
formData.append("file", file); // Append all the additional input data of your form here!
});
myDropzone.on("addedfile", function (event) {
$(".dz-progress").hide();
});
}
});
As most examples suggest I call processQueue when submit is clicked, but the problem is that the controller action is called twice, once with the files but without the other models, and the next time with the models but without the files.
I can't use stopPropagation on submit because I call different views based on the logic in the action method.
The basic question is how I can take the files from dropzone and append them to form data.
Hidden fields does not work, I don't know why.
Any help would be appreciated.

Categories