Search code examples
javascriptjqueryhtmlprogress-barcherrypy

HTML progress bar using cherrypy and JavaScript


Hi there I am trying to develop a simple web-based file upload form with a progress bar. I'm using cherrypy 3.2 as the server and the file is being successfully uploaded. My problem is the fact that the progress bar appears but isn't updated in the web browser during the upload process. I know that the function prompt() is being called because an alert box is displayed when i click the upload button without selecting a file first.

I've included my code below. Please let me know if i'm missing something. Any help would be appreciated. Thanks

The sever side:

class filedrop(object):
    def index(self):
        return open('index.html')
    index.exposed = True

    def upload_handler(self, myFile, mySize):
        fileName = os.path.split(myFile.filename)[1]
        chunksize = round(int(mySize)/10)
        fo = open('C:/Sprint 16/' + fileName, 'wb')
        while True:
            data = myFile.file.read(int(chunksize))
            if not data:
                sys.stderr.write("\n")
                break
            fo.write(data)
        fo.close()
        raise cherrypy.HTTPRedirect("/")
    upload_handler.exposed = True
cherrypy.quickstart(filedrop())

The 'index.html' file

<head><script type="text/javascript" src="/jquery-1.4.2.min.js"></script></head>
<body>
    <b>Upload Files To This Directory</b><br><br>
    <form id="form" action="upload_handler" method="POST" enctype="multipart/form-data" name="Uform" onsubmit="return prompt()">
        <input type="file" name="myFile" id="upFile" /><br />
        <input type="submit" value=" Upload"/>
        <input type="hidden" name="mySize" id="fileSize"/>
    </form> <progress id="progBar" max="100" value="0"></progress>
    <script>
        function prompt(){
            var x=document.forms["Uform"]["myFile"].value;
            if(x==null || x==""){
                alert("No file chosen. Please go back and try again");
                return false;
            }
            var input = document.getElementById("upFile");
            var size = input.files[0].size;
            var sizeField = document.getElementById("fileSize");
            sizeField.value = size;

            var xhr = new XMLHttpRequest();
            xhr.upload.addEventListener("progress", updateProgress, false);
            xhr.open("POST", "upload_handler");
        }
        function updateProgress(evt){
            if(evt.lengthComputable){
                var percentComplete = (evt.loaded / evt.total)*100;
                var progressBar = document.getElementById("progBar");
                proressbar.value = percentComplete;                             
            }
        }
    </script>
</body>

Solution

  • Here's what I got working...

    <head><script type="text/javascript" src="/jquery-1.4.2.min.js"></script></head>
    <body>
        <b>Upload Files To This Directory</b><br><br>
        <!--<form id="form" action="/filedrop/upload_handler" method="POST" enctype="multipart/form-data" name="Uform" onsubmit="return prompt()">-->
            <input type="file" name="myFile" id="upFile" /><br />
            <input type="submit" value=" Upload" onclick="prompt();"/>
        <!--    <input type="hidden" name="mySize" id="fileSize"/>
        </form>--> <progress id="progBar" max="100" value="0"></progress>
        <script>
            function prompt(){
                var x=document.getElementById("upFile").value;
                if(x==null || x==""){
                    alert("No file chosen. Please go back and try again");
                    return false;
                }
                var input = document.getElementById("upFile");
                //var size = input.files[0].size;
                //var sizeField = document.getElementById("fileSize");
                //sizeField.value = size;
    
                var data = new FormData();
                data.append('myFile', document.getElementById("upFile").files[0]);
    
                var xhr = new XMLHttpRequest();
                xhr.upload.addEventListener("progress", updateProgress, false);
                xhr.open("POST", "upload_handler");
                xhr.send(data);
            }
            function updateProgress(evt){
                if(evt.lengthComputable){
                    var percentComplete = (evt.loaded / evt.total)*100;
                    var progressBar = document.getElementById("progBar");
                    progressBar.value = percentComplete;                             
                }
            }
            </script>
    </body>
    

    *.py file reads:

    import cherrypy
    import os
    
    class filedrop(object):
        def index(self):
            return open('index.html')
        index.exposed = True
    
        def upload_handler(self, myFile):
            fo = open(os.path.dirname(__file__) + "/" + myFile.filename, 'wb')
            all_data = bytearray()
            while True:
                data = myFile.file.read(8192)
                all_data += data
                if not data:
                    break
            fo.write(all_data)
            fo.close()
            #raise cherrypy.HTTPRedirect("/")
         upload_handler.exposed = True
    cherrypy.quickstart(filedrop())
    

    I believe the problems were that proressbar was misspelled in the bottom of your script tag, the form was posting and taking you off the page that was giving the progress update and you weren't really sending the file to the server side. Let me know if you have any more problems. Hope this helps!