Antonio Gallardo wrote:
> Upayavira wrote:
> 
>> Antonio Gallardo wrote:
>>  
>>
>>> Hi:
>>>
>>> I was playing around AJAX and the upload widget. Why the upload widget
>>> is not supported by AJAX?
>>>   
>>
>>
>> I started working on an AJAX progress bar for the upload widget during
>> the GetTogether.
>>
> Great!
> 
>> I can explain where I got to if you want to look into
>> finishing it.
>>  
>>
> Yes, please! :-D

I've attached two patches, one for o.a.c.servlet.multipart, and one for
the forms block. This code is by no means finished, but may give you
ideas. It is based upon this demo:

http://sean.treadway.info/demo/upload

I stopped at the point at which I realised that I needed to switch from
using the Prototype periodic updater to using Cocoon's own implementation.

The basic idea behind this is that when the user clicks submit, an AJAX
periodic updater is started that reloads a bit of the screen every 2
seconds. This is the progress bar. Then it submits the form into a
hidden iframe to start the upload. The upload is handled by the
MultiPart code within Cocoon, which stores vital info (e.g. total file
size, size so far) in the session, so that when the periodic updater
requests a page, the progress bar can be built based upon how much has
been uploaded so far.

Now, if you don't get a chance to look at this, either myself or a
colleague might within the next week or so.

Regards, Upayavira
Index: java/org/apache/cocoon/forms/resources/forms-field-styling.xsl
===================================================================
--- java/org/apache/cocoon/forms/resources/forms-field-styling.xsl	(revision 307124)
+++ java/org/apache/cocoon/forms/resources/forms-field-styling.xsl	(working copy)
@@ -459,25 +459,38 @@
       | fi:upload
       +-->
   <xsl:template match="fi:upload">
-    <span id="[EMAIL PROTECTED]" title="{fi:hint}">
-      <xsl:choose>
-        <xsl:when test="fi:value">
-          <!-- Has a value (filename): display it with a change button -->
-            <xsl:text>[</xsl:text>
-            <xsl:value-of select="fi:value"/>
-            <xsl:text>] </xsl:text>
-            <input type="button" id="[EMAIL PROTECTED]" name="[EMAIL PROTECTED]" value="..." onclick="forms_submitForm(this)"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <input type="file" id="[EMAIL PROTECTED]" name="[EMAIL PROTECTED]" title="{fi:hint}" accept="[EMAIL PROTECTED]">
-            <xsl:apply-templates select="." mode="styling"/>
-          </input>
-        </xsl:otherwise>
-      </xsl:choose>
-      <xsl:apply-templates select="." mode="common"/>
-    </span>
+      <div id="[EMAIL PROTECTED]" title="{fi:hint}" style="border: 2px solid black">
+        <xsl:choose>
+          <xsl:when test="fi:value">
+            <!-- Has a value (filename): display it with a change button -->
+              <xsl:text>[</xsl:text>
+              <xsl:value-of select="fi:value"/>
+              <xsl:text>] </xsl:text>
+              <input type="button" id="[EMAIL PROTECTED]" name="[EMAIL PROTECTED]" value="..." onclick="forms_submitForm(this)"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <input type="file" id="[EMAIL PROTECTED]" name="[EMAIL PROTECTED]" title="{fi:hint}" accept="[EMAIL PROTECTED]">
+              <xsl:apply-templates select="." mode="styling"/>
+            </input>
+          </xsl:otherwise>
+        </xsl:choose>
+        <input name="[EMAIL PROTECTED]" id="[EMAIL PROTECTED]" type="button" value="upload" onclick="return Cocoon.CForms.submitUpload($('[EMAIL PROTECTED]'), '[EMAIL PROTECTED]')"/>
+        <xsl:apply-templates select="." mode="common"/>
+        <div id="[EMAIL PROTECTED]" style="display: none; border: 1px solid black">
+          <!-- NB: keep the following all on one line - makes the js easier: -->
+          <div class="forms-upload-progress-bar" id="[EMAIL PROTECTED]" style="border: 2px solid blue"><div class="forms-upload-border"><div id="[EMAIL PROTECTED]" class="forms-upload-background" style="width: {fi:[EMAIL PROTECTED]'progress-bar]/@width}%"><div class="forms-upload-foreground">a</div></div></div></div>
+          <div class="forms-upload-status" id="[EMAIL PROTECTED]" xmlns:bu="http://apache.org/cocoon/browser-update/1.0";>
+            <xsl:if test="/bu:document">
+              <xsl:apply-templates select="fi:[EMAIL PROTECTED]'progress-bar']/*|fi:[EMAIL PROTECTED]'progress-bar']/text()"/>
+            </xsl:if>
+          </div>
+        </div>
+      </div>
+      <iframe id="[EMAIL PROTECTED]" name="[EMAIL PROTECTED]" src="" style="width:300px;height:100px;border:2px solid black"></iframe>          
   </xsl:template>
 
