18.1.4.1. События, возникающие в ходе выгрузки

Кроме событий, которые удобно использовать для мониторинга загрузки НТТР-ответа, спецификация «ХНН2» также определяет события для мониторинга выгрузки HTTP-запроса. В броузерах, реализующих эту возможность, объект XMLHttpRequest имеет свойство upload. Значением свойства upload является объект, определяющий метод addEventListener() и полный набор свойств-событий хода выполнения операции выгрузки, таких как onprogress и onload. (Однако этот объект не определяет свойство onreadystatechange: в процессе выгрузки генерируются только эти новые события.)

Обработчики событий хода выполнения операции выгрузки можно использовать точно так же, как используются обычные обработчики событий хода выполнения загрузки. Для объекта х типа XMLHttpRequest обработчик х.onprogress позволяет вести мониторинг хода выполнения загрузки ответа. А свойство х.upload.onprogress - мониторинг хода выполнения выгрузки запроса.

Пример 18.11 демонстрирует, как использовать событие «progress», генерируемое в ходе выгрузки запроса, для организации обратной связи с пользователем. Этот пример также демонстрирует, как получать объекты File с применением механизма буксировки (drag-and-drop) и как с помощью объекта FormData выгружать сразу несколько файлов в одном запросе XMLHttpRequest. На момент написания этих строк спецификации, определяющие эти особенности, находились в состоянии проектирования и этот пример работал не во всех броузерах.

Пример 18.11. Мониторинг хода выполнения операции выгрузки

// Отыскивает все элементы с классом "fileDropTarget" и регистрирует

// обработчики событий механизма DnD, чтобы они могли откликаться

// на операции буксировки файлов. При сбросе файлов на эти элементы

// они выгружают их на URL-адрес, указанный в атрибуте data-uploadto.

whenReady(function() {

  var elts = document.getElementsByClassName("fileDropTarget");

  for(var і = 0; і < elts.length; i++) {

    var target = elts[i];

    var url = target.getAttribute("data-uploadto");

    if (!url) continue;

    createFileUploadDropTarget(target, url);

  }

  function createFileUploadDropTarget(target, url) {

    // Следит за ходом выполнения операции выгрузки и позволяет отвергнуть

    // выгрузку файла. Можно было бы обрабатывать сразу несколько параллельных

    // операций выгрузки, но это значительно усложнило бы

    // отображение хода их выполнения,

    var uploading = false;

    console.log(target.url);

    target.ondragenter = function(e) {

      console. log("dragenter");

      if (uploading) return; // Игнорировать попытку сброса, если

      // элемент уже занят выгрузкой файла

      var types = e.dataTransfer.types;

      if (types &&

          ((types.contains && types.contains("Files")) ||

          (types.indexOf && types.index0f("Files”) !== -1))) {

        target.classList.add("wantdrop");

        return false;

      }

    };

    target.ondragover = function(e) {

      if (!uploading) return false;

    };

    target.ondragleave = function(e) {

      if (!uploading) target.classList.remove("wantdrop");

    };

    target.ondrop = function(e) {

      if (uploading) return false;

      var files = e.dataTransfer.files;

      if (files && files.length) {

        uploading = true;

        var message = "Выгружаются файлы:<ul>";

        for(var і = 0; і < files.length; i++)

          message += "<li>" + files[i].name + "</li>";

        message += "</ul>";

        target.innerHTML = message;

        target.classList.remove("wantdrop");

        target.classList.add("uploading");

        var xhr = new XMLHttpRequest();

        xhr.open("POST", url);

        var body = new FormData();

        for(var i=0; і < files.length; i++)

          body.append(i, files[і]);

        xhr.upload.onprogress = function(e) {

        if (e.lengthComputable) {

            target.innerHTML = message +

            Math.round(e.loaded/e.total*100) +

                             "% Завершено";

          }

        };

        xhr.upload.onload = function(e) {

          uploading = false;

          target.classList.remove("uploading");

          target.innerHTML = "Отбуксируйте сюда файл для выгрузки";

        };

        xhr.send(body);

        return false;

      }

      target.classList. removefwantdrop");

    }

  }

});