Chapter 5: Progress Bar

Contents

5.1 Introducing the HTML-based Progress Bar

Starting with Version 3.0, AspUpload offers a unique feature: an HTML-based progress indicator which pops up upon the commencement of an upload and displays the current upload status including the percentage completed and time remaining information. Once an upload is finished or aborted by the user, the progress window automatically closes. This feature is particularly useful when uploading large (over 1 MB) files.

The progress bar is implemented using nothing but HTML and client-side JavaScript. No ActiveX controls or Java applets are used. A typical progress window looks like this:

The layout of the progress window is fully customizable. You can move around the progress bar and numeric indicators, change captions, add custom logos, etc.

5.2 Implementation Steps

You must carefully follow these steps to add progress bar functionality to your application.

Step 1. If your upload form is located in an .HTML file, you should make it into an .ASP file as some ASP script needs to be added to that file.

Step 2. At the top of your form file (above the actual form), place the following code:

<%
Set UploadProgress = Server.CreateObject("Persits.UploadProgress")
PID = "PID=" & UploadProgress.CreateProgressID()
barref = "framebar.asp?to=10&" & PID
%>

This code is responsible for creating a unique progress ID which connects the page containing the upload form with the progress indicator and upload script.

Step 3. Add the following JavaScript function to your form file below the ASP fragment of Step 2. You may place it between the <HEAD>...</HEAD> tags.

<SCRIPT LANGUAGE="JavaScript">
function ShowProgress()
{
  strAppVersion = navigator.appVersion;
  if (document.MyForm.FILE1.value != "" || document.MyForm.FILE2.value != "" || document.MyForm.FILE3.value != "")
  {
    if (strAppVersion.indexOf('MSIE') != -1 && strAppVersion.substr(strAppVersion.indexOf('MSIE')+5,1) > 4)
    {
      winstyle = "dialogWidth=385px; dialogHeight:140px; center:yes";
      window.showModelessDialog('<% = barref %>&b=IE',null,winstyle);
    }
    else
    {
      window.open('<% = barref %>&b=NN','','width=370,height=115', true);
    }
  }
  return true;
}
</SCRIPT>

The function ShowProgress() is responsible for opening the progress bar window upon submission of your upload form. You may need to change the line

if (document.MyForm.FILE1.value != "" || document.MyForm.FILE2.value != "" || document.MyForm.FILE3.value != "")

according to your own form name and the names of your file item(s). In our example, the form name is MyForm, and the file items are FILE1, FILE2 and FILE3.

Step 4. Add an extra parameter to the ACTION attribute of your upload form, as follows:

<FORM NAME="MyForm" METHOD="POST" ENCTYPE="multipart/form-data"
  ACTION="progress_upload.asp?<% = PID %>">

Step 5. Add an OnSubmit attribute to your upload form which calls the ShowProgress() routine added in Step 3, as follows:

<FORM NAME="MyForm" METHOD="POST" ENCTYPE="multipart/form-data"
  ACTION="progress_upload.asp?<% = PID %>"
  OnSubmit="return ShowProgress();">

Step 5. Make sure the files FRAMEBAR.ASP, BAR.ASP, and NOTE.HTM are located in the same directory as your form file. FRAMEBAR.ASP contains the main frameset for the progress indicator. Under IE, it invokes the file BAR.ASP within an <IFRAME>. Under Netscape, it invokes the files BAR.ASP and NOTE.HTM within a regular <FRAMESET>. You only need to modify the files BAR.ASP and NOTE.HTM to customize your progress indicator. We do not recommend making any changes to the file FRAMEBAR.ASP, unless you need to change the size of your progress bar.

Step 6. Add the following line to your upload script right after the CreateObject line:

<%
Set Upload = Server.CreateObject("Persits.Upload")
Upload.ProgressID = Request.QueryString("PID")

...
%>

This tells the UploadManager object the progress ID of the current upload, thereby connecting it to the progress window.

The sample files progress.asp and progress_upload.asp demonstrate a simple progress bar-enabled upload system.

Click the link below to run this code sample:

5.3 Customizing the Progress Bar

To change the phrase To cancel uploading, press your browser's STOP button, make the appropriate modifications in the files FRAMEBAR.ASP (for IE) and NOTE.HTM (for Netscape).

All other modifications involve the method UploadProgress.FormatProgress called in the file BAR.ASP.

The method FormatProgress expects the following parameters:

ProgressID
Iteration (in/out)
BarColor
Format

