Java Script

Описание: Наиболее перспективное направление развития компьютерных наук. Надо быть в теме!

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#13 dyvniy » Вс, 27 сентября 2015, 23:01:11

HTML5 версия StarCraft
https://github.com/gloomyson/StarCraft
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#14 dyvniy » Вт, 29 сентября 2015, 17:02:21

Лямбды
http://habrahabr.ru/post/113344/

Код: Выделить всё

//Python:
lambda xx

//Smalltalk:
[ :]

//JavaScript 1.8:
function(xx
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#15 dyvniy » Пн, 5 октября 2015, 13:36:08

Распределённые вычисления JS
http://habrahabr.ru/post/119692/
http://geektimes.ru/post/87274/
мало о чём, но всё же
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#16 dyvniy » Вс, 11 октября 2015, 18:56:14

static & prototype
http://stackoverflow.com/questions/1535631/static-variables-in-javascript

Код: Выделить всё

function MyClass () { // constructor function
  
var privateVariable "foo";  // Private variable 

  
this.publicVariable "bar";  // Public variable 

  
this.privilegedMethod = function () {  // Public Method
    
alert(privateVariable);
  };
}

// Instance method will be available to all instance but only load once in memory 
MyClass.prototype.publicMethod = function () {    
  
alert(this.publicVariable);
};

// Static variable shared by all instance 
MyClass.staticProperty "baz";

//...
var myInstance = new MyClass(); 
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#17 dyvniy » Чт, 15 октября 2015, 13:26:24

Загрузка файлов на сервер
http://habrahabr.ru/post/109079/
Спойлер
HTML5 File API: множественная загрузка файлов на сервер из песочницы
Веб-разработка*, jQuery*
Когда передо мной в очередной раз встала задача об одновременной загрузке нескольких файлов на сервер (без перезагрузки страницы, само собой), я стал блуждать по интернетам в поисках довольно корявого jQuery-плагина, который позволяет имитировать ajax-загрузку файла (того самого плагина, который со скрытым фрэймом: от java- и flash- плагинов сразу было решено отказаться). В процессе поиска я вспомнил, что в грядущем стандарте html 5 возможности по работе с файлами должны быть существенно расширены, и часть этих возможностей доступна уже сейчас. В итоге было решено опробовать их в действии.

Рассматривать возможности File API будем на примере одновременной загрузки нескольких картинок на сервер. В конце статьи приводится готовое решение, оформленное в виде jQuery-плагина.


Не хочу это читать, интересует готовое решение.

Итак, какие же преимущества дает нам использование File API:
Независимость от внешних плагинов
Возможность контролировать процесс загрузки и отображать информацию о нем (прогрессбар всегда добавляет терпения пользователю)
Возможность прочитать файл и узнать его размер до начала загрузки (в нашем примере это дает нам возможность отсеять файлы, не содержащие изображений и показывать миниатюры картинок)
Возможность выбрать сразу несколько файлов через стандартное поле выбора файла
Возможность использовать интерфейс drag and drop для выбора файлов. Да-да, мы сможем перетаскивать файлы для загрузки прямо с рабочего стола или, например, из проводника!

Из недостатков можно отметить только недостаточную поддержку в браузерах. Сейчас File API поддерживают только Firefox ≥ 3.6 и Chrome ≥ 6.0. Есть такое ощущение, что и Safari уже совсем скоро подтянется, а вот про IE и Opera пока ничего не ясно (может быть, кто-то располагает сведениями?). Расстроило конечно, что File API не поддерживает IE9 Beta: это странно, учитывая что разработчики IE сейчас взяли курс на обильную поддержку html 5. Но как бы то ни было, очевидно, что в будущем всем браузерам придется подтянуться.

Работающий пример можно увидеть по адресу http://safron.su/playground/html5uploader/, ниже приведены только наиболее важные фрагменты кода.

Для начала разберемся с html-кодом. Нам понадобится дефолтный элемент input, контейнер для перетаскивания файлов и список ul, куда мы будем помещать миниатюрки изображений:
<div>
<input type="file" name="file" id="file-field" multiple="true" />
</div>
<div id="img-container">
<ul id="img-list"></ul>
</div>


Ничего особенного, кроме того, что для элемента input указан атрибут multiple="true". Это необходимо для того, чтобы в стандартном диалоге выбора файлов можно было выделять их сразу несколько. Кстати, начиная с Firefox 4, разработчики браузера обещают, что ненавистные многим верстальщикам стандартные поля выбора файла можно будет скрывать, а диалог показывать, вызвав событие click для скрытого элемента.

Теперь перейдем к JavaScript (обратите внимание, что я использовал jQuery для упрощения манипуляций с DOM. Тот, кто по каким-либо причинам захочет отказаться от jQuery, сможет без труда переделать скрипты таким образом, чтобы обойтись без него). Сначала сохраним в переменных ссылки на html-элементы, снявшиеся в главных ролях. Далее определим обработчики событий для стандартного поля выбора файлов и для области, куда можно будет перетаскивать файлы.
// Стандарный input для файлов
var fileInput = $('#file-field');

// ul-список, содержащий миниатюрки выбранных файлов
var imgList = $('ul#img-list');

// Контейнер, куда можно помещать файлы методом drag and drop
var dropBox = $('#img-container');

// Обработка события выбора файлов в стандартном поле
fileInput.bind({
change: function() {
displayFiles(this.files);
}
});

// Обработка событий drag and drop при перетаскивании файлов на элемент dropBox
dropBox.bind({
dragenter: function() {
$(this).addClass('highlighted');
return false;
},
dragover: function() {
return false;
},
dragleave: function() {
$(this).removeClass('highlighted');
return false;
},
drop: function(e) {
var dt = e.originalEvent.dataTransfer;
displayFiles(dt.files);
return false;
}
});


И в том и в другом случае в обработчике мы получаем доступ к объекту FileList, который по сути представляет собой массив объектов File. Этот массив передается функции displayFiles(), текст которой приведен ниже.
function displayFiles(files) {
$.each(files, function(i, file) {
if (!file.type.match(/image.*/)) {
// Отсеиваем не картинки
return true;
}
// Создаем элемент li и помещаем в него название, миниатюру и progress bar,
// а также создаем ему свойство file, куда помещаем объект File (при загрузке понадобится)
var li = $('<li/>').appendTo(imgList);
$('<div/>').text(file.name).appendTo(li);
var img = $('<img/>').appendTo(li);
$('<div/>').addClass('progress').text('0%').appendTo(li);
li.get(0).file = file;

// Создаем объект FileReader и по завершении чтения файла, отображаем миниатюру и обновляем
// инфу обо всех файлах
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.attr('src', e.target.result);
aImg.attr('width', 150);
/* ... обновляем инфу о выбранных файлах ... */
};
})(img);

reader.readAsDataURL(file);
});
}


Объект File содержит метаданные о файле, такие как его имя, размер и тип (в формате MIME, например, image/gif) соответственно в свойствах name, size и type. Для доступа же к содержимому файла существует специальный объект FileReader.