+  <xsl:template match="fi:[EMAIL PROTECTED]'progress-bar']"/>
+
   <!--+
       | fi:upload, output state
       +-->
Index: java/org/apache/cocoon/forms/resources/css/forms.css
===================================================================
--- java/org/apache/cocoon/forms/resources/css/forms.css	(revision 307124)
+++ java/org/apache/cocoon/forms/resources/css/forms.css	(working copy)
@@ -73,3 +73,25 @@
 .forms-doubleList input {
     width: 40px;
 }
+
+.forms-upload-status {
+  margin: 5px;
+}
+
+.forms-upload-progress-bar {
+  margin: 5px;
+}
+
+.forms-upload-progress-bar .forms-upload-border {
+  background: url(../img/progress-remainder.gif) repeat-x;
+  border-left: 1px solid grey;
+  border-right: 1px solid grey;
+  width: 100%;
+}
+
+.forms-upload-progress-bar .forms-upload-background {
+  background: url(../img/progress-bar.gif) repeat-x;
+  background-color: #049;
+  height: 18px;
+  width: 25%;
+}
Index: java/org/apache/cocoon/forms/resources/js/cforms.js
===================================================================
--- java/org/apache/cocoon/forms/resources/js/cforms.js	(revision 307124)
+++ java/org/apache/cocoon/forms/resources/js/cforms.js	(working copy)
@@ -105,3 +105,41 @@
     }
     return result;
 }
+
+Cocoon.CForms.submitUpload = function(element, id) {
+    var form = forms_getForm(element);
+    if (form == null) {
+        alert("Cannot find form for " + element);
+        return;
+    }
+    var periodicUrl = form.action + "?cocoon-ajax=true";
+    if (form.action.indexOf('upload_id')<0) {
+        form.action += '?upload_id=1';
+    }
+    form.target = id + "-target";
+    var bar = $(id+"-upload-bar-bg");
+    $(id + "-status").innerHTML='Upload starting...'; 
+    bar.style.width='0%'; 
+    new Effect.Appear(id + '-status'); 
+    if (document.uploadStatus1) {
+        document.uploadStatus1.stop();
+    }
+    document.uploadStatus1
+         = new Ajax.PeriodicalUpdater(id + "-upload-status", periodicUrl,
+                                      { onComplete: Cocoon.CForms.uploadComplete,
+                                        evalScripts:true, 
+                                        asynchronous:true,
+                                        decay:1.8,
+                                        frequency:2.0
+                                      }
+                                     );
+    forms_submitForm(element);
+}
+Cocoon.CForms.uploadComplete = function(request) {
+  $(id + "-upload-status").innerHTML='Upload finished.';
+  var bar = $(id + "-upload-bar-bgr")
+  bar.style.width='100%';
+  document.uploadStatus1 = null; 
+  setTimeout(function() {new Effect.Fade('status');}, 2000)
+}
+                                        
\ No newline at end of file
Index: samples/forms/upload_template.xml
===================================================================
--- samples/forms/upload_template.xml	(revision 307124)
+++ samples/forms/upload_template.xml	(working copy)
@@ -15,19 +15,30 @@
   limitations under the License.
 -->
 <page xmlns:ft="http://apache.org/cocoon/forms/1.0#template";
