Так получилось, что я на своих сайтах использую плагин uploadify для jQuery — uploadify.com (хоть он уже устарел, флеш и все такое, но HTML5-версия у них уже платная). Плагин предоставляет мультизагрузку файлов, не перегружая страницу, что нам всем и надо. Однако оказалось, что в этом плагине не работает (и/или работает не так, как надо) функция проверки существования файлов перед отправкой на сервер.
Смотрим на нужный нам кусок кода. И видим там сразу четыре «бага». Ну, сразу не видим, да, давайте по порядку.
Проблема первая. Нужная опция называется не так, как она упомянута во всех туториалах в сети — checkExisiting, а не checkScript. Но это ладно, тут сам виноват — лучше читать родную документацию, а еще лучше код (в документации тоже напутано — в платной HTML5-версии плагина именно checkScript).
Проблема вторая. Мне нужна очень простая функция — если файл в нужном мне альбоме на сайте есть, то повторно его закачивать не надо, его надо просто молча пропустить и перейти к следующему, это сильно сэкономит трафик, а мне не надо помнить, какие файлы уже закачались, а какие нет — кормим uploadify 200 файлов, и он быстро докачает только те, которых нет. Но оказалось, что авторы сделали все не так, как мне надо.
Написал скрипт, запускаю — ой. На каждый существующий файл он выдает окошко с просьбой подтвердить загрузку этого файла. И так 200 раз.
Не пойдет.
(В settings.checkExisting хранится путь к моему скрипту, который должен вернуть 1, если такой файл уже существует и 0, если нет.)
В качестве обходного решения можно закомментировать var overwrite = confirm(..., а вместо этого просто написать var overwrite = false;
Я так сначала и сделал. Но потом решил, что это некрасиво и не гибко, так что чуть-чуть переписал эту фичу — в объект settings добавил новое свойство-опцию skipExisting, и поставил ее по умолчанию в true, что значит молча пропускать существующие файлы. Ну и в коде:
Проблема третья. Плагин во время закачивания файла передает не только его имя, но и произвольный набор данных в объекте formData. А вот при проверке существования файла почему-то ничего кроме его имени не передает. А мне ведь нужны те же formData, что и при закачке. Мне как минимум нужно знать номер альбома, в котором проверять файл. В разных альбомах могут встречаться повторяющиеся имена файлов. Не пойдет. Фиксим.
Меняем так, чтобы передавался в .ajax в качестве data не {filename: file.name},
А просто объект formData (из объекта settings):
Только теперь file.name надо в него добавить, иначе потеряется. Добавляем его перед вызовом метода .ajax:
ОК. Запускаю, все работает. Ан, нет! Не работает! Первый файл пытается пропустить, а потом:
Оба-на, а вот и баг.
Проблема четвертая. Авторы почему-то забыли про контекст. И метод .cancelUpload на this не срабатывает. Ну конечно, this-то не тот.
Вариантов фикса аж целых четыре — this можно запроксить, можно забиндить, можно просто закэшировать в переменной перед вызовом .ajax, но мы поступим еще проще, в методе jQuery.ajax есть опция context:
Всё! Теперь плагин работает как надо.
Итак, новый код с изменениями:
Ну и не забыть в опциях:
Можете скачать исправленную версию у меня, но я ее не минифицировал, пардон. Это только js-файл, вам все равно сперва надо будет скачать полный архив на uploadify.com
Смотрим на нужный нам кусок кода. И видим там сразу четыре «бага». Ну, сразу не видим, да, давайте по порядку.
if (settings.checkExisting) {
$.ajax({
type : 'POST',
async : false,
url : settings.checkExisting,
data : {filename: file.name},
success : function(data) {
if (data == 1) {
var overwrite = confirm('A file with the name "' + file.name + '" already exists on the server.\nWould you like to replace the existing file?');
if (!overwrite) {
this.cancelUpload(file.id);
$('#' + file.id).remove();
if (this.queueData.uploadQueue.length > 0 && this.queueData.queueLength > 0) {
if (this.queueData.uploadQueue[0] == '*') {
this.startUpload();
} else {
this.startUpload(this.queueData.uploadQueue.shift());
}
}
}
}
}
});
}
Проблема первая. Нужная опция называется не так, как она упомянута во всех туториалах в сети — checkExisiting, а не checkScript. Но это ладно, тут сам виноват — лучше читать родную документацию, а еще лучше код (в документации тоже напутано — в платной HTML5-версии плагина именно checkScript).
Проблема вторая. Мне нужна очень простая функция — если файл в нужном мне альбоме на сайте есть, то повторно его закачивать не надо, его надо просто молча пропустить и перейти к следующему, это сильно сэкономит трафик, а мне не надо помнить, какие файлы уже закачались, а какие нет — кормим uploadify 200 файлов, и он быстро докачает только те, которых нет. Но оказалось, что авторы сделали все не так, как мне надо.
Написал скрипт, запускаю — ой. На каждый существующий файл он выдает окошко с просьбой подтвердить загрузку этого файла. И так 200 раз.
Не пойдет.
(В settings.checkExisting хранится путь к моему скрипту, который должен вернуть 1, если такой файл уже существует и 0, если нет.)
В качестве обходного решения можно закомментировать var overwrite = confirm(..., а вместо этого просто написать var overwrite = false;
Я так сначала и сделал. Но потом решил, что это некрасиво и не гибко, так что чуть-чуть переписал эту фичу — в объект settings добавил новое свойство-опцию skipExisting, и поставил ее по умолчанию в true, что значит молча пропускать существующие файлы. Ну и в коде:
var overwrite = (this.settings.skipExisting) ? false : confirm('A file with the name "' + file.name + '" already exists on the server.\nWould you like to replace the existing file?');
Проблема третья. Плагин во время закачивания файла передает не только его имя, но и произвольный набор данных в объекте formData. А вот при проверке существования файла почему-то ничего кроме его имени не передает. А мне ведь нужны те же formData, что и при закачке. Мне как минимум нужно знать номер альбома, в котором проверять файл. В разных альбомах могут встречаться повторяющиеся имена файлов. Не пойдет. Фиксим.
Меняем так, чтобы передавался в .ajax в качестве data не {filename: file.name},
data : {filename: file.name},
А просто объект formData (из объекта settings):
data : settings.formData,
Только теперь file.name надо в него добавить, иначе потеряется. Добавляем его перед вызовом метода .ajax:
settings.formData.filename = file.name;
ОК. Запускаю, все работает. Ан, нет! Не работает! Первый файл пытается пропустить, а потом:
Оба-на, а вот и баг.
Проблема четвертая. Авторы почему-то забыли про контекст. И метод .cancelUpload на this не срабатывает. Ну конечно, this-то не тот.
Вариантов фикса аж целых четыре — this можно запроксить, можно забиндить, можно просто закэшировать в переменной перед вызовом .ajax, но мы поступим еще проще, в методе jQuery.ajax есть опция context:
$.ajax({
context : this,
type : 'POST',
// и т.д...
Всё! Теперь плагин работает как надо.
Итак, новый код с изменениями:
if (settings.checkExisting) {
settings.formData.filename = file.name;
$.ajax({
context : this,
type : 'POST',
async : false,
url : settings.checkExisting,
data : settings.formData,
success : function(data) {
if (data == 1) {
var overwrite = (settings.skipExisting) ? false : confirm('A file with the name "' + file.name + '" already exists on the server.\nWould you like to replace the existing file?');
if (!overwrite) {
this.cancelUpload(file.id);
$('#' + file.id).remove();
if (this.queueData.uploadQueue.length > 0 && this.queueData.queueLength > 0) {
if (this.queueData.uploadQueue[0] == '*') {
this.startUpload();
} else {
this.startUpload(this.queueData.uploadQueue.shift());
}
}
}
}
}
});
}
Ну и не забыть в опциях:
skipExisting : true, // Show prompt on exisiting files if false and just skip them if true
Можете скачать исправленную версию у меня, но я ее не минифицировал, пардон. Это только js-файл, вам все равно сперва надо будет скачать полный архив на uploadify.com
Поделиться с друзьями
Комментарии (7)
tomgif
08.02.2017 23:42Возьмите http://www.dropzonejs.com и будет вам счастье.
pnl
09.02.2017 09:57+1Так я не ищу замену, если будет новый проект с нуля, возьму другую библиотеку, а uploadify я фиксил для множества проектов, где она уже используется и никто переписывать не будет.
justboris
09.02.2017 12:29Очень слабое оправдание. Библиотеки они на то и библиотеки, что содержат стандартный задокументированный код.
Своими правками вы заложили бомбу для каждого, кто будет допиливать этот код в будущем. Легаси может быть и не таким страшным, достаточно соблюдать элементарные правила
justboris
Зачем пользоваться такой странной библиотекой, которую еще нужно допиливать напильником.
Есть же open-source, и без флеша: https://github.com/blueimp/jquery-file-upload
pnl
По историческим причинам, увы. Иногда legacy такое legacy.
kAIST
Но ведь flash… сейчас полно народа сидят в интернете со смартфонов и планшетов.
Да и вы же не все целиком переписываете, а просто меняете такую мелочь. ИМХО, проще взять другой плагин или написать самому — аплоад файлов не такая уж и сложная штука.
pnl
Ну и есть ряд проектов, к которым я уже не имею прямого отношения и переписывать их не буду, но я знаю, что там используется uploadify. Фикс в том числе и для них.