Внутри функции displayFiles() мы проходимся по переданному массиву файлов и сначала отсеиваем те, которые не являются изображениями. Далее для каждого изображения создается элемент списка li, куда помещается пустой пока элемент img (обратите внимание, что в кажом элементе li также создается свойство file, содержащее соответствующий объект). После чего создается экземпляр FileReader и для него определяется обработчик onload, в котором данные передаются прямо в атрибут src созданного ранее элемента img. Метод readAsDataURL() объекта FileReader принимает параметром объект File и запускает чтение данных из него. В результате для всех выбранных через стандартное поле или перетащенных прямо в браузер картинок, мы видим их миниатюры (искусственно уменьшенные до 150 пикселей).

Что еще осталось сделать? Осталось только реализовать саму загрузку всех выбранных файлов на сервер. Для этого создадим какую-нибудь кнопку или ссылку, при нажатии на которую останется только пробежаться по всем созданным элементам li, прочитать их свойство file и передать в функцию uploadFile(), текст которой приведен ниже. Отмечу, что здесь для упрощения я реализовал загрузку через функцию, а в реальном примере, расположенном по адресу http://safron.su/playground/html5uploader/, я собрал все действия по загрузке в объект uploaderObject, при создании которого можно передать дополнительные параметры, такие как функции обратного вызова для получения информации о процессе загрузки.
function uploadFile(file, url) {

var reader = new FileReader();

reader.onload = function() {
var xhr = new XMLHttpRequest();

xhr.upload.addEventListener("progress", function(e) {
if (e.lengthComputable) {
var progress = (e.loaded * 100) / e.total;
/* ... обновляем инфу о процессе загрузки ... */
}
}, false);

/* ... можно обрабатывать еще события load и error объекта xhr.upload ... */

xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if(this.status == 200) {
/* ... все ок! смотрим в this.responseText ... */
} else {
/* ... ошибка! ... */
}
}
};

xhr.open("POST", url);
var boundary = "xxxxxxxxx";
// Устанавливаем заголовки
xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Cache-Control", "no-cache");
// Формируем тело запроса
var body = "--" + boundary + "\r\n";
body += "Content-Disposition: form-data; name='myFile'; filename='" + file.name + "'\r\n";
body += "Content-Type: application/octet-stream\r\n\r\n";
body += reader.result + "\r\n";
body += "--" + boundary + "--";

if(xhr.sendAsBinary) {
// только для firefox
xhr.sendAsBinary(body);
} else {
// chrome (так гласит спецификация W3C)
xhr.send(body);
}
};
// Читаем файл
reader.readAsBinaryString(file);
}


Здесь создается экземпляр уже знакомого нам объекта FileReader, точно так же, как и выше; ему присваивается обработчик события onload, в котором создается XMLHttpRequest (к сожалению, пока нельзя воспользоваться ajax-интерфейсом jQuery, поскольку там еще не предусмотрена загрузка файлов). В XMLHttpRequest второй версии появилось свойство upload, содержащее объект-загрузчик, который может обрабатывать события progress, load и error (подробнее см. http://www.w3.org/TR/XMLHttpRequest2/#xmlhttprequesteventtarget). В примере выше показана только обработка события progress. Далее присваиваем обработчик завершения запроса самому реквесту (в отличие от событий объекта-загрузчика он вызывается уже тогда, когда все данные загружены и ответ от сервера получен), добавляем два дополнительных заголовка и формируем тело запроса, читая данные из свойства result объекта FileReader. После этого загрузка запускается. Отмечу только, что по нынешней спецификации W3C подразумевается, что метод send() объекта XMLHttpRequest может принимать в параметре бинарные данные, что успешно и реализовано в Google Chrome, однако в Firefox сделано по-своему, через особый метод sendAsBinary(). Поэтому перед началом отправки проверяем, определен ли метод sendAsBinary() в объекте реквеста, и, если да, используем его.

Вот, собственно, и все. С нетерпением ждем утверждения и распространения html 5!

Кое-какие ссылки

http://safron.su/playground/html5uploader/ — работающий пример того, что описывалось выше (плюс еще кое-что)
http://safron.su/playground/html5uploader/full.zip — весь код целиком в архиве
http://html5test.com — проверка браузеров на соответсвие html 5 (очень наглядно)
http://playground.html5rocks.com — площадка для экпериментов с кодом от Google (ее интерфейс будет знаком тем, кто использовал многочисленные API Google)


UPD
Для упрощения использования всего вышеизложенного, был создан JQuery-плагин. При помощи него можно загружать файлы через File API там, где это возможно, и реализовать замену (например, обычную отправку формы) там, где нет. По просьбам трудящихся и соотносясь с замечаниями комментаторов, была добавлена загрузка через объект FormData в браузерах, которые его поддерживают (Chrome, Safari 5+, FF 4+). В самом верху файла с плагином есть описание параметров, методов, а также краткие примеры использования. Более полный пример использования можно увидеть здесь (это изначальный пример из этой статьи, только переделанный на использование плагина, его полный код, включая серверную часть, можно скачать здесь [see UPD2]).

Использованные источники

https://developer.mozilla.org/en/using_files_from_web_applications — статья о файловом интерфейсе на сайте девелоперов Mozilla
https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest — cтатья об использовании XMLHttpRequest там же
http://www.w3.org/TR/FileAPI/ — текущая спецификация File API на сайте W3C
http://www.w3.org/TR/XMLHttpRequest2/ — текущая спецификация XMLHttpRequest там же



UPD2
По просьбе пользователя glebovgin плагин был доработан таким образом, чтобы можно было отправлять не только непосредственно объект File, но также Blob-данные (объект Blob). Это может быть полезно, если есть необходимость отправлять на сервер, например, содержимое canvas, ну или просто вручную сгенерированные данные.

В демке (которая переехала немного на другой адрес) был добавлен пример отправки картинки из canvas. На данный момент эта возможность работает в FF, Chrome, IE10.

Исходный код ныне доступен на GitHub. Замечания, предложения, улучшения приветствуются!
html, html5, file upload, file api, jquery, jquery plugin
+97

50680

437


Саша Сафронов @safron карма54,0 рейтинг0,0
Похожие публикации

Мой последний file uploader (26)
PickMeUp — хороший jQuery datepicker plugin (49)
Спасибо за HTML5 File API или читаем ID3-тег и заполняем форму не загружая MP3-файл (12)
jQuery File Upload (118)
Drag'n'drop файлов во Flex, используя HTML5 File API (4)
Комментарии (57)

+1 dapmoed30 ноября 2010 в 17:32#
Очень вовремя! Вот только собирался использовать мультиаплоад в своем проекте и вот замечательная статья.
Довольно четко и очень понятно объяснено.
Огромное спасибо.
+1 safron30 ноября 2010 в 17:35#↵↑
на здоровие ;)
0 Sannis 1 декабря 2010 в 09:31#↵↑
Как вы собираетесь реализовать поддержку старых браузеров?
0 TheShock16 декабря 2010 в 20:19#↵↑
забить?)
+1 lutz30 ноября 2010 в 17:39#
Изящное решение на html5 + вечный грубый костыль со скрытым вреймом для IE6-8…
0 proc30 ноября 2010 в 17:40#
Эх, жаль что это можно будет использовать только года через 3-4 когда умрут все браузеры которые не понимают html5
+2 safron30 ноября 2010 в 17:48#↵↑
Не скажите, смотря для каких целей. Например, в данном случае я делал интерфейс для одной почтенной женщины-фотографа, она использует (а если бы и не использовала, то можно было бы убедить) файрфокс и ее все устраивает.

Или вот пример с gmail — они же отказались от поддержки IE6, хотя его до сих пор используют 15 (или даже 20) % пользователей, которые получают предупреждение, что их браузер устарел.

Тут два варианта: делать костыли для более старых браузеров и честно говорить пользователям, что надо обновить браузер.

Но это я так. Согласен, чтоэту технологию пока рано запускать в массы. Как минимум надо дождаться, когда все последние версии браузеров будут ее поддерживать.
+2 dapmoed30 ноября 2010 в 17:51#↵↑
Зря Вы так. Для массового пользователя — да, а вот для своего удобства — уже сейчас.
0 script8830 ноября 2010 в 17:54#↵↑
Мало по малому, но уже можно начинать внедрять
+1 TiKo30 ноября 2010 в 17:40#
К сожалению в реальных проектах придется использовать еще и альтернативный вариант загрузки, пока такой функционал не будут поддерживать основные броузеры :(
+17 lutz30 ноября 2010 в 17:41#
Дедушка Мороз, я хорошо себя вел в этом году, пожалуйста, сделай так чтобы IE не стало…
0 lesa8030 ноября 2010 в 17:44#
грустно когда ездить можно на приличных авто… а клиент хочет (тоже конечно не по своей воле) ваз тюнинговать… ((
+1 barmaley_exe30 ноября 2010 в 18:00#
Расстроило конечно, что File API не поддерживает IE9 Beta: это странно, учитывая что разработчики IE сейчас взяли курс на обильную поддержку html 5. Но как бы то ни было, очевидно, что в будущем всем браузерам придется подтянуться.
Ничего странного, все просто. File API — черновик, его еще будут дописывать и переписывать. Если бы в IE9 внедрили FileAPI в текущем виде, то ничего хорошего не вышло бы. А мозиловцы вообще любят всякую экспериментальщину внедрять. Отсюда и остался в FF 3.6 метод sendAsBinary. В 4-ке уже должен быть FormData, который и описывается в последней версии черновика.
0 safron30 ноября 2010 в 18:15#↵↑
Согласен, весь HTML5 пока черновик, но ничего плохого в том, если бы ИЕ поддерживал уже тоже не было бы. Вообще, остальные браузеры регулярно обновляют младшие версии (может, подверсии? как правильно?), добавляя новые возможности. А уж если в ИЕ какой-то возможности нет, то еще год-другой надо ждать, пока выйдет следующий.
0 barmaley_exe30 ноября 2010 в 18:26#↵↑
Вот в этом-то и проблема. Если Хром, FF, Опера обновляются достаточно часто, то IE — крайне редко. Поэтому внедрять что-то экспериментальное в IE опасно, т.к. может так случиться, что через неделю после релиза черновик перепишут, выпустят новые версии браузеров и… IE останется не у дел, со старыми реализациями (и снова хаки для IE). Разработчики оперы тоже не любят экспериментальные фичи. Вспомнить хотя бы border-radius (и многие другие css3 свойства), реализовывать которые Opera Software не спешили.

А вообще, реализовывать такой функционал следует только при уверенности, что Вы сможете среагировать на изменение стандарта. Если Вы работаете над сайтом, который Вы точно будете поддерживать через полгода-год, то не страшно. А если Вы работаете над заказом, то лучше на это не рассчитывать. Иначе вместе с очередным обновлением браузеров может умереть весь новый функционал, а исполнителя и след простыл.
+1 safron30 ноября 2010 в 18:29#↵↑
Ну ок, убедили — хорошо, что ИЕ пока не поддерживает :)
+1 script8830 ноября 2010 в 19:44#↵↑
По моему IE как был не удел так и будет.
0 develop7 1 декабря 2010 в 11:38#↵↑
Если Хром, FF, Опера обновляются достаточно часто, то IE — крайне редко
а так нечестно, да
+1 Demetros30 ноября 2010 в 18:05#
Для загрузки картинок (небольших файлов) ваш код условно подходит.
По-нормальному, надо без извращений с ручным формированием тела запроса использовать FormData
0 safron30 ноября 2010 в 18:10#↵↑
правильно, но к сож. файрфокс пока не поддерживает. Выйдет официальо 4й — переделаем!
0 safron25 февраля 2011 в 04:23#↵↑
Переписал код так, чтоб где это возможно использовался FormData. Если интересно, см. апдейт внизу статьи.
0 Santacruz30 ноября 2010 в 19:25#
вовремя… надо бы jquery plugin заделать
0 safron30 ноября 2010 в 19:42#↵↑
сделаете? покажете?
–1 Santacruz30 ноября 2010 в 20:09#↵↑
искал добровольцев :)
0 safron25 февраля 2011 в 04:24#↵↑
Сделано! Если интересно, см. апдейт к статье.
0 Zerstoren30 ноября 2010 в 19:29#
Спасибо! Применю на своем проекте, как раз не будет лишним)

+1 Zerstoren30 ноября 2010 в 19:30#↵↑
и да здравствует HTML5 в W3C
www.w3.org/TR/FileAPI/ — текущая спецификация File API на сайте W3C

