johnspackman / uploadmgr Goto Github PK
View Code? Open in Web Editor NEWUploads files with background uploads and progress feedback on modern browsers
Uploads files with background uploads and progress feedback on modern browsers
I have found that when listening to a file's changeProgress
event, the file's state
never becomes the final state of uploaded'
. So something like the following will never execute the the code when the state is uploaded
.
let uploader = new com.zenesis.qx.upload.UploadMgr(this.upload, uploadUrl);
uploader.addListener('addFile', function(evt) {
let file = evt.getData();
let progressListenerId = file.addListener('changeProgress', function(evt) {
let file = evt.getTarget();
let uploadedSize = evt.getData();
if(file.getState() === 'uploading')
{
console.log('uploading...');
}
else if(file.getState() === 'uploaded')
{
// this is never executed...
console.log('finished uploading!');
}
}
});
I have made a fix by firing the changeProgress
data event in File.js _applyState
function:
// property apply
_applyState: function(value, oldValue) {
qx.core.Assert.assertTrue((!oldValue && value == "not-started")
|| (oldValue == "not-started" && (value == "cancelled" || value == "uploading"))
|| (oldValue == "uploading" && (value == "cancelled" || value == "uploaded")));
// fire the event!
this.fireDataEvent('changeProgress', value);
}
With Microsoft edge browser the drag drop is not working.
Any idea?
The API currently allows for setting "regular" parameters, but I'm using a REST API that demands a particular parameter be specified in the request header.
Derrell Lipman @derrell 13:37
@johnspackman I'm looking at and seeking to understand UploadMgr. Testing it against your server, the demo app tells me it has uploaded my file, but I don't see a multipart/form message being sent, nor any data from my file... yet I get back a 200. Can you enlighten me as to what's going on?
John Spackman @johnspackman 14:00
@derrell so if the request is not multipart/formdata what is it that returns the 200 response?
John Spackman @johnspackman 14:02
basically on modern browsers it uses XMLHttpRequest, and either uses the browser’s native support for FormData to send it as multipart, or uses a FormData shim to achive teh same thing
Derrell Lipman @derrell 14:02
@johnspackman request:
OPTIONS /demoupload HTTP/1.1
Host: www.zenesis.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Access-Control-Request-Headers: content-type, x-file-name, x-requested-with
Accept: /
Referer: http://localhost:8000/Mutualink/wsg.git/frontend/UploadMgr.git/demo/default/source/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
response:
HTTP/1.1 200 OK
Date: Thu, 19 May 2016 12:23:47 GMT
Server: Apache
Allow: GET,HEAD,POST,OPTIONS,TRACE
Content-Length: 0
Connection: close
Content-Type: text/plain; charset=UTF-8
Derrell Lipman @derrell 14:03
@johnspackman That's all that happens, so I'm confused.
John Spackman @johnspackman 14:03
@derrell so an OPTIONS request is the first connection that asks the server what kind of cross site access is allowed; it’s implemented by the browser transparently, and unless the server responds that the request from your server is allowed, thebrowser will return access denies
whats the response for OPTIONS?
Derrell Lipman @derrell 14:04
@johnspackman those two messages are all that are sent in either direction.
John Spackman @johnspackman 14:05
@derrell ah, it looks like the little demo xss server may not be on my site any more
Derrell Lipman @derrell 14:05
@johnspackman What's giving me the 200?
@johnspackman And more importantly, why is the demo telling me "(Completed)" ?
John Spackman @johnspackman 14:06
don’t know, but AFAICR you should get back more than that - like response headers starting Allow-Access-*
John Spackman @johnspackman 14:06
can you setup an upload url on your localhost:8000?
the only thing my server ever did was to allow anyone to upload from any URL, and then delete the file as soon as it arrived
Derrell Lipman @derrell 14:07
I can. I was hoping to work with an existing server first, since I need to create the upload server here and I've never used multer which I think I want to use.
But if yours no longer exists, I'll need to set it up anyway. I'm concerned, though, that it says it worked. Does this indicate a possible UploadMgr bug?
Or maybe it's just a demo bug?
John Spackman @johnspackman 14:08
@derrell possibly. i started migrating it last weekend and i’ll do some more on it next weekend or when I get a mo, but ill add it as an issue so that it gets tracked down
Derrell Lipman @derrell 14:09
I may be a step ahead of you along that path, since I'd like to get this working today.
The com.zenesis.qx.upload.File#size
property seems to be floating between the upload stages; only the value reported at uploading
stage is byte-precise. All the subsequent stages return file size + size of request headers. Here's a log excerpt (UploadMgr demo app, 116260127 byte file):
083557 uploadmgr.demo.Application[16-0]: Added file payara-4.1.1.161.zip
083565 uploadmgr.demo.Application[16-0]: payara-4.1.1.161.zip: state=uploading, file size=116260127, progress=0
083796 uploadmgr.demo.Application[16-0]: Upload payara-4.1.1.161.zip: 1899907 / 116260624 - 2%
083944 uploadmgr.demo.Application[16-0]: Upload payara-4.1.1.161.zip: 14286211 / 116260624 - 12%
084191 uploadmgr.demo.Application[16-0]: Upload payara-4.1.1.161.zip: 20771307 / 116260624 - 18%
...
086077 uploadmgr.demo.Application[16-0]: Upload payara-4.1.1.161.zip: 116260624 / 116260624 - 100%
086581 uploadmgr.demo.Application[16-0]: payara-4.1.1.161.zip: state=uploaded, file size=116260624, progress=116260624
It would be more natural if the size
property would be consistent between the stages and would always reflect the real file size.
I use an upload button as a child control and have a member function that runs on the addFile
event.
The addFile
member function does some checking of the file to meet file size and extension restrictions before calling uploader.getUploadHandler().beginUploads()
. It is clear that the addFile
event is executing when I add a file, but it appears the the upload handler's __queue
is empty when beginUploads()
executes.
So, adding one file does nothing, but adding a second file just afterwards ends up uploading both files, even when the multiple
flag is set to false.
Here is a trace in the console after adding the first file:
016872 project.sections.user.Profile[362-0]: NAME: IcoNinja_b.jpg SIZE: 32291
016873 project.sections.user.Profile[362-0]: QUEUE: [ ]
So you can see that the addFile event is firing normally but the uploader's queue is an empty array; this may be why no uploads occur. However, upon the second (different) file added, I get:
024531 project.sections.user.Profile[362-0]: NAME: IcoNinja_p.png SIZE: 15785
024532 project.sections.user.Profile[362-0]: QUEUE: [ File[613-0] ]
And we can see the uploader's queue is length 1 (I'm guessing the previously added file) but the two files are in fact uploaded.
024544 com.zenesis.qx.upload.XhrHandler[389-0]: onprogress: lengthComputable=true, total=32748, loaded=32748, headerLength=374
024564 com.zenesis.qx.upload.XhrHandler[389-0]: onprogress: lengthComputable=true, total=16241, loaded=16241, headerLength=374
Child control code:
_createChildControlImpl : function(id)
{
var control;
var btnMinMax = 160;
var imgMinMax = 150;
switch(id)
{
case 'profileBtn' :
control = new com.zenesis.qx.upload.UploadButton;
control.set({
minWidth : btnMinMax,
maxWidth : btnMinMax,
minHeight : btnMinMax,
maxHeight : btnMinMax,
padding : 5,
acceptUpload : '.jpg,.png,.gif'
});
var img = control.getChildControl('icon');
img.set({
minWidth : imgMinMax,
maxWidth : imgMinMax,
minHeight : imgMinMax,
maxHeight : imgMinMax,
scale : true
});
this.add(control);
this.__uploader = new com.zenesis.qx.upload.UploadMgr(control, "/uploads");
this.__uploader.set({
autoUpload : false,
multiple : false
});
this.__uploader.addListener('addFile', this.__addFile, this);
break;
}
return control || this.base(arguments, id);
}
The member function that runs on the addFile
event
__addFile : function(e)
{
var file = e.getData();
var fileName = file.getFilename();
var fileSize = file.getSize();
var ext = fileName.split('.').pop().toLowerCase();
if(!qx.lang.Array.contains(['jpg', 'jpeg', 'png', 'gif'], ext))
{
project.Alert.getInstance().setMessage('Invalid file format!</br>Must be of type JPEG, PNG or GIF.');
this.__uploader.getUploadHandler().cancelAll();
//this.info('UPLOADER:', this.__uploader.getUploadHandler().__queue);
return;
}
if(fileSize > 2000000) // 2 MB
{
project.Alert.getInstance().setMessage('File too large!</br>Must be 1 MB or smaller.');
this.__uploader.getUploadHandler().cancelAll();
//this.info('UPLOADER:', this.__uploader.getUploadHandler().__queue);
return;
}
this.info('NAME:', fileName, 'SIZE:', fileSize);
this.info('QUEUE:', this.__uploader.getUploadHandler().__queue);
this.__uploader.setParam("fileName", fileName);
this.__uploader.setParam("sessionId", project.Model.getInstance().getSessionInfo().SESSION_ID);
this.__uploader.getUploadHandler().beginUploads();
var stateListener = file.addListener("changeState", function(evt) {
var state = evt.getData();
var file = evt.getTarget();
if(state == 'uploaded')
{
var btn = this.getChildControl('profileBtn');
btn.setIcon('/uploads/user/' + file.getResponse() + '?nocache=' + Math.random());
}
// Remove the listeners
if (state == 'uploaded' || state == 'cancelled')
{
file.removeListenerById(stateListener);
}
}, this);
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.