FileAPI: Загрузка и обработка файлов
Что было           3
Что было           4
Что было           Flash                   5
Что было           HTML/JS                     6
Требования  •   Множественный выбор файлов  •   Получение информации (название, размер, тип)  •   Создание пред-просмотра ...
Требования  •   Не зависеть от вѐрстки  •   Никакой бизнес-логики  •   Расширяемость  •   Самодостаточность               ...
Error #203810%
Error #2038  5%
Поддержка            •   Chrome 10+            •   FireFox 3.6+            •   Opera 11.1+            •   Safari 5.4+     ...
13
ПОЛУЧЕНИЕ СПИСКА    ФАЙЛОВ                   14
HTML5<input id="file" type="file" multiple /><script>        var input = document.getByElementId("file");        input.add...
HTML5<input id="file" type="file" multiple /><script>        var input = document.getByElementId("file");        input.add...
HTML5<input id="file" type="file" multiple /><script>        var input = document.getByElementId("file");        input.add...
Flash        FLASH                18
Flash   FLASH           19
Flash       FLASH Flash --> jsFunc([{              id:   "346515436346",      // уникальный идентификатор              nam...
Взаимодействие    flash.cmd("imageTransform", {            id:       "346515436346", // идентификатор файла            mat...
API <span class="js-fileapi-wrapper" style="position: relative">         <input id="file" type="file" multiple /> </span> ...
API <span class="js-fileapi-wrapper" style="position: relative">         <input id="file" type="file" multiple /> </span> ...
ФИЛЬТРАЦИЯ             24
FileReader  • readAsDataURL(file)  • readAsBinaryString(file)  • readAsArrayBuffer(file)  • readAsText(file[, encoding])
Фильтрация     FileAPI.filterFiles(files, function (file, info){              return file.size < 10 * FileAPI.MB;     }, f...
Информация о файле FileAPI.addInfoReader(/^audio/, function (file, callback){         // собираем нужную информацию       ...
Информация о файле  FileAPI.getInfo(audioFile, function (err, tags){          if( !err ){                    var li = docu...
ПРЕДПРОСМОТР
Предпросмотр           DataURI
Предпросмотр           DataURI         Base64
Предпросмотр           DataURI                                       <img/>         Base64                  ―data:image/pn...
Предпросмотр           DataURI                                       <img/>         Base64                  ―data:image/pn...
Предпросмотр HTML5  • FileReader.readAsDataURL(file) — позволяет    прочесть содержимое файла как DataURL  • URL.createObj...
Предпросмотр HTML5  • FileReader.readAsDataURL(file) — позволяет    прочесть содержимое файла как DataURL  • URL.createObj...
FileAPI.Image  • crop(x, y, width, height) — кадрирование  • resize(width[, height]) — масштабирование  • rotate(deg) — по...
Matrix  {      // параметры фрагмента оригинала         sx: Number,         sy: Number,         sw: Number,         sh: Nu...
FileAPI.Image   FileAPI.Image(imageFle)           .crop(300, 300)           .resize(100, 100)           .get(function (err...
Сжатие         5197х4987
Сжатие
Сжатие    5197х4987   2598х2493
Сжатие x 25197х4987    2598х2493   1299х1246
Сжатие x 55197х4987    2598х2493   1299х1246                                     100х100
Сжатие         Серия
ЗАГРУЗКА ФАЙЛОВ
Требования    • Без обновления страницы    • Процесс загрузки    • Получить ответ от сервера
Загрузка   <form      action="/upload"      method="post"      enctype="multipart/form-data">           <input name="files...
Загрузка   <form      target="__UNIQ__"                 Уникальный идентификатор      action="/upload"      method="post" ...
Загрузка   XMLHttpRequest level 2           FormData
Загрузка  // собираем данные для отправки  var form = new FormData  form.append("foo", "bar");  form.append("attach", file...
Загрузка  // собираем данные для отправки  var form = new FormData  form.append("foo", "bar");  form.append("attach", file...
Загрузка  canvasToBlob(canvas, function (blob){     // собираем данные для отправки     var form = new FormData     form.a...
ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);<cavnas/>                     DataURL
ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);base64 = dataURL.replace(/^data:[^,]+,/, ―‖);<cavnas/>                    ...
ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);base64 = dataURL.replace(/^data:[^,]+,/, ―‖);binaryString = window.atob(ba...
Multipart var uniq = 1234567890; var xhr = new XMLHttpRequest; xhr.open(POST, /upload, true); xhr.setRequestHeader(Content...
Загрузка var xhr = ​FileAPI.upload({    url: /upload,    data: { foo: bar },    headers: { Session-Id: ... },    files: { ...
Загрузка var xhr = ​FileAPI.upload({    url: /upload,    data: { foo: bar },    headers: { Session-Id: ... },    files: { ...
Загрузка imageTransform:    {        huge:    { maxWidth: 800, maxHeight: 600, rotate: 90 },        medium: { width: 320, ...
XHRvar xhr = FileAPI.upload({ … });                                   60
XHRvar xhr = FileAPI.upload({ … }); • status — HTTP status code • statusText — HTTP status text • responseText — ответ сер...
Drag’n’Drop              <div class="dropzone"></div>          Перетащите файлы сюда
Drag’n’Drop      <div class="dropzone dropzone_hover"></div>                                          4
Drag’n’Drop <div id="el" class="dropzone"></div> <script>   var el = document.getElementById("el");   FileAPI.event.dnd(el...
Drag’n’Drop <div id="el" class="dropzone"></div> <script>   var el = document.getElementById("el");   FileAPI.event.dnd(el...
Drag’n’Drop <div id="el" class="dropzone"></div> <script>   var el = document.getElementById("el");   FileAPI.event.dnd(el...
Drag’n’Drop <div id="el" class="dropzone"></div> <script>   var el = document.getElementById("el");   FileAPI.event.dnd(el...
Drag’n’Drop  function uploadFiles(dropFiles){    FileAPI.upload({        url: "/upload",        files: { attaches: dropFil...
https://github.com/mailru/FileAPI      Константин Лебедев     JavaScript архитектор     k.lebedev@corp.mail.ru
константин лебедев
константин лебедев
Upcoming SlideShare
Loading in …5
×

константин лебедев

4,310 views
4,183 views

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,310
On SlideShare
0
From Embeds
0
Number of Embeds
523
Actions
Shares
0
Downloads
13
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • Добрый день, меня зовут Лебедев Константин. Я JavaScript-архитектор проекта «Почта@mail.ru».Сегодня я в очередной раз затрону тему загрузки файлов на сервер и особое внимание уделю их обработке на клиенте. Расскажу об основных решениях и технологиях, которые существуют на данный момент, и о том как их использовать и что это дает. Я покажу как решение реальных задач трансформировалось в наш чудо велосипед, который помог нам и я надеюсь поможет и вам.
  • Он позволял выбрать больше одного файла и получить информацию о них, такую как название, тип и размер, а для изображений создавать пред-просмотр.
  • Так же у него есть возможность предварительной обработки изображений: он мог масштабировать и поворачивать. Всё это происходило на клиенте, а потом отправлялось на сервер.
  • Однако у него был ряд недостатков. Это была flash’ка. Вся верстка, графика, бизнес-логика, и даже локализация были зашиты в нем, в результате чего решение было тяжеловесным, а внести правки мог только flash-разработчик.
  • Но это ещё не всё. Так же у нас был второй загрузчик, для тех браузеров, которые не поддерживают flash.Это был обычный js-загрузчик, который позволял выбрать один файл и загрузить его через iframe. Вот и всё что он умел.Как вы понимаете…Вот так, появилась задача переписать наш загрузчик файлов. Тут я бы хотел пояснить, на выходе, мы хотели получить унифицированное API, которое бы работало в независимо от окружения и его можно было использовать не только в рамках проекта “Почта@Mail.ru”, но и где угодно.
  • Для этого API были сформированы следующие требования:Во первых, необходимо сохранить текущую функциональность. Все что умел старый загрузчик, нужно перенести в новый.
  • Во вторых, надо избавиться от недостатков. Бизнес-логика, верстка и тп, не должно содержаться в загрузчике. Только работа с файлами и как можно лучше, все остальное не его задача. В третьих, расширяемость. Если завтра окажется, что нужно получать id3 теги аудио-файла, это не должно стать сюрпризом.
  • Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  • Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  • Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  • Как видите, уже более 63% браузеров поддерживают FileAPI. IE обзаведется поддержкой только с 10 версии. Но 63, это далеко не 95% и даже 90% пользователей, так что от флешь отказываться рано!
  • Таким образом, задача свелась к созданию механизма, который совмещал бы в себе обе технологии и реализованный так, чтобы конечному разработчику было не важно как это происходит.Рассмотрим на конкретных примерах, как проходил процесс разработки.
  • Таким образом, задача свелась к созданию механизма, который совмещал бы в себе обе технологии и реализованный так, чтобы конечному разработчику было не важно как это происходит.Рассмотрим на конкретных примерах, как проходил процесс разработки.
  • На HTML5, это выглядит следующим образом: Получаем ссылку на инпут, далее подписываемся на событие change
  • На HTML5, это выглядит следующим образом: Получаем ссылку на инпут, далее подписываемся на событие change. И когда оно срабатывает, получаем список файлов прямиком из него.
  • Но что делать когда не поддерживаетсяFileAPI, но за то поддерживается Flash? Основным принципом работы с flash, в том, что всё взаимодействие происходит непосредственно через через него, т.е. нельзя просто взять и вызвать диалог выбора файлов. Для этого, необходимо чтобы пользователь кликнул по flash,и только в этот момент открыть диалог, такова политика безопасности, диалог можно открыть только на действие пользователя.
  • Поэтому flash объект размещается над нужным input. Сделано это очень просто,вешается обработчик события mouseoverна весь документ и при наведении на input, публикуем flash-объект в его родитель, относительно которого и позиционируем с нужными размерами.
  • При клике по флешке открывается диалог выбора файлов, пользователь там что-то выбирает и кликает «ОК». После чего, данные получает flash, которые всю очередь передает их JS, посредством вызова callback-функции. После чего JS связывает полученные данные с нужным инпутом и эмулирует событие “change”.
  • При клике по флешке открывается диалог выбора файлов, пользователь там что-то выбирает и кликает «ОК». После чего, данные получает flash, которые всю очередь передает их JS, посредством вызова callback-функции. После чего JS связывает полученные данные с нужным инпутом и эмулирует событие “change”.
  • Все дальнейшее взаимодействие между JS и flash, будет осуществляется через единственный доступный метод у flash, первый аргументом передается название команды, вторым объект параметров, с двумя обязательными полями: id-файлаи callback. Callback будет вызван из flash, по завершению команды.
  • После совмещения двух способов, получилось вот такое API, оно максимально приближено к нативномуjs, единственное различие, это способ получения файлов. Теперь мы используем метод API, тк свойство files у инпута есть только в том случае, когда браузер поддерживает HTML5/FileAPI, в случае с Flash список берется из связанных с ним данных.
  • После совмещения двух способов, получилось вот такое API, оно максимально приближено к нативномуjs, единственное различие, это способ получения файлов. Теперь мы используем метод API, тк свойство files у инпута есть только в том случае, когда браузер поддерживает HTML5/FileAPI, в случае с Flash список берется из связанных с ним данных.
  • Следующим важным шагом, является фильтрация.  Как правило, при загрузке файлов, есть ряд ограничений, таких как размер или тип. Хотя в почте и можно прикреплять любые файлы, для нас было важным получить универсальное решение, так что фильтрация необходима. В чем же её сложность?!Вся соль в том, что изначально, после получения списка файлов, мы имеем только минимальный сведения, такие как название, размер и тип. Но, что делать, когда нужно получить id3 теги или размеры изображения?
  • Все просто, файл нужно прочесть. Для этого в существует FileReader, которые позволяет асинхронно читать файл. И на основе результата чтения, получить нужную информацию, а так как для разных типов файлов, есть свой способ её получения, мы реализовали получение только размеров изображения, как на HTML5, так и через флеш. Но, оставили возможность добавлять свои обработчики, для сбора инфы, в которых разработчик может написать свою реализацию, либо использовать готовое решение.
  • Вот так выглядит метод фильтрации, первым аргументом передаем список файлов, вторым саму функцию фильтрации и третьим callback-который будет вызван по завершению. На выходе получаем два массива, с файлами которые подошли под условия и со всем остальными.
  • При помощи метода FileAPI.addInfoReader, добавляем обработчики информации, для нужных типов файлов, первым аргументом указываем тип, вторым фунцию-обработчик.
  • Так же существует метод получения информации для конкретного файла.
  • Одной из ключевых особенностей нашего flash-загрузщика, была возможность создавать предросмотр изображений. Проблема была в том, что превью было частью flash, те рисовалась в нем. В API такого быть не должно. Но как передать изображение из Flashв HTML?
  • В этом нам поможет DataURI — это определённая стандартомсхема, которая позволяет включать небольшие элементы данных в строкуи использовать в качестве ссылки, в данном случае в качестве srcизображения.
  • Flashчитает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как srcизображения.
  • Flashчитает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как srcизображения.
  • Flashчитает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как srcизображения.
  • На хтмл5 тоже не без сюрпризов,  есть два способа получить изображение.Первый способ, это прочесть файл как DataURL, при помощиFileReader. Второй, createObjectURL — создает ссылку на файл, связанную с текущим табом. Конечно для создания пердпросмотра достаточно второго способа, но не все бразуеры его поддерживают.
  • Так же у Оперы нетметода revokeObjectURL, который сообщает браузеру, что больше не нужно держать ссылку на файл.
  • Класс, обладает следующими методами: кадрирование, масштабирование, поворот и preview, который автоматически кадрирует и масштабирует. Все эти методы заполняют матрицу трансформации и только при вызове метода get, она будет применена. Трансформация происходит через canvas иливнутри flash, когда работает через него.
  • Трансформация происходит через canvas иливнутри flash, когда работает через него. Вот так выглядит та самая матрица,
  • Вот так выглядит создание пердпросмотра 120х120 пикселей, вызываем метод preview, передаем требуемые размеры и вызываем метод get, на вход которого передаем callback, который будет вызван по завершению.
  • Отдельно отмечу процесс ресайза. Если нужно получить превью 100х100, а оригинал примерно 10 МПх, а это вполне реальная ситуация, сейчас каждая мыльница кичится количеством мега-пикселей, то вы получите изображение, примерно такого качества.
  • Как видите, ничего хорошего, сплошные искажения.
  • Но, если сжимать в два раза,потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше.
  • Но, если сжимать в два раза,потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше. Вот, сравните, разница на лицо.
  • Но, если сжимать в два раза,потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше. Вот, сравните, разница на лицо.
  • Еще мы пробовали другие способы, такие как бикубическая интерполяция и алгоритм Ланцоша. Они конечно дают лучший результат, но очень медленные, 1.5сек против 200-300милисекунд. Также данный метод дает одинаковый результат в cavnasи flash.
  • Последняя и основная возможность нашего API, это конечно же загрузка файлов на сервер.
  • Которая должна отвечать следующим требованиям: файлы должны отправляться без обновления страницы, следить за ходом загрузки и получать ответ от сервера.
  • Вот так выглядит самый простой способ загрузки файлов.
  • Для улучшение ситуация, добавляем в форму iframeс уникальным именем, а у формы такой же target.Теперь при сабмите, форма будет отправлена в этот ифрейм. Этот способ позволяет избавиться избавиться от обновления страницы, также работает во всех браузерах, есть возможность получить ответ от сервера, но не дает сведений о ходе загрузки.
  • Последний способ, отправить файл на сервер, не считая flash, это XmlHttpRequest2 и FormData. Он позволяет отправить не просто тестовые данные, но и бинарные.
  • FormData — позволяет создать набор ключ-значение. У неё есть единственный метод append, первым аргументом задаётся название POST-параметра, вторым строка или файл, также есть третий аргумент, название файла, но его пока не все поддерживают.
  • Далее при помощиXmlHttpRequestотправляет собранные данные на сервер.Но ничего не бывает так просто. Как я уже говорил ранее, API должно уметь отправлять модифицированное изображение.
  • Т.к. все трансформации идут через canvas, то именно его и нужно отправить на сервер и это можно сделать, при помощи трансформации canvas в blob, её можно реализовать практически во всех браузерах. Но там, где это невозможно, а это например Opera, мы загружаем cavnas ручного составления мултипарт запроса. И в этом случае, мы делаем следующее:
  • Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  • Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  • Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  • Справедливости ради замечу, что данный способ используется и для тех браузеров, которые не поддерживаютFormData. Т.е. При помощи FileReaderчитаем файл как DataURL и по такой же схеме отправляем их на сервер.
  • На вход ему передается объект параметров: «куда заливать», «дополнительная POST-дата» и «заголовки запроса», также обработчики событий, как для слежения за ходом всей загрузки, так и отдельным файлом. Хотя HTML5 позволяет грузить все файлы сразу, стандартный механизм Flash’а нет, плюс это не очень удачная идея, пользователь может и передумать.
  • На вход ему передается объект параметров: «куда заливать», «дополнительная POST-дата» и «заголовки запроса», также обработчики событий, как для слежения за ходом всей загрузки, так и отдельным файлом. Хотя HTML5 позволяет грузить все файлы сразу, стандартный механизм Flash’а нет, плюс это не очень удачная идея, пользователь может и передумать.
  • Это позволяет перенести часть нагрузки по обработке изображений с сервера, на клиент.
  • Так же функции upload возвращает xhr-образный объект, т.е. он реализует некоторые свойства и методы XmlHttpRequest, такие как
  • Но это еще не все, на самом деле, это прокси объект. Его методы и свойства отражают состояния именно для того файла, который грузится в данный момент.
  • константин лебедев

    1. 1. FileAPI: Загрузка и обработка файлов
    2. 2. Что было 3
    3. 3. Что было 4
    4. 4. Что было Flash 5
    5. 5. Что было HTML/JS 6
    6. 6. Требования • Множественный выбор файлов • Получение информации (название, размер, тип) • Создание пред-просмотра на клиенте • Масштабирование, кадрирование и поворот • Загрузка на сервер + CORS 7
    7. 7. Требования • Не зависеть от вѐрстки • Никакой бизнес-логики • Расширяемость • Самодостаточность 8
    8. 8. Error #203810%
    9. 9. Error #2038 5%
    10. 10. Поддержка • Chrome 10+ • FireFox 3.6+ • Opera 11.1+ • Safari 5.4+ 12
    11. 11. 13
    12. 12. ПОЛУЧЕНИЕ СПИСКА ФАЙЛОВ 14
    13. 13. HTML5<input id="file" type="file" multiple /><script> var input = document.getByElementId("file"); input.addEventListener("change", function (){ var files = input.files; }, false);</script> 15
    14. 14. HTML5<input id="file" type="file" multiple /><script> var input = document.getByElementId("file"); input.addEventListener("change", function (){ var files = input.files; }, false);</script> 16
    15. 15. HTML5<input id="file" type="file" multiple /><script> var input = document.getByElementId("file"); input.addEventListener("change", function (){ var files = input.files; }, false);</script> 17
    16. 16. Flash FLASH 18
    17. 17. Flash FLASH 19
    18. 18. Flash FLASH Flash --> jsFunc([{ id: "346515436346", // уникальный идентификатор name: "hello-world.png", // название файла type: "image/png", // mime-type size: 43325 // рамер }, { // etc. }]) 20
    19. 19. Взаимодействие flash.cmd("imageTransform", { id: "346515436346", // идентификатор файла matrix: { }, // "матрица" трансформации callback: "__UNIQ_NAME__" // размер });
    20. 20. API <span class="js-fileapi-wrapper" style="position: relative"> <input id="file" type="file" multiple /> </span> <script> var input = document.getByElementId("file"); FileAPI.event.on(input, "change", function (){ var files = FileAPI.getFiles(input); }, false); </script> 22
    21. 21. API <span class="js-fileapi-wrapper" style="position: relative"> <input id="file" type="file" multiple /> </span> <script> var input = document.getByElementId("file"); FileAPI.event.on(input, "change", function (evt){ var files = FileAPI.getFiles(evt); }, false); </script> 23
    22. 22. ФИЛЬТРАЦИЯ 24
    23. 23. FileReader • readAsDataURL(file) • readAsBinaryString(file) • readAsArrayBuffer(file) • readAsText(file[, encoding])
    24. 24. Фильтрация FileAPI.filterFiles(files, function (file, info){ return file.size < 10 * FileAPI.MB; }, function (files, ignore){ if( files.length > 0 ){ // ... } }); 26
    25. 25. Информация о файле FileAPI.addInfoReader(/^audio/, function (file, callback){ // собираем нужную информацию // и возвращаем еѐ callback( false, // или текст ошибки { artist: "...", album: "...", title: "...", ... } ); });
    26. 26. Информация о файле FileAPI.getInfo(audioFile, function (err, tags){ if( !err ){ var li = document.createElement("li"); li.innerHTML = tags.artist +" – "+ tags.title; ul.appendChild(li); } });
    27. 27. ПРЕДПРОСМОТР
    28. 28. Предпросмотр DataURI
    29. 29. Предпросмотр DataURI Base64
    30. 30. Предпросмотр DataURI <img/> Base64 ―data:image/png;base64,‖ + Base64
    31. 31. Предпросмотр DataURI <img/> Base64 ―data:image/png;base64,‖ + Base64
    32. 32. Предпросмотр HTML5 • FileReader.readAsDataURL(file) — позволяет прочесть содержимое файла как DataURL • URL.createObjectURL(file) — создает ссылку, указывающую на файл
    33. 33. Предпросмотр HTML5 • FileReader.readAsDataURL(file) — позволяет прочесть содержимое файла как DataURL • URL.createObjectURL(file) — создает ссылку, указывающую на файл • URL.revokeObjectURL(file) — убрать ссылку
    34. 34. FileAPI.Image • crop(x, y, width, height) — кадрирование • resize(width[, height]) — масштабирование • rotate(deg) — поворот • preview(width, height) — кадрирует и масштабирует • get(callback) — получить итоговое изображение 36
    35. 35. Matrix { // параметры фрагмента оригинала sx: Number, sy: Number, sw: Number, sh: Number, // требуемые размеры dw: Number, dh: Number, deg: Number } 37
    36. 36. FileAPI.Image FileAPI.Image(imageFle) .crop(300, 300) .resize(100, 100) .get(function (err, img){ if( !err ){ images.appendChild(img); } }) ; 38
    37. 37. Сжатие 5197х4987
    38. 38. Сжатие
    39. 39. Сжатие 5197х4987 2598х2493
    40. 40. Сжатие x 25197х4987 2598х2493 1299х1246
    41. 41. Сжатие x 55197х4987 2598х2493 1299х1246 100х100
    42. 42. Сжатие Серия
    43. 43. ЗАГРУЗКА ФАЙЛОВ
    44. 44. Требования • Без обновления страницы • Процесс загрузки • Получить ответ от сервера
    45. 45. Загрузка <form action="/upload" method="post" enctype="multipart/form-data"> <input name="files" type="file" /> <input name="foo" value="bar" type="hidden" /> </form>
    46. 46. Загрузка <form target="__UNIQ__" Уникальный идентификатор action="/upload" method="post" enctype="multipart/form-data"> <iframe name="__UNIQ__"></iframe> <input name="files" type="file" /> <input name="foo" value="bar" type="hidden" /> </form>
    47. 47. Загрузка XMLHttpRequest level 2 FormData
    48. 48. Загрузка // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", file); // отправояем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form)
    49. 49. Загрузка // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", file); // отправляем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form)
    50. 50. Загрузка canvasToBlob(canvas, function (blob){ // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", blob, "filename.png"); // отправляем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form) });
    51. 51. ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);<cavnas/> DataURL
    52. 52. ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);base64 = dataURL.replace(/^data:[^,]+,/, ―‖);<cavnas/> DataURL Base64
    53. 53. ЗагрузкаdataURL = canvas.toDataURL(―image/png‖);base64 = dataURL.replace(/^data:[^,]+,/, ―‖);binaryString = window.atob(base64);<cavnas/> DataURL Base64 BinaryString
    54. 54. Multipart var uniq = 1234567890; var xhr = new XMLHttpRequest; xhr.open(POST, /upload, true); xhr.setRequestHeader(Content-Type, multipart/form-data; boundary=_+uniq); xhr.sendAsBinary([ --_+ uniq , Content-Disposition: form-data; name="my-file"; filename="hello-world.png" , Content-Type: image/png , , binaryString , --_+ uniq +-- ].join(rn)); 56
    55. 55. Загрузка var xhr = ​FileAPI.upload({ url: /upload, data: { foo: bar }, headers: { Session-Id: ... }, files: { images: imageFiles, others: otherFiles }, imageTransform: { maxWidth: 1024, maxHeight: 768 }, upload: function (xhr){}, progress: function (event, file){}, complete: function (err, xhr, file){}, fileupload: function (file, xhr){}, fileprogress: function (event, file){}, filecomplete: function (err, xhr, file){} });​ 57
    56. 56. Загрузка var xhr = ​FileAPI.upload({ url: /upload, data: { foo: bar }, headers: { Session-Id: ... }, files: { images: imageFiles, others: otherFiles }, imageTransform: { maxWidth: 1024, maxHeight: 768 }, upload: function (xhr){}, progress: function (event, file){}, complete: function (err, xhr, file){}, fileupload: function (file, xhr){}, fileprogress: function (event, file){}, filecomplete: function (err, xhr, file){} });​ 58
    57. 57. Загрузка imageTransform: { huge: { maxWidth: 800, maxHeight: 600, rotate: 90 }, medium: { width: 320, height: 240, preview: true }, small: { width: 100, height: 120, preview: true } }
    58. 58. XHRvar xhr = FileAPI.upload({ … }); 60
    59. 59. XHRvar xhr = FileAPI.upload({ … }); • status — HTTP status code • statusText — HTTP status text • responseText — ответ сервера • getResponseHeader(name) — получить заголовок ответа сервера • getAllResponseHeaders() — получить все заголовки • abort() — отменить загрузку 61
    60. 60. Drag’n’Drop <div class="dropzone"></div> Перетащите файлы сюда
    61. 61. Drag’n’Drop <div class="dropzone dropzone_hover"></div> 4
    62. 62. Drag’n’Drop <div id="el" class="dropzone"></div> <script> var el = document.getElementById("el"); FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); } else { 4 el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
    63. 63. Drag’n’Drop <div id="el" class="dropzone"></div> <script> var el = document.getElementById("el"); FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); 4 } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
    64. 64. Drag’n’Drop <div id="el" class="dropzone"></div> <script> var el = document.getElementById("el"); FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); 4 } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
    65. 65. Drag’n’Drop <div id="el" class="dropzone"></div> <script> var el = document.getElementById("el"); FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); 4 } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
    66. 66. Drag’n’Drop function uploadFiles(dropFiles){ FileAPI.upload({ url: "/upload", files: { attaches: dropFiles }, complete: function (err, xhr){ if( !err ){ 4 // файлы загружены } } }); }
    67. 67. https://github.com/mailru/FileAPI Константин Лебедев JavaScript архитектор k.lebedev@corp.mail.ru

    ×