Фиксим дивна поведінка плагін jQuery uploadify (і один баг)

Так вийшло, що я на своїх сайтах використовую плагін 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;

ОК. Запускаю, все працює. Ан, ні! Не працює! Перший файл намагається пропустити, а потім:

image
Оба-на, а ось і баг.

Проблема четверта. Автори чомусь забули про контекст. І метод .cancelUpload на це не спрацьовує. Ну звичайно, 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

Можете завантажити виправлену версію у мене, але я її не минифицировал, пардон.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.