Так получилось, что я на своих сайтах использую плагин 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