0 ymik30 ноября 2010 в 20:06#
Для скрытия инпута можно просто сделать ему visibility:hidden и растянуть поверх графического элемента
0 TEHEK30 ноября 2010 в 22:01#
М… меня опередили *сворачивает черновик* =)
0 b0n3Z30 ноября 2010 в 22:26#
Последний год использовал www.plupload.com/.
Опенсурс библиотека для загрузки файлов. Поставил на сайт — если у пользователя оказывался не хтмл5-браузер, автоматически библиотека переключала на другой способ загрузки.
Апи очень простое, рекомендую.
0 safron30 ноября 2010 в 22:43#↵↑
Спасибо за линк! Это громоздкое, но зато комплексное решение по загрузке файлов. И, насколько я понял, оно уже использует html 5 там, где это возможно
0 b0n3Z30 ноября 2010 в 22:46#↵↑
Да, так и есть. Более того, через апи самому можно выставлять приоритет способов загрузки. Я ранее ставил так: gears -> html5 -> flash -> silverlight -> html4.
0 safron30 ноября 2010 в 22:47#↵↑
ок, спс за инфо. Я гуглил готовые решения перед тем как сделать свой вариант, но на это не натыкался.
0 bolk30 ноября 2010 в 23:08#
Ссылка по теме: bolknote.ru/2009/11/30/~2322
0 mihaild 1 декабря 2010 в 02:22#
На правах рекламы:
code.google.com/p/jquery-html5-upload/
+2 webwin 1 декабря 2010 в 11:24#
Спасибо
вместо $('ul#img-list') используйте $('#img-list'). Во втором случае получим элемент намного быстрей, так как будет использоваться родной document.getElementById
0 safron 1 декабря 2010 в 15:15#↵↑
спасибо за инфо. Это, знаете ли, просто привычка, чтоб в коде видеть, какой именно элемент имеет такой айди (надо в комментариях писать — никак не могу переучиться). Потом везде убрал, а тут забыл.
0 b0n3Z 1 декабря 2010 в 23:31#
Сегодня весь вечер внедрял загрузку по этому посту и нашел очень неприятную штуковину.
В частности, этот код:
if (self.xhr.sendAsBinary) {
// firefox
self.xhr.sendAsBinary(body);
} else {
// chrome (W3C spec.)
self.xhr.send(body);
}

> метод send() объекта XMLHttpRequest может принимать в параметре бинарные данные, что успешно и реализовано в Google Chrome
Попробовал на chrome 7 и trunk chromium 9 — они не смогли. Сейчас думаю о возможных решениях проблемы, первое, что пришло на ум — это реализация метода sendAsBinary с помощью FileWriter API. Это апи разработчики совсем недавно добавили в хромиум и firefox. Вот код:
if (XMLHttpRequest.prototype.sendAsBinary === undefined && Uint8Array) {
XMLHttpRequest.prototype.sendAsBinary = function(data) {
var blob = new BlobBuilder(),
arrb = new ArrayBuffer(data.length),
ui8a = new Uint8Array(arrb, 0);
for (var i=0; i<data.length; i++) {
ui8a[i] = (data.charCodeAt(i) & 0xff);
}
blob.append(arrb);
var blob = blob.getBlob();
this.send(blob);
}
}
+1 OlegTar16 декабря 2010 в 14:59#↵↑
А если взять reader.readAsDataURL,
отсечь от начала «data:image/png;base64,»
разбить оставшися текст на строки по 74 символов каждая (включая, \r\n),
Поставить хэдер Content-Transfer-Encoding: base64

и отправить?
0 Devgru26 декабря 2010 в 20:19#↵↑
А почему по 72 именно?
0 Devgru26 декабря 2010 в 20:23#↵↑
74*
0 OlegTar26 декабря 2010 в 22:16#↵↑
просто я отправил из почтовой программы Thunderbird себе письмо с вложенным файлом.
Потом я посмотрел исходный код письма.
Так вот, Thunderbird закодировал файл в строку base64 и после каждого 72 символа он ставил
\r\n (либо просто \n)
Из-за этого подумал, что 74 — это максимальная длина строки в письмах.
===
P.S. Но вот сейчас взял первое попавшееся письмо на gmail, выбрал «Показать оригинал».
Увидел, что там в строке base64 76 печатных символов.

В rfc искал чего-то ничего по этому поводу не нашёл.

+1 OlegTar16 декабря 2010 в 20:14#
Хорошая статья, спасибо.
Но у способа есть минус: большие файлы загружаются в память, браузер висит и отжирает много памяти.
0 safron16 декабря 2010 в 20:38#↵↑
Как справедливо отметил выше товарищ Demetros, для этой задачи лучше использовать объект FormData, который будет реализован в файрфоксе (см. описание на сайте MDC), начиная с версии 4 (в хроме уже есть, про остальные не в курсе). Очень вероятно, что браузер тогда будет кушать гораздо меньше памяти, ибо возьмет на себя всю черновую работу по чтению файлов.

Пока же можно ограничивать кол-во одновременных загрузок и максимальный размер одного файла.
0 OlegTar16 декабря 2010 в 21:00#↵↑
вот метод FormData:
void append(DOMString name, Blob value);

и чего? value что должно содержать? не тело ли файла? раз у неё тип blob

+1 safron16 декабря 2010 в 21:11#↵↑
Вы зря ссылку внимательно не посмотрели, там есть строка:
formData.append("afile", fileInputElement.files[0]);

Как видите, метод append достаточно умен, чтоб принимать и blob-данные и просто объект File. Я верю, что разработчики оптимизируют процесс чтения и загрузки дял второго случая.
+1 OlegTar17 декабря 2010 в 00:01#↵↑
а да, спасибо.

Я просто заходил на http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
там этого нету.
0 safron25 февраля 2011 в 04:29#↵↑
Теперь там, где это возможно (Safari, Chrome, FF 4+) используется FormData, что позволяет избежать загрузки файлов в память (само собой, если есть цель сэкономить память, не стоит их открывать файлы, чтоб делать превьюшки).
Если интересно, см. апдейт статьи.
0 OlegTar25 февраля 2011 в 16:35#↵↑
Спасибо!
0 Pavel_Osipov18 апреля 2011 в 15:05#
За статью больше спасибо
Для MooTools тоже есть очень похожий плагин mootools.net/forge/p/uploadmanager
0 phgrey16 июля 2011 в 17:02#
За статью спасибо.
Приведенный плагин нужно чуть-чуть допилить — FF 3.6 не поддеоживает FileReader, но поддерживает File.getAsBinary()

} else if($.support.fileReading && xhr.sendAsBinary) {

заменить на

0 phgrey16 июля 2011 в 17:03#↵↑
} else if(($.support.fileReading || item.file.getAsBinary) && xhr.sendAsBinary) { (извините, нечаянно нажал отправить)
+1 phgrey16 июля 2011 в 17:10#↵↑
Опять соврал — тестировал под FF 3.5. Также еще одно замечание по поводу имени файла — вместо строки
var filename = item.replaceName || item.file.name;

нужно
var filename = item.replaceName || item.file.name || item.file.fileName;

0 corpix22 ноября 2011 в 09:49#
xhr.setRequestHeader(«Content-Type», «multipart/form-data, boundary=»+boundary);
Запятую нужно заменить на ";"
self.xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary='+boundary);

У меня node.js(formidable) не захотела обрабатывать такую форму.
Да и ещё… если есть возможность получить правельный mime-type для файла, то почему бы его не выставить?
body += 'Content-Type: ' + params.file.type + '\r\n\r\n';
0 Kichee18 августа 2012 в 23:19#
Спасибо за статью, ваши наработки оказались очень полезными.
0 unclechu19 декабря 2013 в 13:49#
На данный момент могу сказать что всё работает отлично в Mozilla Firefox 26, Chromium 27. В Opera 12.16 при Drag&Drop при перетаскивании нескольких файлов — залетает только 1, через мультивыбор из поля input:file — нормально, как и должно. А для всяких недобраузеров (кроме Opera), — просто делаются по старинке несколько input:file полей с возможностью добавить ещё, пользователи IE сами выбрали страдания, пусть наслаждаются.
0 safron19 декабря 2013 в 22:37#↵↑
Ну я для недобраузеров делаю еще проще: просто одно поле input:file оставляю :)