ProgressID is a unique ID passed to the file BAR.ASP via the PID variable.

BarColor is the color of the progress bar. By default, this value is "#0000F7".

Iteration will be covered later.

Format is a string containing special characters (described below) which controls the HTML layout of the progress window. By default, this value is

"%TUploading files...%t%B3%T%R left (at %S/sec) %r%U/%V(%P)%l%t"

The format string may contain the following special characters:

%T - the beginning of an HTML table (<table><tr><td>)
%t - the end of an HTML table (</td></tr></table>)
%d - a new column (</td><td>)
%r - a new column aligned to the right (</td><td align=right>)
%c - a new column aligned to the center (</td><td align=center>)
%l - a new row (</td></tr><tr><td>)
%n - a line break (<br>)

%Bn - the progress bar; n indicates the number of percentage points per progress square. Our sample uses %B3. For a solid progress bar, use %B0.

The following special characters are placeholders for various numeric values:

%E - elapsed time
%R - remaining time
%S - current transfer speed
%U - transferred amount
%V - total upload size
%P - percentage completed
%Y - remaining amount

The code samples progress1.asp, BAR1.ASP and FRAMEBAR1.ASP demonstrate a customized progress bar which displays a logo. The following changes were made to the original files:

  • In the file progress1.asp, the barref variable points to FRAMEBAR1.ASP instead of FRAMEBAR.ASP. Also, the dialog height is increased by 50 points:
    barref = "framebar1.asp?to=10&" & PID

    winstyle = "dialogWidth=385px; dialogHeight:190px; center:yes";
    ...
    window.open('<% = barref %>&b=NN','','width=370,height=165', true)

  • In the file FRAMEBAR1.ASP, all references to BAR.ASP are replaced by BAR1.ASP, and the sizes are changed as well:
    <IFRAME src="bar1.asp?PID=... frameborder=0 framespacing=10 width=369 height=115></IFRAME>
    ...
    <FRAMESET ROWS="80%, 20%" COLS="100%" border="0" framespacing="0" frameborder="NO">
  • In the file BAR1.ASP, the format string is changed as follows:
    "<CENTER><IMG SRC=logo.gif></CENTER>%TUpload Progress%t%B3%T%R left (at %S/sec) %r%U/%V(%P)%l%t"
  • And finally, an image file logo.gif is placed in the appropriate virtual folder.

Click the link below to run this code sample:

5.4 Fine-tuning the Progress Bar

If something goes wrong with an upload, and the progress bar window stops receiving signals from the server, it will remain open for 10 refreshes (roughly 10 seconds as the progress window is refreshed every second).

This parameter can be changed, if necessary. The value 10 is passed to the progress bar via the to (time open) variable, as follows:

barref = "framebar1.asp?to=10&" & PID

This line of code is located in the top portion of your upload form file (in our case, progress.asp and progress1.asp).

5.5 Ajax-based Progress Bar (Version 3.1)

As of AspUpload 3.1, the progress bar can be displayed on the same page as the upload form, as opposed to a pop-up window. This is made possible via the Ajax technology, and a new method of the ProgressManager object, XmlProgress. The Ajax-based progress bar is demonstrated by this Live Demo.

For an Ajax-base implementation, the upload form and upload script can be combined into a single file which may look as follows:

progress_ajax.asp:
<HTML>
<HEAD>

<%
Set UploadProgress = Server.CreateObject("Persits.UploadProgress")
PID = UploadProgress.CreateProgressID()

Set Upload = Server.CreateObject("Persits.Upload")

' This is needed to enable the progress indicator
Upload.ProgressID = Request.QueryString("PID")
Upload.IgnoreNoPost = True ' to use upload script in the same file as the form.

Upload.Save "c:\upload"

If Upload.Files.Count > 0 Then
   Res = "Success! " & Upload.Files.Count & " files have been uploaded."
Else
   Res = ""
End If
%>

<script src="progress_ajax.js"></script>

</HEAD>
<BODY>

   <FORM METHOD="POST" ENCTYPE="multipart/form-data"
      ACTION="progress_ajax.asp?pid=<% = PID %>"
      OnSubmit="ShowProgress('<% = PID %>')">

   <INPUT TYPE="FILE" NAME="FILE1"><BR>
   <INPUT TYPE="FILE" NAME="FILE2"><BR>
   <INPUT TYPE="FILE" NAME="FILE3"><BR>

   <INPUT TYPE="SUBMIT" VALUE="Upload!">
   <INPUT TYPE="BUTTON" VALUE="Stop" OnClick="OnStop()">
   </FORM>

   <div id="txtProgress"></div>

   <% = Res %>