-      xmlns:fi="http://apache.org/cocoon/forms/1.0#instance";>
+      xmlns:fi="http://apache.org/cocoon/forms/1.0#instance";
+      xmlns:jx="http://apache.org/cocoon/templates/jx/1.0";>
+  <jx:import uri="resource://org/apache/cocoon/forms/generation/jx-macros.xml"/>
   <h4 class="samplesGroup">Upload widget</h4>
   <title>Upload Sample</title>
   <content>
     <para>
     For this example to work, you must enable uploads in your web.xml file.
     </para>
-    <ft:form-template action="#{$cocoon/continuation/id}.continue" method="POST" enctype="multipart/form-data">
+    <ft:form-template action="#{$cocoon/continuation/id}.continue" method="POST" enctype="multipart/form-data" ajax="true">
       <fi:group>
         <fi:styling layout="columns"/>
         <fi:items>
           <ft:widget id="user"/>
-          <ft:widget id="upload"/>
+          <ft:widget id="upload">
+            <fi:styling type="progress-bar" width="20${cocoon.session.getAttribute('ajax.upload.width')}">
+              <div>10${cocoon.session.getAttribute("ajax.upload1.kb")} Kb of 
+                   200${cocoon.session.getAttribute("ajax.upload1.kbTotal")} Kb at
+                   14.2${cocoon.session.getAttribute("ajax.upload1.kbps")} Kb/s;
+                   12${cocoon.session.getAttribute("ajax.upload1.remaining")} remaining
+                   
+              </div>
+            </fi:styling>
+          </ft:widget>
           <input type="submit"/>
         </fi:items>
       </fi:group>
Index: samples/flow/upload_example.js
===================================================================
--- samples/flow/upload_example.js	(revision 307124)
+++ samples/flow/upload_example.js	(working copy)
@@ -18,7 +18,7 @@
 function upload() {
     
     var form = new Form("forms/upload_model.xml");
-    var k = form.showForm("upload-display-pipeline");
+    var k = form.showForm("upload-display-pipeline.jx");
 
     k.invalidate();
Index: MultipartException.java
===================================================================
--- MultipartException.java	(revision 307124)
+++ MultipartException.java	(working copy)
@@ -20,7 +20,7 @@
  * a malformed stream.
  *
  * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a>
- * @version CVS $Id: MultipartException.java,v 1.2 2004/03/05 13:02:58 bdelacretaz Exp $
+ * @version CVS $Id$
  */
 public class MultipartException extends Exception {
 
Index: TokenStream.java
===================================================================
--- TokenStream.java	(revision 307124)
+++ TokenStream.java	(working copy)
@@ -24,7 +24,7 @@
  *
  * A newline is espected after each boundary and is parsed away.
  * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a>
- * @version CVS $Id: TokenStream.java,v 1.4 2004/03/05 13:02:58 bdelacretaz Exp $
+ * @version CVS $Id$
  */
 class TokenStream extends PushbackInputStream {
 
Index: MultipartParser.java
===================================================================
--- MultipartParser.java	(revision 307124)
+++ MultipartParser.java	(working copy)
@@ -30,6 +30,7 @@
 import java.util.Vector;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 import org.apache.cocoon.util.NullOutputStream;
 
@@ -50,6 +51,8 @@
 
     private static final int MAX_BOUNDARY_SIZE = 128;
 
+    private static final String LENGTH_SESSION_ATTR = "org.apache.cocoon.servlet.multipartparser.length";
+
     private boolean saveUploadedFilesToDisk;
 
     private File uploadDirectory = null;
@@ -67,7 +70,11 @@
     private boolean oversized = false;
     
     private int contentLength;
+
+    private HttpSession session;
     
+    private boolean hasSession;
+
     /**
      * Constructor, parses given request
      *
@@ -131,6 +138,9 @@
             }
             this.parts.put(name, v);
         }
+        this.session = request.getSession(); 
+        this.hasSession = this.session != null;
+
         parseParts(request.getContentLength(), request.getContentType(), request.getInputStream());    
         return this.parts;    
     }
@@ -259,6 +269,9 @@
             while (in.getState() == TokenStream.STATE_READING) {    // read data
                 read = in.read(buf);
                 length += read;
+                if (this.hasSession) {
+                    this.session.setAttribute(LENGTH_SESSION_ATTR, Integer.toString(length));
+                }
                 out.write(buf, 0, read);
             }
         } catch (IOException ioe) {

Reply via email to