Еще стоит отметить, что все работает отлично также в ИЕ 10+
http://safron.su/playground/html5uploader/
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#18 dyvniy » Чт, 15 октября 2015, 13:27:52

Загрузка файлов на сервер
http://habrahabr.ru/post/109079/
Спойлер
HTML5 File API: множественная загрузка файлов на сервер из песочницы
Веб-разработка*, jQuery*
Когда передо мной в очередной раз встала задача об одновременной загрузке нескольких файлов на сервер (без перезагрузки страницы, само собой), я стал блуждать по интернетам в поисках довольно корявого jQuery-плагина, который позволяет имитировать ajax-загрузку файла (того самого плагина, который со скрытым фрэймом: от java- и flash- плагинов сразу было решено отказаться). В процессе поиска я вспомнил, что в грядущем стандарте html 5 возможности по работе с файлами должны быть существенно расширены, и часть этих возможностей доступна уже сейчас. В итоге было решено опробовать их в действии.

Рассматривать возможности File API будем на примере одновременной загрузки нескольких картинок на сервер. В конце статьи приводится готовое решение, оформленное в виде jQuery-плагина.


Не хочу это читать, интересует готовое решение.

Итак, какие же преимущества дает нам использование File API:
Независимость от внешних плагинов
Возможность контролировать процесс загрузки и отображать информацию о нем (прогрессбар всегда добавляет терпения пользователю)
Возможность прочитать файл и узнать его размер до начала загрузки (в нашем примере это дает нам возможность отсеять файлы, не содержащие изображений и показывать миниатюры картинок)
Возможность выбрать сразу несколько файлов через стандартное поле выбора файла
Возможность использовать интерфейс drag and drop для выбора файлов. Да-да, мы сможем перетаскивать файлы для загрузки прямо с рабочего стола или, например, из проводника!

Из недостатков можно отметить только недостаточную поддержку в браузерах. Сейчас File API поддерживают только Firefox ≥ 3.6 и Chrome ≥ 6.0. Есть такое ощущение, что и Safari уже совсем скоро подтянется, а вот про IE и Opera пока ничего не ясно (может быть, кто-то располагает сведениями?). Расстроило конечно, что File API не поддерживает IE9 Beta: это странно, учитывая что разработчики IE сейчас взяли курс на обильную поддержку html 5. Но как бы то ни было, очевидно, что в будущем всем браузерам придется подтянуться.

Работающий пример можно увидеть по адресу http://safron.su/playground/html5uploader/, ниже приведены только наиболее важные фрагменты кода.

Для начала разберемся с html-кодом. Нам понадобится дефолтный элемент input, контейнер для перетаскивания файлов и список ul, куда мы будем помещать миниатюрки изображений:
<div>
<input type="file" name="file" id="file-field" multiple="true" />
</div>
<div id="img-container">
<ul id="img-list"></ul>
</div>


Ничего особенного, кроме того, что для элемента input указан атрибут multiple="true". Это необходимо для того, чтобы в стандартном диалоге выбора файлов можно было выделять их сразу несколько. Кстати, начиная с Firefox 4, разработчики браузера обещают, что ненавистные многим верстальщикам стандартные поля выбора файла можно будет скрывать, а диалог показывать, вызвав событие click для скрытого элемента.

Теперь перейдем к JavaScript (обратите внимание, что я использовал jQuery для упрощения манипуляций с DOM. Тот, кто по каким-либо причинам захочет отказаться от jQuery, сможет без труда переделать скрипты таким образом, чтобы обойтись без него). Сначала сохраним в переменных ссылки на html-элементы, снявшиеся в главных ролях. Далее определим обработчики событий для стандартного поля выбора файлов и для области, куда можно будет перетаскивать файлы.
// Стандарный input для файлов
var fileInput = $('#file-field');

// ul-список, содержащий миниатюрки выбранных файлов
var imgList = $('ul#img-list');

// Контейнер, куда можно помещать файлы методом drag and drop
var dropBox = $('#img-container');

// Обработка события выбора файлов в стандартном поле
fileInput.bind({
change: function() {
displayFiles(this.files);
}
});

// Обработка событий drag and drop при перетаскивании файлов на элемент dropBox
dropBox.bind({
dragenter: function() {
$(this).addClass('highlighted');
return false;
},
dragover: function() {
return false;
},
dragleave: function() {
$(this).removeClass('highlighted');
return false;
},
drop: function(e) {
var dt = e.originalEvent.dataTransfer;
displayFiles(dt.files);
return false;
}
});


И в том и в другом случае в обработчике мы получаем доступ к объекту FileList, который по сути представляет собой массив объектов File. Этот массив передается функции displayFiles(), текст которой приведен ниже.
function displayFiles(files) {
$.each(files, function(i, file) {
if (!file.type.match(/image.*/)) {
// Отсеиваем не картинки
return true;
}
// Создаем элемент li и помещаем в него название, миниатюру и progress bar,
// а также создаем ему свойство file, куда помещаем объект File (при загрузке понадобится)
var li = $('<li/>').appendTo(imgList);
$('<div/>').text(file.name).appendTo(li);
var img = $('<img/>').appendTo(li);
$('<div/>').addClass('progress').text('0%').appendTo(li);
li.get(0).file = file;

// Создаем объект FileReader и по завершении чтения файла, отображаем миниатюру и обновляем
// инфу обо всех файлах
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.attr('src', e.target.result);
aImg.attr('width', 150);
/* ... обновляем инфу о выбранных файлах ... */
};
})(img);

reader.readAsDataURL(file);
});
}


Объект File содержит метаданные о файле, такие как его имя, размер и тип (в формате MIME, например, image/gif) соответственно в свойствах name, size и type. Для доступа же к содержимому файла существует специальный объект FileReader.

Внутри функции displayFiles() мы проходимся по переданному массиву файлов и сначала отсеиваем те, которые не являются изображениями. Далее для каждого изображения создается элемент списка li, куда помещается пустой пока элемент img (обратите внимание, что в кажом элементе li также создается свойство file, содержащее соответствующий объект). После чего создается экземпляр FileReader и для него определяется обработчик onload, в котором данные передаются прямо в атрибут src созданного ранее элемента img. Метод readAsDataURL() объекта FileReader принимает параметром объект File и запускает чтение данных из него. В результате для всех выбранных через стандартное поле или перетащенных прямо в браузер картинок, мы видим их миниатюры (искусственно уменьшенные до 150 пикселей).