</BODY>
</HTML>

Much of the script above is similar to what we used for the pop-up progress bar described in the previous sections of this chapter. There are two new items to note:

  • The inclusion of the JavaScript file progress_ajax.js which contains the Ajax code:

    <script src="progress_ajax.js"></script>
  • A <div> placeholder that the Ajax code will use to display the progress bar:

    <div id="txtProgress"></div>

The file progress_ajax.js contains the definitions of the ShowProgress and OnStop functions and also auxiliary code common to all Ajax implementations:

progress_ajax.js:

var xmlHttp;
var TimoutID;
var strSessionID;

var IsChrome; // chrome requires special treatment

function GetXmlObject()
{
   try
   {
      // Firefox, Opera 8.0+, Safari
      xmlHttp = new XMLHttpRequest();
   }
   catch (e)
   {
      // Internet Explorer
      try
      {
         xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
      }
      catch (e)
      {
         xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
      }
   }
   return xmlHttp;
}

function stateChanged()
{
   if (xmlHttp.readyState == 4)
   {
      // Skipped for brevity
      ...

      document.getElementById('txtProgress').innerHTML = strFormat;

       // schedule next update in 1 sec.
      clearTimeout(TimoutID);
      TimoutID = setTimeout( 'Update()', 1000);
   }
}

function OnStop()
{
   if( navigator.appName == "Microsoft Internet Explorer" )
   {
      document.execCommand('Stop');
   }
   else
   {
      window.stop();
   }

   document.getElementById('txtProgress').innerHTML = "Stopped";
   clearTimeout(TimoutID);
}

function ShowProgress( strPID )
{
   xmlHttp = GetXmlObject();
   if( xmlHttp == null )
   {
      alert( 'Your browser does not support AJAX!');
      return;
   }

   xmlHttp.onreadystatechange = stateChanged;

   // Chrome and Safari require false instead of true in xmlHttp.Open
   IsChrome = navigator.userAgent.indexOf('Chrome') >= 0
      || navigator.userAgent.indexOf('Safari') >= 0;

   strSessionID = strPID
   Update();
}

function Update()
{
   xmlHttp.open('GET','progress_ajax_update.asp?pid=' + strSessionID, !IsChrome);
   xmlHttp.onreadystatechange = stateChanged;
   xmlHttp.send(null);
}

The Ajax code shown above essentially invokes the script progress_ajax_update.asp, which supplies the updated progress information, every 1000 milliseconds, and displays it on the upload form page.

The script progress_ajax_update.asp is very simple: it calls the ProgressManager method XmlProgress introduced in Version 3.1 which returns the progress information broken down into individual pieces and packaged as an XML document.

progress_ajax_update.asp:

<%@EnableSessionState=False%>
<%
response.expires = -1
response.contenttype = "text/xml"

PID = Request.QueryString("pid")

Set UploadProgress = Server.CreateObject("Persits.UploadProgress")
Response.Write UploadProgress.XmlProgress(PID)
%>

The XML document returned by XmlProgress has the following structure (shown with sample data):

<?xml version="1.0"?>
<Progress>
  <ElapsedTime>02:44</ElapsedTime>
  <RemainingTime>01:53</RemainingTime>
  <PercentComplete>28</PercentComplete>
  <TotalBytes>6.13M</TotalBytes>
  <UploadedBytes>1.71M</UploadedBytes>
  <RemainingBytes>4.42M</RemainingBytes>
  <TransferSpeed>39.8K/Sec</TransferSpeed>
</Progress>

The function stateChanged() of the file progress_ajax.js uses the following code to parse out the individual components of the progress information from this XML document:

function stateChanged()
{
  if (xmlHttp.readyState == 4)
  {
    var Xml = xmlHttp.responseXML;

    var PercentComplete =
      Xml.getElementsByTagName('PercentComplete')[0].firstChild.nodeValue;

    var RemainingTime =
      Xml.getElementsByTagName('RemainingTime')[0].firstChild.nodeValue;

    var TransferSpeed =
      Xml.getElementsByTagName('TransferSpeed')[0].firstChild.nodeValue;

    var TotalBytes =
      Xml.getElementsByTagName('TotalBytes')[0].firstChild.nodeValue;

    var UploadedBytes =
      Xml.getElementsByTagName('UploadedBytes')[0].firstChild.nodeValue;

    }

    ...

}

Click the link below to run this code sample: