avatars_for_rails 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,89 +1,156 @@
1
1
  /*
2
- * jQuery File Upload Plugin 3.4
2
+ * jQuery File Upload Plugin 4.4.2
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2010, Sebastian Tschan
6
+ * https://blueimp.net
3
7
  *
4
- * Copyright 2010, Sebastian Tschan, AQUANTUM
5
8
  * Licensed under the MIT license:
6
9
  * http://creativecommons.org/licenses/MIT/
7
- *
8
- * https://blueimp.net
9
- * http://www.aquantum.de
10
10
  */
11
11
 
12
12
  /*jslint browser: true */
13
- /*global File, FileReader, FormData, unescape, jQuery */
13
+ /*global XMLHttpRequestUpload, File, FileReader, FormData, ProgressEvent, unescape, jQuery, upload */
14
14
 
15
15
  (function ($) {
16
+ 'use strict';
16
17
 
17
- var FileUpload,
18
- methods;
18
+ var defaultNamespace = 'file_upload',
19
+ undef = 'undefined',
20
+ func = 'function',
21
+ FileUpload,
22
+ methods,
23
+
24
+ MultiLoader = function (callBack, numOrList) {
25
+ var loaded = 0,
26
+ list = [];
27
+ if (numOrList) {
28
+ if (numOrList.length) {
29
+ list = numOrList;
30
+ } else {
31
+ list[numOrList - 1] = null;
32
+ }
33
+ }
34
+ this.complete = function () {
35
+ loaded += 1;
36
+ if (loaded === list.length) {
37
+ callBack(list);
38
+ loaded = 0;
39
+ list = [];
40
+ }
41
+ };
42
+ this.push = function (item) {
43
+ list.push(item);
44
+ };
45
+ this.getList = function () {
46
+ return list;
47
+ };
48
+ },
49
+
50
+ SequenceHandler = function () {
51
+ var sequence = [];
52
+ this.push = function (callBack) {
53
+ sequence.push(callBack);
54
+ if (sequence.length === 1) {
55
+ callBack();
56
+ }
57
+ };
58
+ this.next = function () {
59
+ sequence.shift();
60
+ if (sequence.length) {
61
+ sequence[0]();
62
+ }
63
+ };
64
+ };
19
65
 
20
66
  FileUpload = function (container) {
21
67
  var fileUpload = this,
22
- uploadForm = (container.is('form') ? container : container.find('form').first()),
23
- fileInput = uploadForm.find('input:file').first(),
68
+ uploadForm,
69
+ fileInput,
24
70
  settings = {
25
- namespace: 'file_upload',
26
- cssClass: 'file_upload',
71
+ namespace: defaultNamespace,
72
+ uploadFormFilter: function (index) {
73
+ return true;
74
+ },
75
+ fileInputFilter: function (index) {
76
+ return true;
77
+ },
78
+ cssClass: defaultNamespace,
27
79
  dragDropSupport: true,
28
80
  dropZone: container,
29
- url: uploadForm.attr('action'),
30
- method: uploadForm.attr('method'),
31
- fieldName: fileInput.attr('name'),
81
+ url: function (form) {
82
+ return form.attr('action');
83
+ },
84
+ method: function (form) {
85
+ return form.attr('method');
86
+ },
87
+ fieldName: function (input) {
88
+ return input.attr('name');
89
+ },
90
+ formData: function (form) {
91
+ return form.serializeArray();
92
+ },
93
+ requestHeaders: null,
32
94
  multipart: true,
33
95
  multiFileRequest: false,
34
- formData: function () {
35
- return uploadForm.serializeArray();
36
- },
37
96
  withCredentials: false,
38
- forceIframeUpload: false
97
+ forceIframeUpload: false,
98
+ sequentialUploads: false,
99
+ maxChunkSize: null,
100
+ maxFileReaderSize: 50000000
39
101
  },
40
102
  documentListeners = {},
41
103
  dropZoneListeners = {},
42
- fileInputListeners = {},
43
- undef = 'undefined',
44
- func = 'function',
45
- num = 'number',
46
104
  protocolRegExp = /^http(s)?:\/\//,
47
-
48
- MultiLoader = function (callBack, numberComplete) {
49
- var loaded = 0;
50
- this.complete = function () {
51
- loaded += 1;
52
- if (loaded === numberComplete) {
53
- callBack();
54
- }
55
- };
105
+ optionsReference,
106
+ multiLoader = new MultiLoader(function (list) {
107
+ if (typeof settings.onLoadAll === func) {
108
+ settings.onLoadAll(list);
109
+ }
110
+ }),
111
+ sequenceHandler = new SequenceHandler(),
112
+
113
+ completeNext = function () {
114
+ multiLoader.complete();
115
+ sequenceHandler.next();
56
116
  },
57
117
 
58
118
  isXHRUploadCapable = function () {
59
- return typeof XMLHttpRequest !== undef && typeof File !== undef && (
60
- !settings.multipart || typeof FormData !== undef || typeof FileReader !== undef
61
- );
119
+ return typeof XMLHttpRequest !== undef && typeof XMLHttpRequestUpload !== undef &&
120
+ typeof File !== undef && (!settings.multipart || typeof FormData !== undef ||
121
+ (typeof FileReader !== undef && typeof XMLHttpRequest.prototype.sendAsBinary === func));
62
122
  },
63
123
 
64
124
  initEventHandlers = function () {
65
125
  if (settings.dragDropSupport) {
66
126
  if (typeof settings.onDocumentDragEnter === func) {
67
- documentListeners['dragenter.' + settings.namespace] = settings.onDocumentDragEnter;
127
+ documentListeners['dragenter.' + settings.namespace] = function (e) {
128
+ settings.onDocumentDragEnter(e);
129
+ };
68
130
  }
69
131
  if (typeof settings.onDocumentDragLeave === func) {
70
- documentListeners['dragleave.' + settings.namespace] = settings.onDocumentDragLeave;
132
+ documentListeners['dragleave.' + settings.namespace] = function (e) {
133
+ settings.onDocumentDragLeave(e);
134
+ };
71
135
  }
72
136
  documentListeners['dragover.' + settings.namespace] = fileUpload.onDocumentDragOver;
73
137
  documentListeners['drop.' + settings.namespace] = fileUpload.onDocumentDrop;
74
138
  $(document).bind(documentListeners);
75
139
  if (typeof settings.onDragEnter === func) {
76
- dropZoneListeners['dragenter.' + settings.namespace] = settings.onDragEnter;
140
+ dropZoneListeners['dragenter.' + settings.namespace] = function (e) {
141
+ settings.onDragEnter(e);
142
+ };
77
143
  }
78
144
  if (typeof settings.onDragLeave === func) {
79
- dropZoneListeners['dragleave.' + settings.namespace] = settings.onDragLeave;
145
+ dropZoneListeners['dragleave.' + settings.namespace] = function (e) {
146
+ settings.onDragLeave(e);
147
+ };
80
148
  }
81
149
  dropZoneListeners['dragover.' + settings.namespace] = fileUpload.onDragOver;
82
150
  dropZoneListeners['drop.' + settings.namespace] = fileUpload.onDrop;
83
151
  settings.dropZone.bind(dropZoneListeners);
84
152
  }
85
- fileInputListeners['change.' + settings.namespace] = fileUpload.onChange;
86
- fileInput.bind(fileInputListeners);
153
+ fileInput.bind('change.' + settings.namespace, fileUpload.onChange);
87
154
  },
88
155
 
89
156
  removeEventHandlers = function () {
@@ -93,41 +160,185 @@
93
160
  $.each(dropZoneListeners, function (key, value) {
94
161
  settings.dropZone.unbind(key, value);
95
162
  });
96
- $.each(fileInputListeners, function (key, value) {
97
- fileInput.unbind(key, value);
98
- });
163
+ fileInput.unbind('change.' + settings.namespace);
99
164
  },
100
165
 
101
- initUploadEventHandlers = function (files, index, xhr, settings) {
102
- if (typeof settings.onProgress === func) {
103
- xhr.upload.onprogress = function (e) {
104
- settings.onProgress(e, files, index, xhr, settings);
166
+ isChunkedUpload = function (settings) {
167
+ return typeof settings.uploadedBytes !== undef;
168
+ },
169
+
170
+ createProgressEvent = function (lengthComputable, loaded, total) {
171
+ var event;
172
+ if (typeof document.createEvent === func && typeof ProgressEvent !== undef) {
173
+ event = document.createEvent('ProgressEvent');
174
+ event.initProgressEvent(
175
+ 'progress',
176
+ false,
177
+ false,
178
+ lengthComputable,
179
+ loaded,
180
+ total
181
+ );
182
+ } else {
183
+ event = {
184
+ lengthComputable: true,
185
+ loaded: loaded,
186
+ total: total
105
187
  };
106
188
  }
189
+ return event;
190
+ },
191
+
192
+ getProgressTotal = function (files, index, settings) {
193
+ var i,
194
+ total;
195
+ if (typeof settings.progressTotal === undef) {
196
+ if (files[index]) {
197
+ total = files[index].size;
198
+ settings.progressTotal = total ? total : 1;
199
+ } else {
200
+ total = 0;
201
+ for (i = 0; i < files.length; i += 1) {
202
+ total += files[i].size;
203
+ }
204
+ settings.progressTotal = total;
205
+ }
206
+ }
207
+ return settings.progressTotal;
208
+ },
209
+
210
+ handleGlobalProgress = function (event, files, index, xhr, settings) {
211
+ var progressEvent,
212
+ loaderList,
213
+ globalLoaded = 0,
214
+ globalTotal = 0;
215
+ if (event.lengthComputable && typeof settings.onProgressAll === func) {
216
+ settings.progressLoaded = parseInt(
217
+ event.loaded / event.total * getProgressTotal(files, index, settings),
218
+ 10
219
+ );
220
+ loaderList = multiLoader.getList();
221
+ $.each(loaderList, function (index, item) {
222
+ // item is an array with [files, index, xhr, settings]
223
+ globalLoaded += item[3].progressLoaded || 0;
224
+ globalTotal += getProgressTotal(item[0], item[1], item[3]);
225
+ });
226
+ progressEvent = createProgressEvent(
227
+ true,
228
+ globalLoaded,
229
+ globalTotal
230
+ );
231
+ settings.onProgressAll(progressEvent, loaderList);
232
+ }
233
+ },
234
+
235
+ handleLoadEvent = function (event, files, index, xhr, settings) {
236
+ var progressEvent;
237
+ if (isChunkedUpload(settings)) {
238
+ settings.uploadedBytes += settings.chunkSize;
239
+ progressEvent = createProgressEvent(
240
+ true,
241
+ settings.uploadedBytes,
242
+ files[index].size
243
+ );
244
+ if (typeof settings.onProgress === func) {
245
+ settings.onProgress(progressEvent, files, index, xhr, settings);
246
+ }
247
+ handleGlobalProgress(progressEvent, files, index, xhr, settings);
248
+ if (settings.uploadedBytes < files[index].size) {
249
+ if (typeof settings.resumeUpload === func) {
250
+ settings.resumeUpload(
251
+ event,
252
+ files,
253
+ index,
254
+ xhr,
255
+ settings,
256
+ function () {
257
+ upload(event, files, index, xhr, settings, true);
258
+ }
259
+ );
260
+ } else {
261
+ upload(event, files, index, xhr, settings, true);
262
+ }
263
+ return;
264
+ }
265
+ }
266
+ settings.progressLoaded = getProgressTotal(files, index, settings);
107
267
  if (typeof settings.onLoad === func) {
108
- xhr.onload = function (e) {
109
- settings.onLoad(e, files, index, xhr, settings);
110
- };
268
+ settings.onLoad(event, files, index, xhr, settings);
111
269
  }
112
- if (typeof settings.onAbort === func) {
113
- xhr.onabort = function (e) {
114
- settings.onAbort(e, files, index, xhr, settings);
270
+ completeNext();
271
+ },
272
+
273
+ handleProgressEvent = function (event, files, index, xhr, settings) {
274
+ var progressEvent = event;
275
+ if (isChunkedUpload(settings) && event.lengthComputable) {
276
+ progressEvent = createProgressEvent(
277
+ true,
278
+ settings.uploadedBytes + parseInt(event.loaded / event.total * settings.chunkSize, 10),
279
+ files[index].size
280
+ );
281
+ }
282
+ if (typeof settings.onProgress === func) {
283
+ settings.onProgress(progressEvent, files, index, xhr, settings);
284
+ }
285
+ handleGlobalProgress(progressEvent, files, index, xhr, settings);
286
+ },
287
+
288
+ initUploadEventHandlers = function (files, index, xhr, settings) {
289
+ if (xhr.upload) {
290
+ xhr.upload.onprogress = function (e) {
291
+ handleProgressEvent(e, files, index, xhr, settings);
115
292
  };
116
293
  }
117
- if (typeof settings.onError === func) {
118
- xhr.onerror = function (e) {
294
+ xhr.onload = function (e) {
295
+ handleLoadEvent(e, files, index, xhr, settings);
296
+ };
297
+ xhr.onabort = function (e) {
298
+ settings.progressTotal = settings.progressLoaded;
299
+ if (typeof settings.onAbort === func) {
300
+ settings.onAbort(e, files, index, xhr, settings);
301
+ }
302
+ completeNext();
303
+ };
304
+ xhr.onerror = function (e) {
305
+ settings.progressTotal = settings.progressLoaded;
306
+ if (typeof settings.onError === func) {
119
307
  settings.onError(e, files, index, xhr, settings);
120
- };
308
+ }
309
+ completeNext();
310
+ };
311
+ },
312
+
313
+ getUrl = function (settings) {
314
+ if (typeof settings.url === func) {
315
+ return settings.url(settings.uploadForm || uploadForm);
316
+ }
317
+ return settings.url;
318
+ },
319
+
320
+ getMethod = function (settings) {
321
+ if (typeof settings.method === func) {
322
+ return settings.method(settings.uploadForm || uploadForm);
323
+ }
324
+ return settings.method;
325
+ },
326
+
327
+ getFieldName = function (settings) {
328
+ if (typeof settings.fieldName === func) {
329
+ return settings.fieldName(settings.fileInput || fileInput);
121
330
  }
331
+ return settings.fieldName;
122
332
  },
123
333
 
124
334
  getFormData = function (settings) {
335
+ var formData;
125
336
  if (typeof settings.formData === func) {
126
- return settings.formData();
337
+ return settings.formData(settings.uploadForm || uploadForm);
127
338
  } else if ($.isArray(settings.formData)) {
128
339
  return settings.formData;
129
340
  } else if (settings.formData) {
130
- var formData = [];
341
+ formData = [];
131
342
  $.each(settings.formData, function (name, value) {
132
343
  formData.push({name: name, value: value});
133
344
  });
@@ -151,12 +362,35 @@
151
362
  return true;
152
363
  },
153
364
 
154
- nonMultipartUpload = function (file, xhr, sameDomain) {
365
+ initUploadRequest = function (files, index, xhr, settings) {
366
+ var file = files[index],
367
+ url = getUrl(settings),
368
+ sameDomain = isSameDomain(url);
369
+ xhr.open(getMethod(settings), url, true);
155
370
  if (sameDomain) {
156
- xhr.setRequestHeader('X-File-Name', unescape(encodeURIComponent(file.name)));
371
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
372
+ if (!settings.multipart || isChunkedUpload(settings)) {
373
+ xhr.setRequestHeader('X-File-Name', file.name);
374
+ xhr.setRequestHeader('X-File-Type', file.type);
375
+ xhr.setRequestHeader('X-File-Size', file.size);
376
+ if (!isChunkedUpload(settings)) {
377
+ xhr.setRequestHeader('Content-Type', file.type);
378
+ } else if (!settings.multipart) {
379
+ xhr.setRequestHeader('Content-Type', 'application/octet-stream');
380
+ }
381
+ }
382
+ } else if (settings.withCredentials) {
383
+ xhr.withCredentials = true;
384
+ }
385
+ if ($.isArray(settings.requestHeaders)) {
386
+ $.each(settings.requestHeaders, function (index, header) {
387
+ xhr.setRequestHeader(header.name, header.value);
388
+ });
389
+ } else if (settings.requestHeaders) {
390
+ $.each(settings.requestHeaders, function (name, value) {
391
+ xhr.setRequestHeader(name, value);
392
+ });
157
393
  }
158
- xhr.setRequestHeader('Content-Type', file.type);
159
- xhr.send(file);
160
394
  },
161
395
 
162
396
  formDataUpload = function (files, xhr, settings) {
@@ -166,41 +400,47 @@
166
400
  formData.append(field.name, field.value);
167
401
  });
168
402
  for (i = 0; i < files.length; i += 1) {
169
- formData.append(settings.fieldName, files[i]);
403
+ formData.append(getFieldName(settings), files[i]);
170
404
  }
171
405
  xhr.send(formData);
172
406
  },
173
407
 
174
408
  loadFileContent = function (file, callBack) {
175
- var fileReader = new FileReader();
176
- fileReader.onload = function (e) {
177
- file.content = e.target.result;
178
- callBack();
179
- };
180
- fileReader.readAsBinaryString(file);
409
+ file.reader = new FileReader();
410
+ file.reader.onload = callBack;
411
+ file.reader.readAsBinaryString(file);
181
412
  },
182
413
 
183
- buildMultiPartFormData = function (boundary, files, fields) {
414
+ utf8encode = function (str) {
415
+ return unescape(encodeURIComponent(str));
416
+ },
417
+
418
+ buildMultiPartFormData = function (boundary, files, filesFieldName, fields) {
184
419
  var doubleDash = '--',
185
420
  crlf = '\r\n',
186
- formData = '';
421
+ formData = '',
422
+ buffer = [];
187
423
  $.each(fields, function (index, field) {
188
424
  formData += doubleDash + boundary + crlf +
189
425
  'Content-Disposition: form-data; name="' +
190
- unescape(encodeURIComponent(field.name)) +
426
+ utf8encode(field.name) +
191
427
  '"' + crlf + crlf +
192
- unescape(encodeURIComponent(field.value)) + crlf;
428
+ utf8encode(field.value) + crlf;
193
429
  });
194
430
  $.each(files, function (index, file) {
195
431
  formData += doubleDash + boundary + crlf +
196
432
  'Content-Disposition: form-data; name="' +
197
- unescape(encodeURIComponent(settings.fieldName)) +
198
- '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
199
- 'Content-Type: ' + file.type + crlf + crlf +
200
- file.content + crlf;
433
+ utf8encode(filesFieldName) +
434
+ '"; filename="' + utf8encode(file.name) + '"' + crlf +
435
+ 'Content-Type: ' + utf8encode(file.type) + crlf + crlf;
436
+ buffer.push(formData);
437
+ buffer.push(file.reader.result);
438
+ delete file.reader;
439
+ formData = crlf;
201
440
  });
202
441
  formData += doubleDash + boundary + doubleDash + crlf;
203
- return formData;
442
+ buffer.push(formData);
443
+ return buffer.join('');
204
444
  },
205
445
 
206
446
  fileReaderUpload = function (files, xhr, settings) {
@@ -212,6 +452,7 @@
212
452
  xhr.sendAsBinary(buildMultiPartFormData(
213
453
  boundary,
214
454
  files,
455
+ getFieldName(settings),
215
456
  getFormData(settings)
216
457
  ));
217
458
  }, files.length);
@@ -220,67 +461,99 @@
220
461
  }
221
462
  },
222
463
 
223
- upload = function (files, index, xhr, settings) {
224
- var sameDomain = isSameDomain(settings.url),
225
- filesToUpload;
226
- initUploadEventHandlers(files, index, xhr, settings);
227
- xhr.open(settings.method, settings.url, true);
228
- if (sameDomain) {
229
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
230
- } else if (settings.withCredentials) {
231
- xhr.withCredentials = true;
464
+ getBlob = function (file, settings) {
465
+ var blob,
466
+ ub = settings.uploadedBytes,
467
+ mcs = settings.maxChunkSize;
468
+ if (file && typeof file.slice === func && (ub || (mcs && mcs < file.size))) {
469
+ settings.uploadedBytes = ub = ub || 0;
470
+ blob = file.slice(ub, mcs || file.size - ub);
471
+ settings.chunkSize = blob.size;
472
+ return blob;
232
473
  }
233
- if (!settings.multipart) {
234
- nonMultipartUpload(files[index], xhr, sameDomain);
235
- } else {
236
- if (typeof index === num) {
237
- filesToUpload = [files[index]];
238
- } else {
239
- filesToUpload = files;
474
+ return file;
475
+ },
476
+
477
+ upload = function (event, files, index, xhr, settings, nextChunk) {
478
+ var send;
479
+ send = function () {
480
+ if (!nextChunk) {
481
+ if (typeof settings.onSend === func &&
482
+ settings.onSend(event, files, index, xhr, settings) === false) {
483
+ completeNext();
484
+ return;
485
+ }
240
486
  }
241
- if (typeof FormData !== undef) {
242
- formDataUpload(filesToUpload, xhr, settings);
243
- } else if (typeof FileReader !== undef) {
244
- fileReaderUpload(filesToUpload, xhr, settings);
487
+ var blob = getBlob(files[index], settings),
488
+ filesToUpload;
489
+ initUploadEventHandlers(files, index, xhr, settings);
490
+ initUploadRequest(files, index, xhr, settings);
491
+ if (!settings.multipart) {
492
+ if (xhr.upload) {
493
+ xhr.send(blob);
494
+ } else {
495
+ $.error('Browser does not support XHR file uploads');
496
+ }
245
497
  } else {
246
- $.error('Browser does neither support FormData nor FileReader interface');
498
+ filesToUpload = (typeof index === 'number') ? [blob] : files;
499
+ if (typeof FormData !== undef) {
500
+ formDataUpload(filesToUpload, xhr, settings);
501
+ } else if (typeof FileReader !== undef && typeof xhr.sendAsBinary === func) {
502
+ fileReaderUpload(filesToUpload, xhr, settings);
503
+ } else {
504
+ $.error('Browser does not support multipart/form-data XHR file uploads');
505
+ }
506
+ }
507
+ };
508
+ if (!nextChunk) {
509
+ multiLoader.push(Array.prototype.slice.call(arguments, 1));
510
+ if (settings.sequentialUploads) {
511
+ sequenceHandler.push(send);
512
+ return;
247
513
  }
248
514
  }
515
+ send();
249
516
  },
250
517
 
251
- handleUpload = function (event, files, index) {
518
+ handleUpload = function (event, files, input, form, index) {
252
519
  var xhr = new XMLHttpRequest(),
253
520
  uploadSettings = $.extend({}, settings);
254
- if (typeof settings.initUpload === func) {
255
- settings.initUpload(
521
+ uploadSettings.fileInput = input;
522
+ uploadSettings.uploadForm = form;
523
+ if (typeof uploadSettings.initUpload === func) {
524
+ uploadSettings.initUpload(
256
525
  event,
257
526
  files,
258
527
  index,
259
528
  xhr,
260
529
  uploadSettings,
261
530
  function () {
262
- upload(files, index, xhr, uploadSettings);
531
+ upload(event, files, index, xhr, uploadSettings);
263
532
  }
264
533
  );
265
534
  } else {
266
- upload(files, index, xhr, uploadSettings);
535
+ upload(event, files, index, xhr, uploadSettings);
267
536
  }
268
537
  },
269
538
 
270
- handleFiles = function (event, files) {
271
- var i;
272
- if (settings.multiFileRequest) {
273
- handleUpload(event, files);
539
+ handleLegacyGlobalProgress = function (event, files, index, iframe, settings) {
540
+ var total = 0,
541
+ progressEvent;
542
+ if (typeof index === undef) {
543
+ $.each(files, function (index, file) {
544
+ total += file.size ? file.size : 1;
545
+ });
274
546
  } else {
275
- for (i = 0; i < files.length; i += 1) {
276
- handleUpload(event, files, i);
277
- }
547
+ total = files[index].size ? files[index].size : 1;
278
548
  }
549
+ progressEvent = createProgressEvent(true, total, total);
550
+ settings.progressLoaded = total;
551
+ handleGlobalProgress(progressEvent, files, index, iframe, settings);
279
552
  },
280
553
 
281
- legacyUploadFormDataInit = function (input, settings) {
554
+ legacyUploadFormDataInit = function (input, form, settings) {
282
555
  var formData = getFormData(settings);
283
- uploadForm.find(':input').not(':disabled')
556
+ form.find(':input').not(':disabled')
284
557
  .attr('disabled', true)
285
558
  .addClass(settings.namespace + '_disabled');
286
559
  $.each(formData, function (index, field) {
@@ -288,80 +561,165 @@
288
561
  .attr('name', field.name)
289
562
  .val(field.value)
290
563
  .addClass(settings.namespace + '_form_data')
291
- .insertBefore(fileInput);
564
+ .appendTo(form);
292
565
  });
293
- input.insertAfter(fileInput);
566
+ input
567
+ .attr('name', getFieldName(settings))
568
+ .appendTo(form);
294
569
  },
295
570
 
296
- legacyUploadFormDataReset = function (input, settings) {
297
- input.remove();
298
- uploadForm.find('.' + settings.namespace + '_disabled')
571
+ legacyUploadFormDataReset = function (input, form, settings) {
572
+ input.detach();
573
+ form.find('.' + settings.namespace + '_disabled')
299
574
  .removeAttr('disabled')
300
575
  .removeClass(settings.namespace + '_disabled');
301
- uploadForm.find('.' + settings.namespace + '_form_data').remove();
302
- },
303
-
304
- legacyUpload = function (input, iframe, settings) {
305
- iframe
306
- .unbind('abort')
307
- .bind('abort', function (e) {
308
- iframe.readyState = 0;
309
- // javascript:false as iframe src prevents warning popups on HTTPS in IE6
310
- // concat is used here to prevent the "Script URL" JSLint error:
311
- iframe.unbind('load').attr('src', 'javascript'.concat(':false;'));
312
- if (typeof settings.onAbort === func) {
313
- settings.onAbort(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
314
- }
315
- })
316
- .unbind('load')
317
- .bind('load', function (e) {
318
- iframe.readyState = 4;
319
- if (typeof settings.onLoad === func) {
320
- settings.onLoad(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
321
- }
322
- });
323
- uploadForm
324
- .attr('action', settings.url)
325
- .attr('target', iframe.attr('name'));
326
- legacyUploadFormDataInit(input, settings);
327
- iframe.readyState = 2;
328
- uploadForm.get(0).submit();
329
- legacyUploadFormDataReset(input, settings);
576
+ form.find('.' + settings.namespace + '_form_data').remove();
577
+ },
578
+
579
+ legacyUpload = function (event, files, input, form, iframe, settings, index) {
580
+ var send;
581
+ send = function () {
582
+ if (typeof settings.onSend === func && settings.onSend(event, files, index, iframe, settings) === false) {
583
+ completeNext();
584
+ return;
585
+ }
586
+ var originalAction = form.attr('action'),
587
+ originalMethod = form.attr('method'),
588
+ originalTarget = form.attr('target');
589
+ iframe
590
+ .unbind('abort')
591
+ .bind('abort', function (e) {
592
+ iframe.readyState = 0;
593
+ // javascript:false as iframe src prevents warning popups on HTTPS in IE6
594
+ // concat is used here to prevent the "Script URL" JSLint error:
595
+ iframe.unbind('load').attr('src', 'javascript'.concat(':false;'));
596
+ handleLegacyGlobalProgress(e, files, index, iframe, settings);
597
+ if (typeof settings.onAbort === func) {
598
+ settings.onAbort(e, files, index, iframe, settings);
599
+ }
600
+ completeNext();
601
+ })
602
+ .unbind('load')
603
+ .bind('load', function (e) {
604
+ iframe.readyState = 4;
605
+ handleLegacyGlobalProgress(e, files, index, iframe, settings);
606
+ if (typeof settings.onLoad === func) {
607
+ settings.onLoad(e, files, index, iframe, settings);
608
+ }
609
+ // Fix for IE endless progress bar activity bug
610
+ // (happens on form submits to iframe targets):
611
+ $('<iframe src="javascript:false;" style="display:none;"></iframe>')
612
+ .appendTo(form).remove();
613
+ completeNext();
614
+ });
615
+ form
616
+ .attr('action', getUrl(settings))
617
+ .attr('method', getMethod(settings))
618
+ .attr('target', iframe.attr('name'));
619
+ legacyUploadFormDataInit(input, form, settings);
620
+ iframe.readyState = 2;
621
+ form.get(0).submit();
622
+ legacyUploadFormDataReset(input, form, settings);
623
+ form
624
+ .attr('action', originalAction)
625
+ .attr('method', originalMethod)
626
+ .attr('target', originalTarget);
627
+ };
628
+ multiLoader.push([files, index, iframe, settings]);
629
+ if (settings.sequentialUploads) {
630
+ sequenceHandler.push(send);
631
+ } else {
632
+ send();
633
+ }
330
634
  },
331
635
 
332
- handleLegacyUpload = function (event, input) {
636
+ handleLegacyUpload = function (event, input, form, index) {
637
+ if (!(event && input && form)) {
638
+ $.error('Iframe based File Upload requires a file input change event');
639
+ return;
640
+ }
333
641
  // javascript:false as iframe src prevents warning popups on HTTPS in IE6:
334
- var iframe = $('<iframe src="javascript:false;" style="display:none" name="iframe_' +
642
+ var iframe = $('<iframe src="javascript:false;" style="display:none;" name="iframe_' +
335
643
  settings.namespace + '_' + (new Date()).getTime() + '"></iframe>'),
336
- uploadSettings = $.extend({}, settings);
644
+ uploadSettings = $.extend({}, settings),
645
+ files = event.target && event.target.files;
646
+ files = files ? Array.prototype.slice.call(files, 0) : [{name: input.val(), type: null, size: null}];
647
+ index = files.length === 1 ? 0 : index;
648
+ uploadSettings.fileInput = input;
649
+ uploadSettings.uploadForm = form;
337
650
  iframe.readyState = 0;
338
651
  iframe.abort = function () {
339
652
  iframe.trigger('abort');
340
653
  };
341
654
  iframe.bind('load', function () {
342
655
  iframe.unbind('load');
343
- if (typeof settings.initUpload === func) {
344
- settings.initUpload(
656
+ if (typeof uploadSettings.initUpload === func) {
657
+ uploadSettings.initUpload(
345
658
  event,
346
- [{name: input.val(), type: null, size: null}],
347
- 0,
659
+ files,
660
+ index,
348
661
  iframe,
349
662
  uploadSettings,
350
663
  function () {
351
- legacyUpload(input, iframe, uploadSettings);
664
+ legacyUpload(event, files, input, form, iframe, uploadSettings, index);
352
665
  }
353
666
  );
354
667
  } else {
355
- legacyUpload(input, iframe, uploadSettings);
668
+ legacyUpload(event, files, input, form, iframe, uploadSettings, index);
669
+ }
670
+ }).appendTo(form);
671
+ },
672
+
673
+ canHandleXHRUploadSize = function (files) {
674
+ var bytes = 0,
675
+ totalBytes = 0,
676
+ i;
677
+ if (settings.multipart && typeof FormData === undef) {
678
+ for (i = 0; i < files.length; i += 1) {
679
+ bytes = files[i].size;
680
+ if (bytes > settings.maxFileReaderSize) {
681
+ return false;
682
+ }
683
+ totalBytes += bytes;
684
+ }
685
+ if (settings.multiFileRequest && totalBytes > settings.maxFileReaderSize) {
686
+ return false;
356
687
  }
357
- }).appendTo(uploadForm);
688
+ }
689
+ return true;
358
690
  },
359
691
 
360
- resetFileInput = function () {
361
- var inputClone = fileInput.clone(true);
692
+ handleFiles = function (event, files, input, form) {
693
+ if (!canHandleXHRUploadSize(files)) {
694
+ handleLegacyUpload(event, input, form);
695
+ return;
696
+ }
697
+ var i;
698
+ files = Array.prototype.slice.call(files, 0);
699
+ if (settings.multiFileRequest && settings.multipart && files.length) {
700
+ handleUpload(event, files, input, form);
701
+ } else {
702
+ for (i = 0; i < files.length; i += 1) {
703
+ handleUpload(event, files, input, form, i);
704
+ }
705
+ }
706
+ },
707
+
708
+ initUploadForm = function () {
709
+ uploadForm = (container.is('form') ? container : container.find('form'))
710
+ .filter(settings.uploadFormFilter);
711
+ },
712
+
713
+ initFileInput = function () {
714
+ fileInput = (uploadForm.length ? uploadForm : container).find('input:file')
715
+ .filter(settings.fileInputFilter);
716
+ },
717
+
718
+ replaceFileInput = function (input) {
719
+ var inputClone = input.clone(true);
362
720
  $('<form/>').append(inputClone).get(0).reset();
363
- fileInput.replaceWith(inputClone);
364
- fileInput = inputClone;
721
+ input.after(inputClone).detach();
722
+ initFileInput();
365
723
  };
366
724
 
367
725
  this.onDocumentDragOver = function (e) {
@@ -386,10 +744,10 @@
386
744
  return false;
387
745
  }
388
746
  var dataTransfer = e.originalEvent.dataTransfer;
389
- if (dataTransfer) {
747
+ if (dataTransfer && dataTransfer.files) {
390
748
  dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy';
749
+ e.preventDefault();
391
750
  }
392
- e.preventDefault();
393
751
  };
394
752
 
395
753
  this.onDrop = function (e) {
@@ -409,18 +767,28 @@
409
767
  settings.onChange(e) === false) {
410
768
  return false;
411
769
  }
770
+ var input = $(e.target),
771
+ form = $(e.target.form);
772
+ if (form.length === 1) {
773
+ input.data(defaultNamespace + '_form', form);
774
+ replaceFileInput(input);
775
+ } else {
776
+ form = input.data(defaultNamespace + '_form');
777
+ }
412
778
  if (!settings.forceIframeUpload && e.target.files && isXHRUploadCapable()) {
413
- handleFiles(e, e.target.files);
779
+ handleFiles(e, e.target.files, input, form);
414
780
  } else {
415
- handleLegacyUpload(e, $(e.target));
781
+ handleLegacyUpload(e, input, form);
416
782
  }
417
- resetFileInput();
418
783
  };
419
784
 
420
785
  this.init = function (options) {
421
786
  if (options) {
422
787
  $.extend(settings, options);
788
+ optionsReference = options;
423
789
  }
790
+ initUploadForm();
791
+ initFileInput();
424
792
  if (container.data(settings.namespace)) {
425
793
  $.error('FileUpload with namespace "' + settings.namespace + '" already assigned to this element');
426
794
  return;
@@ -428,16 +796,92 @@
428
796
  container
429
797
  .data(settings.namespace, fileUpload)
430
798
  .addClass(settings.cssClass);
431
- settings.dropZone.addClass(settings.cssClass);
799
+ settings.dropZone.not(container).addClass(settings.cssClass);
800
+ initEventHandlers();
801
+ if (typeof settings.init === func) {
802
+ settings.init();
803
+ }
804
+ };
805
+
806
+ this.options = function (options) {
807
+ var oldCssClass,
808
+ oldDropZone,
809
+ uploadFormFilterUpdate,
810
+ fileInputFilterUpdate;
811
+ if (typeof options === undef) {
812
+ return $.extend({}, settings);
813
+ }
814
+ if (optionsReference) {
815
+ $.extend(optionsReference, options);
816
+ }
817
+ removeEventHandlers();
818
+ $.each(options, function (name, value) {
819
+ switch (name) {
820
+ case 'namespace':
821
+ $.error('The FileUpload namespace cannot be updated.');
822
+ return;
823
+ case 'uploadFormFilter':
824
+ uploadFormFilterUpdate = true;
825
+ fileInputFilterUpdate = true;
826
+ break;
827
+ case 'fileInputFilter':
828
+ fileInputFilterUpdate = true;
829
+ break;
830
+ case 'cssClass':
831
+ oldCssClass = settings.cssClass;
832
+ break;
833
+ case 'dropZone':
834
+ oldDropZone = settings.dropZone;
835
+ break;
836
+ }
837
+ settings[name] = value;
838
+ });
839
+ if (uploadFormFilterUpdate) {
840
+ initUploadForm();
841
+ }
842
+ if (fileInputFilterUpdate) {
843
+ initFileInput();
844
+ }
845
+ if (typeof oldCssClass !== undef) {
846
+ container
847
+ .removeClass(oldCssClass)
848
+ .addClass(settings.cssClass);
849
+ (oldDropZone ? oldDropZone : settings.dropZone).not(container)
850
+ .removeClass(oldCssClass);
851
+ settings.dropZone.not(container).addClass(settings.cssClass);
852
+ } else if (oldDropZone) {
853
+ oldDropZone.not(container).removeClass(settings.cssClass);
854
+ settings.dropZone.not(container).addClass(settings.cssClass);
855
+ }
432
856
  initEventHandlers();
433
857
  };
434
858
 
859
+ this.option = function (name, value) {
860
+ var options;
861
+ if (typeof value === undef) {
862
+ return settings[name];
863
+ }
864
+ options = {};
865
+ options[name] = value;
866
+ fileUpload.options(options);
867
+ };
868
+
435
869
  this.destroy = function () {
870
+ if (typeof settings.destroy === func) {
871
+ settings.destroy();
872
+ }
436
873
  removeEventHandlers();
437
874
  container
438
875
  .removeData(settings.namespace)
439
876
  .removeClass(settings.cssClass);
440
- settings.dropZone.removeClass(settings.cssClass);
877
+ settings.dropZone.not(container).removeClass(settings.cssClass);
878
+ };
879
+
880
+ this.upload = function (files) {
881
+ if (typeof files.length === undef) {
882
+ files = [files];
883
+ }
884
+ handleFiles(null, files);
441
885
  };
442
886
  };
443
887
 
@@ -447,10 +891,36 @@
447
891
  (new FileUpload($(this))).init(options);
448
892
  });
449
893
  },
894
+
895
+ option: function (option, value, namespace) {
896
+ namespace = namespace ? namespace : defaultNamespace;
897
+ var fileUpload = $(this).data(namespace);
898
+ if (fileUpload) {
899
+ if (!option) {
900
+ return fileUpload.options();
901
+ } else if (typeof option === 'string' && typeof value === undef) {
902
+ return fileUpload.option(option);
903
+ }
904
+ } else {
905
+ $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
906
+ }
907
+ return this.each(function () {
908
+ var fu = $(this).data(namespace);
909
+ if (fu) {
910
+ if (typeof option === 'string') {
911
+ fu.option(option, value);
912
+ } else {
913
+ fu.options(option);
914
+ }
915
+ } else {
916
+ $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
917
+ }
918
+ });
919
+ },
450
920
 
451
- destroy : function (namespace) {
921
+ destroy: function (namespace) {
922
+ namespace = namespace ? namespace : defaultNamespace;
452
923
  return this.each(function () {
453
- namespace = namespace ? namespace : 'file_upload';
454
924
  var fileUpload = $(this).data(namespace);
455
925
  if (fileUpload) {
456
926
  fileUpload.destroy();
@@ -458,7 +928,18 @@
458
928
  $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
459
929
  }
460
930
  });
461
-
931
+ },
932
+
933
+ upload: function (files, namespace) {
934
+ namespace = namespace ? namespace : defaultNamespace;
935
+ return this.each(function () {
936
+ var fileUpload = $(this).data(namespace);
937
+ if (fileUpload) {
938
+ fileUpload.upload(files);
939
+ } else {
940
+ $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
941
+ }
942
+ });
462
943
  }
463
944
  };
464
945
 
@@ -468,7 +949,7 @@
468
949
  } else if (typeof method === 'object' || !method) {
469
950
  return methods.init.apply(this, arguments);
470
951
  } else {
471
- $.error('Method ' + method + ' does not exist on jQuery.fileUpload');
952
+ $.error('Method "' + method + '" does not exist on jQuery.fileUpload');
472
953
  }
473
954
  };
474
955