Kendo Upload: sync two conrols upload complete - file-upload

I have on html page two kendo upload widgets without autoupload.
When I press button, both controls starts uploading files to the backend.
When all controls sucessfully uploaded files, I need to perform some post processing.
I can subscribe to the complete event, but how do I catch the moment, when both controls are completed?

Keep a count of the completed uploads. Reset it to zero when you start. In the complete event handler (use the same one for each upload widget), increment the counter. When you hit 2, you know both are done.
var uploadCount;
onStartUpload: function () {
uploadCount = 0;
}
uploadComplete: function () {
uploadCount++;
if (uploadCount = 2) {
doPostProcessing();
}
}
You will of course need to check and cater for successful upload, cancelled uploads, re-uploads etc.

Related

Vue2-Dropzone process form when files manually added

Is it possible to manually process the dropzone form (or queue) when the file is manually loaded?
We have the concept of a drivers license. The user uploads a photo and enters other information such as the license number, expiration date, etc.. The user clicks the save button and I call processQueue() which submit the entire form. This all works just fine.
Next, we display this license in a non-form way with an edit button. When they click the "Edit" button, I display the form again and populate the fields with previously entered data including manually adding the previously submitted photo of their license. Basically like this from the documentation:
mounted: () {
var file = { size: 300, name: "Icon", type: "image/png" };
var url = "https://example.com/img/logo_sm.png";
this.$refs.myVueDropzone.manuallyAddFile(file, url);
}
This appears to all work as expected. I see the dropzone with a thumbnail of the previously uploaded file. The input fields are all populated with previously entered data.
The problem occurs when I try to process this form again with:
onSubmit() {
this.$refs.myVueDropzone.processQueue()
}
If they only make changes to the input fields like the license number and do not upload a new file, the onSubmit() or processQueue() does not work. It only works if I remove and re-add a file or add a second file. It's as if it does not recognize a file has been added. Is manuallyAddFile only for displaying and not actually adding the file?
How can I submit this form when the file is manually added?
After a bit of research on Vue2 Dropzone
Manually adding files
Using the manuallyAddFile method allows you to programatically add files to your dropzone area. For example if you already have files on your server that you'd like to pre-populate your dropzone area with then simply use the function when the vdropzone-mounted event is fired.
source
So the solutions is to check and see if anything needs to be processed in your queue. Since you manually added the file you already have it, it does not need to be uploaded again. Only if the user adds a new file does it need to be uploaded.
You could do this a few ways, but I would recommend something like the example below for it's simplicity:
onSubmit() {
if (this.$refs.myVueDropzone.getQueuedFiles().length) {
this.$refs.myVueDropzone.processQueue()
}
}
If you need to wait until the queue has finished processing to send your form you can leverage vdropzone-queue-complete. Below is a quick example:
<template>
<!-- SOME FORM ELEMENTS HERE -->
<vue-dropzone
ref="myVueDropzone"
:options="dropzoneOptions"
#vdropzone-error="errorUploading"
#vdropzone-success="fileUploaded"
#vdropzone-queue-complete="submitForm"
/>
<button #click="saveForm">Save</button>
</template>
<script>
export default {
methods: {
saveForm () {
if (this.$refs.myVueDropzone.getQueuedFiles().length) {
this.$refs.myVueDropzone.processQueue()
} else {
this.submitForm()
}
},
errorUploading (file, message, xhr) {
// do something when a file errors
// perhaps show a user a message and create a data element to stop form from processing below?
},
fileUploaded (file, response) {
// do something with a successful file upload. response is the server response
// perhaps add it to your form data?
},
submitForm () {
// Queue is done processing (or nothing to process), you can now submit your form
// maybe check for errors before doing the below step
// do what ever you need to submit your form this.$axios.post(...) etc.
}
}
}
</script>

How to cancel all grid store XHR requests but the last [dojo dgrid]?

I am using dojo dgrid 0.3.14
I have live search toolbar
On every user input change i do
searchGrid.set("store", searchStore, query);
It works fine but back end returns data in no order.
So sometimes grid is being refreshed with slow previous response.
How to cancel all grid store XHR requests but the last?
current solution for DGrid is
_abortQuery: function () {
// console.log("_abortQuery" , this._refreshDeferred);
if (this._refreshDeferred && this._refreshDeferred.cancel){
this._refreshDeferred.cancel();
}
return this;
},
refresh: function () {
this._abortQuery();
return this.inherited(arguments);
},
If you're responding to user input on every keypress, I would suggest that rather than seeking to cancel requests, you instead debounce the input. dgrid has a utility function named debounce in dgrid/util/misc for this purpose. Debouncing refers to the practice of listening to an event, but only responding once the event has stopped firing for a certain period of time.
See https://github.com/SitePen/dgrid/wiki/misc for more information.

blueimp file upload. How to clean existing filelist