Что еще осталось сделать? Осталось только реализовать саму загрузку всех выбранных файлов на сервер. Для этого создадим какую-нибудь кнопку или ссылку, при нажатии на которую останется только пробежаться по всем созданным элементам li, прочитать их свойство file и передать в функцию uploadFile(), текст которой приведен ниже. Отмечу, что здесь для упрощения я реализовал загрузку через функцию, а в реальном примере, расположенном по адресу http://safron.su/playground/html5uploader/, я собрал все действия по загрузке в объект uploaderObject, при создании которого можно передать дополнительные параметры, такие как функции обратного вызова для получения информации о процессе загрузки.
function uploadFile(file, url) {

var reader = new FileReader();

reader.onload = function() {
var xhr = new XMLHttpRequest();

xhr.upload.addEventListener("progress", function(e) {
if (e.lengthComputable) {
var progress = (e.loaded * 100) / e.total;
/* ... обновляем инфу о процессе загрузки ... */
}
}, false);

/* ... можно обрабатывать еще события load и error объекта xhr.upload ... */

xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if(this.status == 200) {
/* ... все ок! смотрим в this.responseText ... */
} else {
/* ... ошибка! ... */
}
}
};

xhr.open("POST", url);
var boundary = "xxxxxxxxx";
// Устанавливаем заголовки
xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Cache-Control", "no-cache");
// Формируем тело запроса
var body = "--" + boundary + "\r\n";
body += "Content-Disposition: form-data; name='myFile'; filename='" + file.name + "'\r\n";
body += "Content-Type: application/octet-stream\r\n\r\n";
body += reader.result + "\r\n";
body += "--" + boundary + "--";

if(xhr.sendAsBinary) {
// только для firefox
xhr.sendAsBinary(body);
} else {
// chrome (так гласит спецификация W3C)
xhr.send(body);
}
};
// Читаем файл
reader.readAsBinaryString(file);
}


Здесь создается экземпляр уже знакомого нам объекта FileReader, точно так же, как и выше; ему присваивается обработчик события onload, в котором создается XMLHttpRequest (к сожалению, пока нельзя воспользоваться ajax-интерфейсом jQuery, поскольку там еще не предусмотрена загрузка файлов). В XMLHttpRequest второй версии появилось свойство upload, содержащее объект-загрузчик, который может обрабатывать события progress, load и error (подробнее см. http://www.w3.org/TR/XMLHttpRequest2/#xmlhttprequesteventtarget). В примере выше показана только обработка события progress. Далее присваиваем обработчик завершения запроса самому реквесту (в отличие от событий объекта-загрузчика он вызывается уже тогда, когда все данные загружены и ответ от сервера получен), добавляем два дополнительных заголовка и формируем тело запроса, читая данные из свойства result объекта FileReader. После этого загрузка запускается. Отмечу только, что по нынешней спецификации W3C подразумевается, что метод send() объекта XMLHttpRequest может принимать в параметре бинарные данные, что успешно и реализовано в Google Chrome, однако в Firefox сделано по-своему, через особый метод sendAsBinary(). Поэтому перед началом отправки проверяем, определен ли метод sendAsBinary() в объекте реквеста, и, если да, используем его.

Вот, собственно, и все. С нетерпением ждем утверждения и распространения html 5!

Кое-какие ссылки

http://safron.su/playground/html5uploader/ — работающий пример того, что описывалось выше (плюс еще кое-что)
http://safron.su/playground/html5uploader/full.zip — весь код целиком в архиве
http://html5test.com — проверка браузеров на соответсвие html 5 (очень наглядно)
http://playground.html5rocks.com — площадка для экпериментов с кодом от Google (ее интерфейс будет знаком тем, кто использовал многочисленные API Google)


UPD
Для упрощения использования всего вышеизложенного, был создан JQuery-плагин. При помощи него можно загружать файлы через File API там, где это возможно, и реализовать замену (например, обычную отправку формы) там, где нет. По просьбам трудящихся и соотносясь с замечаниями комментаторов, была добавлена загрузка через объект FormData в браузерах, которые его поддерживают (Chrome, Safari 5+, FF 4+). В самом верху файла с плагином есть описание параметров, методов, а также краткие примеры использования. Более полный пример использования можно увидеть здесь (это изначальный пример из этой статьи, только переделанный на использование плагина, его полный код, включая серверную часть, можно скачать здесь [see UPD2]).

Использованные источники

https://developer.mozilla.org/en/using_files_from_web_applications — статья о файловом интерфейсе на сайте девелоперов Mozilla
https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest — cтатья об использовании XMLHttpRequest там же
http://www.w3.org/TR/FileAPI/ — текущая спецификация File API на сайте W3C
http://www.w3.org/TR/XMLHttpRequest2/ — текущая спецификация XMLHttpRequest там же



UPD2
По просьбе пользователя glebovgin плагин был доработан таким образом, чтобы можно было отправлять не только непосредственно объект File, но также Blob-данные (объект Blob). Это может быть полезно, если есть необходимость отправлять на сервер, например, содержимое canvas, ну или просто вручную сгенерированные данные.

В демке (которая переехала немного на другой адрес) был добавлен пример отправки картинки из canvas. На данный момент эта возможность работает в FF, Chrome, IE10.

Исходный код ныне доступен на GitHub. Замечания, предложения, улучшения приветствуются!
html, html5, file upload, file api, jquery, jquery plugin
+97

50680

437


Саша Сафронов @safron карма54,0 рейтинг0,0
Похожие публикации

Мой последний file uploader (26)
PickMeUp — хороший jQuery datepicker plugin (49)
Спасибо за HTML5 File API или читаем ID3-тег и заполняем форму не загружая MP3-файл (12)
jQuery File Upload (118)
Drag'n'drop файлов во Flex, используя HTML5 File API (4)
Комментарии (57)

+1 dapmoed30 ноября 2010 в 17:32#
Очень вовремя! Вот только собирался использовать мультиаплоад в своем проекте и вот замечательная статья.
Довольно четко и очень понятно объяснено.
Огромное спасибо.
+1 safron30 ноября 2010 в 17:35#↵↑
на здоровие ;)
0 Sannis 1 декабря 2010 в 09:31#↵↑
Как вы собираетесь реализовать поддержку старых браузеров?
0 TheShock16 декабря 2010 в 20:19#↵↑
забить?)
+1 lutz30 ноября 2010 в 17:39#
Изящное решение на html5 + вечный грубый костыль со скрытым вреймом для IE6-8…
0 proc30 ноября 2010 в 17:40#
Эх, жаль что это можно будет использовать только года через 3-4 когда умрут все браузеры которые не понимают html5
+2 safron30 ноября 2010 в 17:48#↵↑
Не скажите, смотря для каких целей. Например, в данном случае я делал интерфейс для одной почтенной женщины-фотографа, она использует (а если бы и не использовала, то можно было бы убедить) файрфокс и ее все устраивает.

Или вот пример с gmail — они же отказались от поддержки IE6, хотя его до сих пор используют 15 (или даже 20) % пользователей, которые получают предупреждение, что их браузер устарел.

Тут два варианта: делать костыли для более старых браузеров и честно говорить пользователям, что надо обновить браузер.

