Так получилось, что я на своих сайтах использую плагин uploadify для jQuery — uploadify.com (хоть он уже устарел, флеш и все такое, но HTML5-версия у них уже платная). Плагин предоставляет мультизагрузку файлов, не перегружая страницу, что нам всем и надо. Однако оказалось, что в этом плагине не работает (и/или работает не так, как надо) функция проверки существования файлов перед отправкой на сервер.
Смотрим на нужный нам кусок кода. И видим там сразу четыре «бага». Ну, сразу не видим, да, давайте по порядку.
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
Можете скачать исправленную версию у меня, но я ее не минифицировал, пардон.
Автор: pnl