I have goggled a lot, but have not found a solution for my issue. The author of the widget references to the last answer of FAQ, but the FAQ does not have the answer or I cannot find it. I suppose it was updated since that time. Other fellows who faced the same issue and asked the same question just gone and did not provide any solution.
Anyway, in my case I have a table with button Pictures:
When a user clicks one of pictures button, modal dialog is shown. The user now can manage pictures for the chosen row. He can upload, delete pictures and so on. When the user opens the dialog for second row in the table he should see pictures for the second row only. It tells me that I have to clean the list of uploaded files every time user hits Pictures button to see the dialog. He will receive list of pictures which corresponds to chosen row from the server. Unfortunately, when I retrieve the list for the chosen row, the received files are added to the existing list.
Could you tell me how I can clean the list or reset the widget without removing files on the server side?
UPDATE I have used the following piece of code as a temporary solution.
jQuery.ajax({
url: "<YOUR URL HERE>",
dataType: 'json',
context: $('#fileupload')[0]
}).done(function (result) {
jQuery("#fileupload").find(".files").empty(); //this line solves the issue
jQuery(this).fileupload('option', 'done').call(this, null, { result: result });
});
Thank you.
i was also trying for one hour to get my upload work ;)
here is, how i solved this problem:
$('#html5FileInput').fileupload({
....
add: function (e, data) {
$.each(data.files, function (index, file) {
var newFileDiv = $(newfileDiv(file.name));
$('#fsUploadProgressHtml5').append(newFileDiv);
newFileDiv.find('a').bind('click', function (event) {
event.preventDefault();
var uploadFilesBox = $("#fsUploadProgressHtml5");
var remDiv = $(document.getElementById("fileDiv_" + event.data.filename));
removeFileFromArray(event.data.filename);
remDiv.remove();
data.files.length = 0;
...
});
data.context = newFileDiv;
});
...
)};
as you can see i create inside the add-event my file-dataset with 'newfileDiv(file.name)'. this creates a div with all information about the file (name, size, ...) and an ankor that exists for deleting the file from the list. on this ankor i bind a click-event in which i have the delete implementation.
hope this helps!
I know this isn't the most elegant solution, but I needed a very quick and dirty...so here's what I did (using jQuery).
//manually trigger the cancel button for all files...removes anything that isn't uploaded yet
$('.fileupload-buttonbar .cancel').first().trigger('click');
//check the checkbox that selects all files
if(!$('.fileupload-buttonbar .toggle').first().checked) {
$('.fileupload-buttonbar .toggle').first().trigger('click');
}
//manually trigger the delete button for all files
$('.fileupload-buttonbar .delete').first().trigger('click');
I know this isn't the best way. I know it isn't elegant...but it works for me and removes everything from the plugin.
If you have added file names or anything else from the plugin to any local arrays or objects, you'll need to clean those up manually (I have several handlers that fire on fileuploadadded, fileuploadsent, fileuploadcomplete, fileuploadfailed, and 'fileuploaddestroyed` events).
protected function get_file_objects($iteration_method = 'get_file_object') {
$upload_dir = $this->get_upload_path();
if (!is_dir($upload_dir)) {
return array();
}
return array_values(array_filter(array_map(
array($this, $iteration_method)
//scandir($upload_dir)
//File listing closed by Doss
)));
}
there is a scandir function responsible for listing the files. just uncomment it like i have done above and your problem is solved. it can be found in the UploadHandler.php file.

How to precompile processingjs sketch to speed load times?

The loading times of my processingjs webpage are getting pretty hairy. How can I precache the compilation of processing to javascript?
It would be acceptable for my application to compile on first entering the webpage (maybe keeping the result in the local store?) and then reuse the compilation on subsequent loads.
There's two ways to drive down load time as experienced by the user. The first is using precompiled sketches, which is relatively easy: github repo, or even just download the master branch using github's download button (https://github.com/processing-js/processing-js), and then look for the "./tools/processing-helper.html" file. This is a helper page that lets you run or compile sketches to the JavaScript source that Processing.js uses. You will still need to run this alongside Processing, since it ties into the API provided, but you can use the "API only" version for that. Take the code it generates, prepend "var mySketch = ", and then do this on your page:
<script src="processing.api.js"></script>
<script>
function whenImGoodAndReady() {
var mySketch = (function.....) // generated by Processing.js helper
var myCanvas = document.getElementById('mycanvas');
new Processing(myCanvas, mySketch);
}
</script>
Just make sure to call the load function when, as the name implies, you're ready to do so =)
The other is to do late-loading, if you have any sketches that are initially off-screen.
There's a "lazy loading" extension in the full download for Processing.js - you can include that on your page, and it will make sketches load only once they're in view. That way you don't bog down the entire page load.
Alternatively, you can write a background loader that does the same thing as the lazy loading extension: turn off Processing.init, and instead gather all the script/canvas elements that represent Processing sketches, then loading them on a timeout using something like
var sketchList = [];
function findSketches() {
/* find all script/canvas elements */
for(every of these elements) {
sketchList.append({
canvas: <a canvas element>,
sourceCode: <the sketch code>
});
}
// kickstart slowloading
slowLoad();
}
function slowLoad() {
if(sketchList.length>0) {
var sketchData = sketchList.splice(0,1);
try {
new Processing(sketchData.canvas, sketchData.sourceCode);
setTimeout(slowLoad, 15000); // load next sketch in 15 seconds
} catch (e) { console.log(e); }
}
}
This will keep slow-loading your sketches until it's run out.

How do I get data from a background page to the content script in google chrome extensions

I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.