Но это я так. Согласен, чтоэту технологию пока рано запускать в массы. Как минимум надо дождаться, когда все последние версии браузеров будут ее поддерживать.
+2 dapmoed30 ноября 2010 в 17:51#↵↑
Зря Вы так. Для массового пользователя — да, а вот для своего удобства — уже сейчас.
0 script8830 ноября 2010 в 17:54#↵↑
Мало по малому, но уже можно начинать внедрять
+1 TiKo30 ноября 2010 в 17:40#
К сожалению в реальных проектах придется использовать еще и альтернативный вариант загрузки, пока такой функционал не будут поддерживать основные броузеры :(
+17 lutz30 ноября 2010 в 17:41#
Дедушка Мороз, я хорошо себя вел в этом году, пожалуйста, сделай так чтобы IE не стало…
0 lesa8030 ноября 2010 в 17:44#
грустно когда ездить можно на приличных авто… а клиент хочет (тоже конечно не по своей воле) ваз тюнинговать… ((
+1 barmaley_exe30 ноября 2010 в 18:00#
Расстроило конечно, что File API не поддерживает IE9 Beta: это странно, учитывая что разработчики IE сейчас взяли курс на обильную поддержку html 5. Но как бы то ни было, очевидно, что в будущем всем браузерам придется подтянуться.
Ничего странного, все просто. File API — черновик, его еще будут дописывать и переписывать. Если бы в IE9 внедрили FileAPI в текущем виде, то ничего хорошего не вышло бы. А мозиловцы вообще любят всякую экспериментальщину внедрять. Отсюда и остался в FF 3.6 метод sendAsBinary. В 4-ке уже должен быть FormData, который и описывается в последней версии черновика.
0 safron30 ноября 2010 в 18:15#↵↑
Согласен, весь HTML5 пока черновик, но ничего плохого в том, если бы ИЕ поддерживал уже тоже не было бы. Вообще, остальные браузеры регулярно обновляют младшие версии (может, подверсии? как правильно?), добавляя новые возможности. А уж если в ИЕ какой-то возможности нет, то еще год-другой надо ждать, пока выйдет следующий.
0 barmaley_exe30 ноября 2010 в 18:26#↵↑
Вот в этом-то и проблема. Если Хром, FF, Опера обновляются достаточно часто, то IE — крайне редко. Поэтому внедрять что-то экспериментальное в IE опасно, т.к. может так случиться, что через неделю после релиза черновик перепишут, выпустят новые версии браузеров и… IE останется не у дел, со старыми реализациями (и снова хаки для IE). Разработчики оперы тоже не любят экспериментальные фичи. Вспомнить хотя бы border-radius (и многие другие css3 свойства), реализовывать которые Opera Software не спешили.

А вообще, реализовывать такой функционал следует только при уверенности, что Вы сможете среагировать на изменение стандарта. Если Вы работаете над сайтом, который Вы точно будете поддерживать через полгода-год, то не страшно. А если Вы работаете над заказом, то лучше на это не рассчитывать. Иначе вместе с очередным обновлением браузеров может умереть весь новый функционал, а исполнителя и след простыл.
+1 safron30 ноября 2010 в 18:29#↵↑
Ну ок, убедили — хорошо, что ИЕ пока не поддерживает :)
+1 script8830 ноября 2010 в 19:44#↵↑
По моему IE как был не удел так и будет.
0 develop7 1 декабря 2010 в 11:38#↵↑
Если Хром, FF, Опера обновляются достаточно часто, то IE — крайне редко
а так нечестно, да
+1 Demetros30 ноября 2010 в 18:05#
Для загрузки картинок (небольших файлов) ваш код условно подходит.
По-нормальному, надо без извращений с ручным формированием тела запроса использовать FormData
0 safron30 ноября 2010 в 18:10#↵↑
правильно, но к сож. файрфокс пока не поддерживает. Выйдет официальо 4й — переделаем!
0 safron25 февраля 2011 в 04:23#↵↑
Переписал код так, чтоб где это возможно использовался FormData. Если интересно, см. апдейт внизу статьи.
0 Santacruz30 ноября 2010 в 19:25#
вовремя… надо бы jquery plugin заделать
0 safron30 ноября 2010 в 19:42#↵↑
сделаете? покажете?
–1 Santacruz30 ноября 2010 в 20:09#↵↑
искал добровольцев :)
0 safron25 февраля 2011 в 04:24#↵↑
Сделано! Если интересно, см. апдейт к статье.
0 Zerstoren30 ноября 2010 в 19:29#
Спасибо! Применю на своем проекте, как раз не будет лишним)

+1 Zerstoren30 ноября 2010 в 19:30#↵↑
и да здравствует HTML5 в W3C
www.w3.org/TR/FileAPI/ — текущая спецификация File API на сайте W3C

0 ymik30 ноября 2010 в 20:06#
Для скрытия инпута можно просто сделать ему visibility:hidden и растянуть поверх графического элемента
0 TEHEK30 ноября 2010 в 22:01#
М… меня опередили *сворачивает черновик* =)
0 b0n3Z30 ноября 2010 в 22:26#
Последний год использовал www.plupload.com/.
Опенсурс библиотека для загрузки файлов. Поставил на сайт — если у пользователя оказывался не хтмл5-браузер, автоматически библиотека переключала на другой способ загрузки.
Апи очень простое, рекомендую.
0 safron30 ноября 2010 в 22:43#↵↑
Спасибо за линк! Это громоздкое, но зато комплексное решение по загрузке файлов. И, насколько я понял, оно уже использует html 5 там, где это возможно
0 b0n3Z30 ноября 2010 в 22:46#↵↑
Да, так и есть. Более того, через апи самому можно выставлять приоритет способов загрузки. Я ранее ставил так: gears -> html5 -> flash -> silverlight -> html4.
0 safron30 ноября 2010 в 22:47#↵↑
ок, спс за инфо. Я гуглил готовые решения перед тем как сделать свой вариант, но на это не натыкался.
0 bolk30 ноября 2010 в 23:08#
Ссылка по теме: bolknote.ru/2009/11/30/~2322
0 mihaild 1 декабря 2010 в 02:22#
На правах рекламы:
code.google.com/p/jquery-html5-upload/
+2 webwin 1 декабря 2010 в 11:24#
Спасибо
вместо $('ul#img-list') используйте $('#img-list'). Во втором случае получим элемент намного быстрей, так как будет использоваться родной document.getElementById
0 safron 1 декабря 2010 в 15:15#↵↑
спасибо за инфо. Это, знаете ли, просто привычка, чтоб в коде видеть, какой именно элемент имеет такой айди (надо в комментариях писать — никак не могу переучиться). Потом везде убрал, а тут забыл.
0 b0n3Z 1 декабря 2010 в 23:31#
Сегодня весь вечер внедрял загрузку по этому посту и нашел очень неприятную штуковину.
В частности, этот код:
if (self.xhr.sendAsBinary) {
// firefox
self.xhr.sendAsBinary(body);
} else {
// chrome (W3C spec.)
self.xhr.send(body);
}

