Chunk Uploads w/ XHR

by Abhishek Nandgaonkar

HTML

<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/4.3.1/css/normalize.css">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/4.3.1/css/foundation.css">
<div class="row">
  <div class="large-12 column">
    <p>Chunk Size: 1mb (1048576 bytes)</p>
    <input type="number" min="1048576" value="1048576" id="numChunks" />
    <input type="file" id="afile" />
    <div id="done"></div>
    <div id="bars"></div>
  </div>
</div>

CSS

.progress {
  color: #fff;
}

.meter {
  width: 0%;
  font-size: 12px;
  padding: .3em;
}

JavaScript

(function() {
   'use strict';
   var bars = document.getElementById('bars'),
     uploaders = [],
     upload,
     chooseFile;

   upload = function(blobOrFile) {
     var progress = document.createElement('div'),
       meter = document.createElement('span'),
       xhr;
     progress.classList.add('progress');
     meter.classList.add('meter');
     bars.appendChild(progress);
     progress.appendChild(meter);

     xhr = new XMLHttpRequest();
     xhr.open('POST', '/echo/json/', true);
     xhr.upload.onprogress = function(e) {
       if (e.lengthComputable) {
         meter.value = Math.round((e.loaded / e.total) * 100);
         meter.textContent = parseFloat(meter.value) + '%';
         meter.style.width = meter.textContent;
       }
       if (meter.textContent === '100%') progress.classList.add('success');


     };
     xhr.onloadend = function(e) {
       uploaders.pop();
       if (!uploaders.length) {
         bars.appendChild(document.createTextNode(' All Done! '));
       }
     };
     uploaders.push(xhr);
     xhr.send(blobOrFile);
   };
   chooseFile = document.getElementById('afile');
   chooseFile.addEventListener('change', function(e) {
     var self = e.currentTarget,
       blob = self.files[0],
       BYTES_PER_CHUNK, SIZE, NUM_CHUNKS, start, end;

     BYTES_PER_CHUNK = parseInt(document.getElementById('numChunks').value, 10);
     SIZE = blob.size;
     NUM_CHUNKS = Math.max(Math.ceil(SIZE / BYTES_PER_CHUNK), 1);
     bars.innerHTML = '';
     bars.innerHTML = '<p>Sending <b>' + NUM_CHUNKS + '</b> chunks:</p>';
     start = 0;
     end = BYTES_PER_CHUNK;
     while (start < SIZE) {
       upload(blob.slice(start, end));
       start = end;
       end = start + BYTES_PER_CHUNK;
     }
   }, false);
 })();