Newer
Older
Sunfish / src / Sunfish.Core / Web / Resources / sunfish.js
@Ivan Dominguez Ivan Dominguez 21 hours ago 3 KB 3.0
// Sunfish: mejora de la subida en el modo moderno (solo se incluye en navegadores actuales).
// Sin este script el formulario funciona igual; con el, se puede arrastrar ficheros a la pagina,
// se ve el progreso y los ficheros grandes se envian por trozos con PUT + Content-Range.
(function () {
  'use strict';
  var form = document.getElementById('sf-upload');
  if (!form || !window.XMLHttpRequest || !window.File || !File.prototype.slice) return;
  var input = form.querySelector('input[type=file]');
  var status = document.getElementById('sf-status');
  var uploadingText = form.getAttribute('data-uploading') || 'Uploading';
  var doneText = form.getAttribute('data-done') || 'Done';
  var CHUNK = 1024 * 1024;
  var busy = false;

  function newId() {
    var s = '';
    for (var i = 0; i < 24; i++) s += Math.floor(Math.random() * 16).toString(16);
    return s;
  }

  function show(text) { if (status) status.textContent = text; }

  function sendFile(file, progress, done) {
    var id = newId();
    var url = location.pathname + encodeURIComponent(file.name);

    function part(offset) {
      var end = Math.min(offset + CHUNK, file.size);
      var xhr = new XMLHttpRequest();
      xhr.open('PUT', url);
      xhr.setRequestHeader('X-Sunfish-Upload', id);
      if (file.size > 0)
        xhr.setRequestHeader('Content-Range', 'bytes ' + offset + '-' + (end - 1) + '/' + file.size);
      xhr.upload.onprogress = function (e) { progress(offset + e.loaded); };
      xhr.onload = function () {
        if (xhr.status >= 200 && xhr.status < 300) {
          if (end >= file.size) done(null); else part(end);
        } else {
          done(file.name + ': ' + (xhr.responseText || xhr.status));
        }
      };
      xhr.onerror = function () { done(file.name + ': network error'); };
      xhr.send(file.slice(offset, end));
    }

    part(0);
  }

  function upload(fileList) {
    if (busy || !fileList || !fileList.length) return;
    busy = true;
    var files = [], total = 0, sent = 0;
    for (var i = 0; i < fileList.length; i++) { files.push(fileList[i]); total += fileList[i].size; }

    function next(k) {
      if (k >= files.length) {
        show(doneText);
        location.reload();
        return;
      }
      var file = files[k];
      sendFile(file, function (bytes) {
        var pct = total > 0 ? Math.floor((sent + bytes) * 100 / total) : 100;
        show(uploadingText + ' ' + file.name + '... ' + pct + '%');
      }, function (error) {
        if (error) { show(error); busy = false; return; }
        sent += file.size;
        next(k + 1);
      });
    }
    next(0);
  }

  form.addEventListener('submit', function (e) {
    if (!input || !input.files || !input.files.length) return;
    e.preventDefault();
    upload(input.files);
  });

  var body = document.body;
  body.addEventListener('dragover', function (e) {
    e.preventDefault();
    body.className = 'sf-drop';
  });
  body.addEventListener('dragleave', function (e) {
    if (e.target === body || !e.relatedTarget) body.className = '';
  });
  body.addEventListener('drop', function (e) {
    e.preventDefault();
    body.className = '';
    if (e.dataTransfer) upload(e.dataTransfer.files);
  });
})();