Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    UploadItem with multiple file select

    Hello,

    is there a way to set the new HTML5 "multiple" attribute of an UploadItem, so that multiple files can be selected and uploaded at once without any addons, flash etc.?
    So that the resulting html looks like

    <input type="file" multiple="multiple" ..../>

    As far as I know, it's already supported by safari, firefox and chrome.
    Info: http://hacks.mozilla.org/2009/12/multiple-file-input-in-firefox-3-6/

    I am using Smart GWT 2.2

    Jens

    #2
    I am also very interested in this feature. Any news on this?

    Comment


      #3
      Any news on this matter? I'm also interested in this feature.

      Comment


        #4
        A dirty workaround...

        ...that works as least for me (that's all I need 4 now):

        The key idea is to add the missing multiple attribut after to the resulting input element after has been attached to the DOM tree (via a deferred command) ...

        Code:
         
        public class UploadDialog extends Window
        {
        	private DynamicForm uploadForm;
        	private UploadItem fileItem;
        	private UploadListener listener;
        
        	public UploadDialog()
        	{
        		...
        		uploadForm= new DynamicForm();
        		fileItem= new UploadItem("theMostUniqueName");
        		Button uploadButton= new Button("Upload");
        
        		//setup components and add them to canvas
        		...
        
        		Scheduler.get().scheduleDeferred(new Command(){
        			@Override
        			public void execute(){
        				enableUpload();
        			}
        		});
        	}
        
        	private native void enableUpload() /*-{
        		var newAttr= document.createAttribute('multiple');
        		newAttr.nodeValue='multiple'; 
        		$wnd.document.getElementsByName('theMostUniqueName')[0].setAttributeNode(newAttr); 
        	}-*/;
        }
        In your FileUploadServlet you now can iterate over the multiple file (using commons fileupload)

        Code:
        private void processFiles(HttpServletRequest request, HttpServletResponse response)
        {
        	ServletFileUpload upload= new ServletFileUpload();
        	FileItemIterator iter= upload.getItemIterator(request);
        	
        	// pick up parameters first and note actual FileItem
        	while (iter.hasNext())
        	{
        		FileItemStream item= iter.next();
        		String name= item.getFieldName();
        		...
        	}
        }
        Last edited by weihnachtsmann; 3 Feb 2012, 10:46.

        Comment


          #5
          Thanks for contributing that weihnachtsmann, we hadn't realized it was that easy. Just to confirm, this does not work in IE8, but does in IE9 right?

          Comment


            #6
            Sorry i forgot to mention. I can only confirm that it works for Firefox 7.0.1/9.0.1 and Chrome 16.0.912.77. I can't check IE since I am using Linux. It should work for all browser that support the multiple attribute.

            By the way...thx 4 your enduring support to users in this forum. This is great...
            Last edited by weihnachtsmann; 5 Feb 2012, 16:03.

            Comment


              #7
              Uploading multiple files is a specific part of HTML5.

              Code:
              <input type="file" multiple="multiple">
              is not supported by IEx (x<10) at all. The code is still working but only a single file is selectable. It would be nice if some yould confirm that it works for IE10. However, FF/Chrome/Opera support multi-file upload.

              Comment


                #8
                Hallo,

                Code:
                public class GngsUploadForm extends DynamicForm {
                
                	private UploadItem uploadItem = new UploadItem();
                	private boolean uploadItemRequired = true;
                	private String randomUploadItemName = "";
                	
                	private void initForm(final boolean multiple) {
                		this.setTarget("fileUploadiFrame");
                		this.setEncoding(Encoding.MULTIPART);
                		this.setAction(GWT.getModuleBaseURL() +"singleFileUploadServlet");
                		
                
                		randomUploadItemName = Long.toString(new Date().getTime()); 
                		uploadItem.setName(randomUploadItemName);
                		uploadItem.setTitle("File: ");
                		
                		if(uploadItemRequired)
                			uploadItem.setRequired(true);
                		
                		super.setFields(uploadItem);		
                		
                		Scheduler.get().scheduleDeferred(new Command(){
                			@Override
                			public void execute(){
                				if(!randomUploadItemName.equals("") && multiple) {
                					setMultiple(randomUploadItemName);
                				}
                			}
                		});	
                	}
                	
                	/**
                	 * 
                	 */
                	public GngsUploadForm(GngsUploadListener listener, boolean multiple) {
                		super();
                		
                		initForm(multiple);
                		
                		if(listener != null)
                			initComplete(listener);
                	}
                
                	/**
                	 * @param jsObj
                	 */
                	public GngsUploadForm(JavaScriptObject jsObj, GngsUploadListener listener, boolean multiple) {
                		super(jsObj);
                
                		initForm(multiple);		
                		
                		if(listener != null)
                			initComplete(listener); 
                	}
                	
                	@Override
                	public void setFields(FormItem... fields) {
                		FormItem[] newFields = new FormItem[fields.length+1];
                		
                		if(uploadItemRequired)
                			uploadItem.setRequired(true);
                		newFields[0] = uploadItem;
                		
                		for(int i = 1; i < fields.length+1; i++) {
                			newFields[i] = fields[i-1];
                		}
                		
                		super.setFields(newFields);
                	}
                	
                	/*
                	 * if true the uploadItem is required
                	 * if false the uploadItem is not required
                	 * default: true
                	 * @param 
                	 */
                	public void setUploadFieldRequired(boolean uploadItemRequired) {
                		this.uploadItemRequired = uploadItemRequired;
                	}
                	
                	private native void initComplete(GngsUploadListener listener) /*-{
                	   $wnd.uploadComplete = function (filename) {
                	   		listener.@de.wwu.imi.gngs.client.helper.GngsUploadListener::uploadComplete(Ljava/lang/String;)(filename);
                	   };
                	}-*/;
                	
                	private native void setMultiple(String randomUploadItemName) /*-{
                		var newAttr= document.createAttribute('multiple');
                		newAttr.nodeValue='multiple';
                		$wnd.document.getElementsByName(randomUploadItemName)[0].setAttributeNode(newAttr); 
                	}-*/;	
                }
                i'm using this class for my Fileuploads. This works fine when i have one Form on one View. But when i have more then one Form on the View i'm getting this exception:

                Code:
                14:16:50.938 [ERROR] [gngs] Uncaught exception escaped
                
                com.google.gwt.core.client.JavaScriptException: (TypeError): $wnd.document.getElementsByName(randomUploadItemName)[0] is undefined
                    at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:248)
                    at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
                    at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
                    at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:289)
                    at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid(JavaScriptHost.java:107)
                    at de.wwu.imi.gngs.client.helper.GngsUploadForm.setMultiple(GngsUploadForm.java)
                    at de.wwu.imi.gngs.client.helper.GngsUploadForm.access$1(GngsUploadForm.java:112)
                    at de.wwu.imi.gngs.client.helper.GngsUploadForm$1.execute(GngsUploadForm.java:51)
                    at com.google.gwt.core.client.impl.SchedulerImpl$Task$.executeScheduled$(SchedulerImpl.java:50)
                    at com.google.gwt.core.client.impl.SchedulerImpl.runScheduledTasks(SchedulerImpl.java:228)
                    at com.google.gwt.core.client.impl.SchedulerImpl.flushPostEventPumpCommands(SchedulerImpl.java:388)
                    at com.google.gwt.core.client.impl.SchedulerImpl$Flusher.execute(SchedulerImpl.java:78)
                    at com.google.gwt.core.client.impl.SchedulerImpl.execute(SchedulerImpl.java:138)
                    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:616)
                    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
                    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
                    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
                    at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
                    at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
                    at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
                    at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
                    at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
                    at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
                    at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
                    at sun.reflect.GeneratedMethodAccessor171.invoke(Unknown Source)
                    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:616)
                    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
                    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
                    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
                    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
                    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
                    at java.lang.Thread.run(Thread.java:679)
                obviously this has something to do with the nativ method setMultiple(String randomUploadItemName) but i dont know why i get this exception :(

                greetings raven22k

                Comment


                  #9
                  Multiple Multi-Uploads

                  I guess this error is because there is no such html element with this name so you cant call setAttributeNode(newAttr) on it. Maybe it was already removed from the DOM tree.

                  One of your problems is overwriting the single uploadComplete javascript function for each UploadForm you create. Hence, if the iframe executes the javascript snippet returned by the Servlet, it calls its parents javascript uploadComplete function. This in turn invokes the uploadComplete function of *the last instanciated* UploadDialog.

                  I recognized this when i tried to do multiple parallel uploads in a tabbed application. If the first download callback was fired, the last dialog with the UploadItem was destroyed causing the upload to fail on the server side with an EOF exception.

                  In order to get multiple UploadForms with callbacks working you have to change your code so something like this:

                  Code:
                  public class UploadDialog extends Dialog
                  {
                     private final String uploadId;
                     
                     public UploadDialog(...)
                     {
                        uploadId= String.valueOf(new Date().getTime());
                        final String uploadItemName= uploadId+"_uploadItem";
                        String iframeName= uploadId+"_iframe";
                  
                        addCompletionCallback(this, uploadId);
                  
                        final UploadItem fileItem= new UploadItem(uploadItemName);
                  
                        final HiddenItem timestampItem= new HiddenItem(ATTRIBUTE_NAME_TIMESTAMP);
                        timestampItem.setValue(uploadId);
                  
                        final DynamicForm mainForm= new DynamicForm();
                        mainForm.setEncoding(Encoding.MULTIPART);
                        mainForm.setMethod(FormMethod.POST);
                        mainForm.setTarget(iframeName);
                        mainForm.setAction(TARGET_URL);
                  
                        mainForm.setItems(fileItem, timestampItem, ...);
                  		
                        HLayout layout= new HLayout();
                        layout.setAlign(Alignment.CENTER);
                        layout.addMember(mainForm);
                        addItem(layout);
                  
                        NamedFrame magicFrame= new NamedFrame(iframeName);
                        magicFrame.setWidth("1px");
                        magicFrame.setHeight("1px");
                        magicFrame.setVisible(false);
                        addChild(magicFrame);
                  
                        IButton saveButton= new IButton();
                        saveButton.addClickHandler(new ClickHandler(){
                           public void onClick(ClickEvent event){
                              if(fileItem.getValue() == null || fileItem.getValueAsString().isEmpty())
                              {
                                 SC.say("Select a file before uploading.");
                                 return;
                              }
                              mainForm.submitForm();
                              UploadDialog.this.setVisible(false);
                           }	
                        });
                  
                        Scheduler.get().scheduleDeferred(new ScheduledCommand(){
                           public void execute(){
                              enableMultiFileUploadNative(uploadItemName);
                           }
                        });
                     }
                  
                     public void uploadComplete(String msg)
                     {
                        SC.say(msg);
                        removeCompletionCallback(uploadId);
                        setVisible(true);
                        cancelClick();
                        destroy();
                     }
                  
                     private native void addCompletionCallback(UploadDialog upload, String id) /*-{
                        if(typeof($wnd.uploadCompleteFunctions)=="undefined")
                           $wnd.uploadCompleteFunctions = {};
                        $wnd.uploadCompleteFunctions[id]= function(msg){
                           upload.@my.package.UploadDialog::uploadComplete(Ljava/lang/String;)(msg);
                        };
                     }-*/;
                  
                     private native void removeCompletionCallback(String id) /*-{
                        delete $wnd.uploadCompleteFunctions[id];
                     }-*/;
                  
                     private native void enableMultiFileUploadNative(String uploadItemName) /*-{
                        var newAttr= document.createAttribute('multiple');
                        newAttr.nodeValue='multiple';
                        var inputElement= $wnd.document.getElementsByName(uploadItemName)[0];
                        inputElement.setAttributeNode(newAttr);
                     }-*/;
                  }

                  And the server side...
                  Code:
                  public class FileUploadServlet extends HttpServlet
                  {
                     public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException 
                     {
                        String uploadIdPattern= "UPLOAD_ID";
                        String pattern= "MESSAGE";
                        String responseMSG= "" +
                           "<html><body>" +
                              "<script type=\"text/javascript\">" +
                                 if(typeof(parent.uploadCompleteFunctions['"+uploadIdPattern+"'])=='function')" +
                                    "{parent.uploadCompleteFunctions['"+uploadIdPattern+"']('"+pattern+"');}" +
                              "</script>" +
                           "</body></html>";
                  
                        ServletFileUpload upload= new ServletFileUpload();
                        FileItemIterator iter= upload.getItemIterator(request);
                        FileItemStream item= iter.next();
                  
                        String name= item.getFieldName();
                        if(item.isFormField() && name.equals(UploadDialog.ATTRIBUTE_NAME_TIMESTAMP))
                        {
                           timestamp= Streams.asString(item.openStream());
                  	responseMSG= responseMSG.replace(uploadIdPattern, timestamp);
                        }
                        ...
                        response.setContentType("text/html");
                        response.setHeader("Pragma", "No-cache");
                        response.setDateHeader("Expires", 0);
                        response.setHeader("Cache-Control", "no-cache");
                        PrintWriter out= response.getWriter();
                        if(responseMSG.contains(pattern))	//no exception
                           responseMSG= responseMSG.replace(pattern, "Upload Complete.");
                        out.println(responseMSG);
                        out.flush();
                     }
                  }
                  Last edited by weihnachtsmann; 25 Oct 2012, 01:08.

                  Comment

                  Working...
                  X