> метод send() объекта XMLHttpRequest может принимать в параметре бинарные данные, что успешно и реализовано в Google Chrome
Попробовал на chrome 7 и trunk chromium 9 — они не смогли. Сейчас думаю о возможных решениях проблемы, первое, что пришло на ум — это реализация метода sendAsBinary с помощью FileWriter API. Это апи разработчики совсем недавно добавили в хромиум и firefox. Вот код:
if (XMLHttpRequest.prototype.sendAsBinary === undefined && Uint8Array) {
XMLHttpRequest.prototype.sendAsBinary = function(data) {
var blob = new BlobBuilder(),
arrb = new ArrayBuffer(data.length),
ui8a = new Uint8Array(arrb, 0);
for (var i=0; i<data.length; i++) {
ui8a[i] = (data.charCodeAt(i) & 0xff);
}
blob.append(arrb);
var blob = blob.getBlob();
this.send(blob);
}
}
+1 OlegTar16 декабря 2010 в 14:59#↵↑
А если взять reader.readAsDataURL,
отсечь от начала «data:image/png;base64,»
разбить оставшися текст на строки по 74 символов каждая (включая, \r\n),
Поставить хэдер Content-Transfer-Encoding: base64

и отправить?
0 Devgru26 декабря 2010 в 20:19#↵↑
А почему по 72 именно?
0 Devgru26 декабря 2010 в 20:23#↵↑
74*
0 OlegTar26 декабря 2010 в 22:16#↵↑
просто я отправил из почтовой программы Thunderbird себе письмо с вложенным файлом.
Потом я посмотрел исходный код письма.
Так вот, Thunderbird закодировал файл в строку base64 и после каждого 72 символа он ставил
\r\n (либо просто \n)
Из-за этого подумал, что 74 — это максимальная длина строки в письмах.
===
P.S. Но вот сейчас взял первое попавшееся письмо на gmail, выбрал «Показать оригинал».
Увидел, что там в строке base64 76 печатных символов.

В rfc искал чего-то ничего по этому поводу не нашёл.

+1 OlegTar16 декабря 2010 в 20:14#
Хорошая статья, спасибо.
Но у способа есть минус: большие файлы загружаются в память, браузер висит и отжирает много памяти.
0 safron16 декабря 2010 в 20:38#↵↑
Как справедливо отметил выше товарищ Demetros, для этой задачи лучше использовать объект FormData, который будет реализован в файрфоксе (см. описание на сайте MDC), начиная с версии 4 (в хроме уже есть, про остальные не в курсе). Очень вероятно, что браузер тогда будет кушать гораздо меньше памяти, ибо возьмет на себя всю черновую работу по чтению файлов.

Пока же можно ограничивать кол-во одновременных загрузок и максимальный размер одного файла.
0 OlegTar16 декабря 2010 в 21:00#↵↑
вот метод FormData:
void append(DOMString name, Blob value);

и чего? value что должно содержать? не тело ли файла? раз у неё тип blob

+1 safron16 декабря 2010 в 21:11#↵↑
Вы зря ссылку внимательно не посмотрели, там есть строка:
formData.append("afile", fileInputElement.files[0]);

Как видите, метод append достаточно умен, чтоб принимать и blob-данные и просто объект File. Я верю, что разработчики оптимизируют процесс чтения и загрузки дял второго случая.
+1 OlegTar17 декабря 2010 в 00:01#↵↑
а да, спасибо.

Я просто заходил на http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
там этого нету.
0 safron25 февраля 2011 в 04:29#↵↑
Теперь там, где это возможно (Safari, Chrome, FF 4+) используется FormData, что позволяет избежать загрузки файлов в память (само собой, если есть цель сэкономить память, не стоит их открывать файлы, чтоб делать превьюшки).
Если интересно, см. апдейт статьи.
0 OlegTar25 февраля 2011 в 16:35#↵↑
Спасибо!
0 Pavel_Osipov18 апреля 2011 в 15:05#
За статью больше спасибо
Для MooTools тоже есть очень похожий плагин mootools.net/forge/p/uploadmanager
0 phgrey16 июля 2011 в 17:02#
За статью спасибо.
Приведенный плагин нужно чуть-чуть допилить — FF 3.6 не поддеоживает FileReader, но поддерживает File.getAsBinary()

} else if($.support.fileReading && xhr.sendAsBinary) {

заменить на

0 phgrey16 июля 2011 в 17:03#↵↑
} else if(($.support.fileReading || item.file.getAsBinary) && xhr.sendAsBinary) { (извините, нечаянно нажал отправить)
+1 phgrey16 июля 2011 в 17:10#↵↑
Опять соврал — тестировал под FF 3.5. Также еще одно замечание по поводу имени файла — вместо строки
var filename = item.replaceName || item.file.name;

нужно
var filename = item.replaceName || item.file.name || item.file.fileName;

0 corpix22 ноября 2011 в 09:49#
xhr.setRequestHeader(«Content-Type», «multipart/form-data, boundary=»+boundary);
Запятую нужно заменить на ";"
self.xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary='+boundary);

У меня node.js(formidable) не захотела обрабатывать такую форму.
Да и ещё… если есть возможность получить правельный mime-type для файла, то почему бы его не выставить?
body += 'Content-Type: ' + params.file.type + '\r\n\r\n';
0 Kichee18 августа 2012 в 23:19#
Спасибо за статью, ваши наработки оказались очень полезными.
0 unclechu19 декабря 2013 в 13:49#
На данный момент могу сказать что всё работает отлично в Mozilla Firefox 26, Chromium 27. В Opera 12.16 при Drag&Drop при перетаскивании нескольких файлов — залетает только 1, через мультивыбор из поля input:file — нормально, как и должно. А для всяких недобраузеров (кроме Opera), — просто делаются по старинке несколько input:file полей с возможностью добавить ещё, пользователи IE сами выбрали страдания, пусть наслаждаются.
0 safron19 декабря 2013 в 22:37#↵↑
Ну я для недобраузеров делаю еще проще: просто одно поле input:file оставляю :)

Еще стоит отметить, что все работает отлично также в ИЕ 10+
http://safron.su/playground/html5uploader/
Изображение


Название раздела: Web на стороне клиента, Java Script
Описание: Наиболее перспективное направление развития компьютерных наук. Надо быть в теме!

Быстрый ответ


Введите код в точности так, как вы его видите. Регистр символов не имеет значения.
Код подтверждения
:) ;) :hihi: :P :hah: :haha: :angel: :( :st: :_( :cool: 8-| :beee: :ham: :rrr: :grr: :* :secret: :stupid: :music: Ещё смайлики…
   

Вернуться в «Web на стороне клиента, Java Script»

Кто сейчас на форуме (по активности за 15 минут)

Сейчас этот раздел просматривают: 6 гостей