glebtv-rails-uploader 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +241 -0
  3. data/Rakefile +26 -0
  4. data/app/assets/javascripts/uploader/application.js +9 -0
  5. data/app/assets/javascripts/uploader/rails_admin.js +25 -0
  6. data/app/assets/stylesheets/uploader/application.css +7 -0
  7. data/app/controllers/uploader/attachments_controller.rb +67 -0
  8. data/app/views/rails_admin/main/_form_rails_uploader.haml +10 -0
  9. data/app/views/uploader/default/_container.html.erb +67 -0
  10. data/app/views/uploader/default/_download.html.erb +17 -0
  11. data/app/views/uploader/default/_upload.html.erb +14 -0
  12. data/config/locales/en.yml +5 -0
  13. data/config/locales/ru.yml +5 -0
  14. data/config/locales/uk.yml +5 -0
  15. data/config/routes.rb +7 -0
  16. data/lib/file_size_validator.rb +66 -0
  17. data/lib/glebtv-rails-uploader.rb +3 -0
  18. data/lib/uploader.rb +35 -0
  19. data/lib/uploader/asset.rb +47 -0
  20. data/lib/uploader/engine.rb +25 -0
  21. data/lib/uploader/fileuploads.rb +109 -0
  22. data/lib/uploader/helpers/field_tag.rb +100 -0
  23. data/lib/uploader/helpers/form_builder.rb +16 -0
  24. data/lib/uploader/helpers/form_tag_helper.rb +16 -0
  25. data/lib/uploader/hooks/active_record.rb +5 -0
  26. data/lib/uploader/hooks/formtastic.rb +14 -0
  27. data/lib/uploader/hooks/simple_form.rb +9 -0
  28. data/lib/uploader/rails_admin/field.rb +28 -0
  29. data/lib/uploader/version.rb +3 -0
  30. data/spec/dummy/README.rdoc +261 -0
  31. data/spec/dummy/Rakefile +7 -0
  32. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  34. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy/app/models/article.rb +7 -0
  37. data/spec/dummy/app/models/asset.rb +27 -0
  38. data/spec/dummy/app/models/picture.rb +5 -0
  39. data/spec/dummy/app/uploaders/picture_uploader.rb +55 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/config.ru +4 -0
  42. data/spec/dummy/config/application.rb +58 -0
  43. data/spec/dummy/config/boot.rb +10 -0
  44. data/spec/dummy/config/database.yml +25 -0
  45. data/spec/dummy/config/environment.rb +5 -0
  46. data/spec/dummy/config/environments/development.rb +37 -0
  47. data/spec/dummy/config/environments/production.rb +67 -0
  48. data/spec/dummy/config/environments/test.rb +37 -0
  49. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/dummy/config/initializers/inflections.rb +15 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  52. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  53. data/spec/dummy/config/initializers/session_store.rb +8 -0
  54. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  55. data/spec/dummy/config/locales/en.yml +5 -0
  56. data/spec/dummy/config/routes.rb +3 -0
  57. data/spec/dummy/db/migrate/20120508093416_create_assets.rb +19 -0
  58. data/spec/dummy/db/migrate/20120508093830_create_articles.rb +10 -0
  59. data/spec/dummy/public/404.html +26 -0
  60. data/spec/dummy/public/422.html +26 -0
  61. data/spec/dummy/public/500.html +25 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/script/rails +6 -0
  64. data/spec/factories/articles.rb +8 -0
  65. data/spec/factories/assets.rb +11 -0
  66. data/spec/factories/files/rails.png +0 -0
  67. data/spec/fileuploads_spec.rb +57 -0
  68. data/spec/requests/attachments_controller_spec.rb +38 -0
  69. data/spec/spec_helper.rb +52 -0
  70. data/spec/uploader_spec.rb +18 -0
  71. data/vendor/assets/images/uploader/but_del_tag2.png +0 -0
  72. data/vendor/assets/images/uploader/ico_attach.png +0 -0
  73. data/vendor/assets/images/uploader/preloader.gif +0 -0
  74. data/vendor/assets/images/uploader/progressBarFillBg.png +0 -0
  75. data/vendor/assets/javascripts/uploader/jquery.fileupload-ip.js +160 -0
  76. data/vendor/assets/javascripts/uploader/jquery.fileupload-ui.js +637 -0
  77. data/vendor/assets/javascripts/uploader/jquery.fileupload.js +904 -0
  78. data/vendor/assets/javascripts/uploader/jquery.iframe-transport.js +171 -0
  79. data/vendor/assets/javascripts/uploader/jquery.ui.widget.js +282 -0
  80. data/vendor/assets/javascripts/uploader/load-image.min.js +1 -0
  81. data/vendor/assets/javascripts/uploader/locales/en.js +27 -0
  82. data/vendor/assets/javascripts/uploader/locales/ru.js +27 -0
  83. data/vendor/assets/javascripts/uploader/locales/uk.js +27 -0
  84. data/vendor/assets/javascripts/uploader/tmpl.min.js +1 -0
  85. data/vendor/assets/stylesheets/uploader/default.css +214 -0
  86. data/vendor/assets/stylesheets/uploader/jquery.fileupload-ui.css +30 -0
  87. metadata +317 -0
@@ -0,0 +1,637 @@
1
+ /*
2
+ * jQuery File Upload User Interface Plugin 6.6.4
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2010, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint nomen: true, unparam: true, regexp: true */
13
+ /*global define, window, document, URL, webkitURL, FileReader */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ 'tmpl',
22
+ 'load-image',
23
+ './jquery.fileupload-ip'
24
+ ], factory);
25
+ } else {
26
+ // Browser globals:
27
+ factory(
28
+ window.jQuery,
29
+ window.tmpl,
30
+ window.loadImage
31
+ );
32
+ }
33
+ }(function ($, tmpl, loadImage) {
34
+ 'use strict';
35
+
36
+ // The UI version extends the IP (image processing) version or the basic
37
+ // file upload widget and adds complete user interface interaction:
38
+ var parentWidget = ($.blueimpIP || $.blueimp).fileupload;
39
+ $.widget('blueimpUI.fileupload', parentWidget, {
40
+
41
+ options: {
42
+ // By default, files added to the widget are uploaded as soon
43
+ // as the user clicks on the start buttons. To enable automatic
44
+ // uploads, set the following option to true:
45
+ autoUpload: false,
46
+ // The following option limits the number of files that are
47
+ // allowed to be uploaded using this widget:
48
+ maxNumberOfFiles: undefined,
49
+ // The maximum allowed file size:
50
+ maxFileSize: undefined,
51
+ // The minimum allowed file size:
52
+ minFileSize: undefined,
53
+ // The regular expression for allowed file types, matches
54
+ // against either file type or file name:
55
+ acceptFileTypes: /.+$/i,
56
+ // The regular expression to define for which files a preview
57
+ // image is shown, matched against the file type:
58
+ previewSourceFileTypes: /^image\/(gif|jpeg|png)$/,
59
+ // The maximum file size of images that are to be displayed as preview:
60
+ previewSourceMaxFileSize: 5000000, // 5MB
61
+ // The maximum width of the preview images:
62
+ previewMaxWidth: 80,
63
+ // The maximum height of the preview images:
64
+ previewMaxHeight: 80,
65
+ // By default, preview images are displayed as canvas elements
66
+ // if supported by the browser. Set the following option to false
67
+ // to always display preview images as img elements:
68
+ previewAsCanvas: true,
69
+ // The ID of the upload template:
70
+ uploadTemplateId: 'template-upload',
71
+ // The ID of the download template:
72
+ downloadTemplateId: 'template-download',
73
+ // The expected data type of the upload response, sets the dataType
74
+ // option of the $.ajax upload requests:
75
+ dataType: 'json',
76
+
77
+ // The add callback is invoked as soon as files are added to the fileupload
78
+ // widget (via file input selection, drag & drop or add API call).
79
+ // See the basic file upload widget for more information:
80
+ add: function (e, data) {
81
+ var that = $(this).data('fileupload'),
82
+ options = that.options,
83
+ files = data.files;
84
+ $(this).fileupload('resize', data).done(data, function () {
85
+ that._adjustMaxNumberOfFiles(-files.length);
86
+ data.isAdjusted = true;
87
+ data.files.valid = data.isValidated = that._validate(files);
88
+ data.context = that._renderUpload(files)
89
+ .appendTo(options.filesContainer)
90
+ .data('data', data);
91
+ that._renderPreviews(files, data.context);
92
+ that._forceReflow(data.context);
93
+ that._transition(data.context).done(
94
+ function () {
95
+ if ((that._trigger('added', e, data) !== false) &&
96
+ (options.autoUpload || data.autoUpload) &&
97
+ data.autoUpload !== false && data.isValidated) {
98
+ data.submit();
99
+ }
100
+ }
101
+ );
102
+ });
103
+ },
104
+ // Callback for the start of each file upload request:
105
+ send: function (e, data) {
106
+ var that = $(this).data('fileupload');
107
+ if (!data.isValidated) {
108
+ if (!data.isAdjusted) {
109
+ that._adjustMaxNumberOfFiles(-data.files.length);
110
+ }
111
+ if (!that._validate(data.files)) {
112
+ return false;
113
+ }
114
+ }
115
+ if (data.context && data.dataType &&
116
+ data.dataType.substr(0, 6) === 'iframe') {
117
+ // Iframe Transport does not support progress events.
118
+ // In lack of an indeterminate progress bar, we set
119
+ // the progress to 100%, showing the full animated bar:
120
+ data.context
121
+ .find('.progress').addClass(
122
+ !$.support.transition && 'progress-animated'
123
+ )
124
+ .find('.bar').css(
125
+ 'width',
126
+ parseInt(100, 10) + '%'
127
+ );
128
+ }
129
+ return that._trigger('sent', e, data);
130
+ },
131
+ // Callback for successful uploads:
132
+ done: function (e, data) {
133
+ var that = $(this).data('fileupload'),
134
+ template,
135
+ preview;
136
+
137
+ if (data.context) {
138
+ data.context.each(function (index) {
139
+ var file = ($.isArray(data.result) &&
140
+ data.result[index]) || {error: 'emptyResult'};
141
+ if (file.error) {
142
+ that._adjustMaxNumberOfFiles(1);
143
+ }
144
+ that._transition($(this)).done(
145
+ function () {
146
+ var node = $(this);
147
+ template = that._renderDownload([file])
148
+ .css('height', node.height())
149
+ .replaceAll(node);
150
+ that._forceReflow(template);
151
+ that._transition(template).done(
152
+ function () {
153
+ data.context = $(this);
154
+ that._trigger('completed', e, data);
155
+ }
156
+ );
157
+ }
158
+ );
159
+ });
160
+ } else {
161
+ template = that._renderDownload(data.result)
162
+ .appendTo(that.options.filesContainer);
163
+ that._forceReflow(template);
164
+ that._transition(template).done(
165
+ function () {
166
+ data.context = $(this);
167
+ that._trigger('completed', e, data);
168
+ }
169
+ );
170
+ }
171
+ },
172
+ // Callback for failed (abort or error) uploads:
173
+ fail: function (e, data) {
174
+ var that = $(this).data('fileupload'),
175
+ template;
176
+ that._adjustMaxNumberOfFiles(data.files.length);
177
+ if (data.context) {
178
+ data.context.each(function (index) {
179
+ if (data.errorThrown !== 'abort') {
180
+ var file = data.files[index];
181
+ file.error = file.error || data.errorThrown ||
182
+ true;
183
+ that._transition($(this)).done(
184
+ function () {
185
+ var node = $(this);
186
+ template = that._renderDownload([file])
187
+ .replaceAll(node);
188
+ that._forceReflow(template);
189
+ that._transition(template).done(
190
+ function () {
191
+ data.context = $(this);
192
+ that._trigger('failed', e, data);
193
+ }
194
+ );
195
+ }
196
+ );
197
+ } else {
198
+ that._transition($(this)).done(
199
+ function () {
200
+ $(this).remove();
201
+ that._trigger('failed', e, data);
202
+ }
203
+ );
204
+ }
205
+ });
206
+ } else if (data.errorThrown !== 'abort') {
207
+ that._adjustMaxNumberOfFiles(-data.files.length);
208
+ data.context = that._renderUpload(data.files)
209
+ .appendTo(that.options.filesContainer)
210
+ .data('data', data);
211
+ that._forceReflow(data.context);
212
+ that._transition(data.context).done(
213
+ function () {
214
+ data.context = $(this);
215
+ that._trigger('failed', e, data);
216
+ }
217
+ );
218
+ } else {
219
+ that._trigger('failed', e, data);
220
+ }
221
+ },
222
+ // Callback for upload progress events:
223
+ progress: function (e, data) {
224
+ if (data.context) {
225
+ data.context.find('.progress .bar').css(
226
+ 'width',
227
+ parseInt(data.loaded / data.total * 100, 10) + '%'
228
+ );
229
+ }
230
+ },
231
+ // Callback for global upload progress events:
232
+ progressall: function (e, data) {
233
+ $(this).find('.fileupload-buttonbar .progress .bar').css(
234
+ 'width',
235
+ parseInt(data.loaded / data.total * 100, 10) + '%'
236
+ );
237
+ },
238
+ // Callback for uploads start, equivalent to the global ajaxStart event:
239
+ start: function (e) {
240
+ var that = $(this).data('fileupload');
241
+ that._transition($(this).find('.fileupload-buttonbar .progress')).done(
242
+ function () {
243
+ that._trigger('started', e);
244
+ }
245
+ );
246
+ },
247
+ // Callback for uploads stop, equivalent to the global ajaxStop event:
248
+ stop: function (e) {
249
+ var that = $(this).data('fileupload');
250
+ that._transition($(this).find('.fileupload-buttonbar .progress')).done(
251
+ function () {
252
+ $(this).find('.bar').css('width', '0%');
253
+ that._trigger('stopped', e);
254
+ }
255
+ );
256
+ },
257
+ // Callback for file deletion:
258
+ destroy: function (e, data) {
259
+ var that = $(this).data('fileupload');
260
+ if (data.url) {
261
+ $.ajax(data);
262
+ }
263
+ that._adjustMaxNumberOfFiles(1);
264
+ that._transition(data.context).done(
265
+ function () {
266
+ $(this).remove();
267
+ that._trigger('destroyed', e, data);
268
+ }
269
+ );
270
+ }
271
+ },
272
+
273
+ // Link handler, that allows to download files
274
+ // by drag & drop of the links to the desktop:
275
+ _enableDragToDesktop: function () {
276
+ var link = $(this),
277
+ url = link.prop('href'),
278
+ name = link.prop('download'),
279
+ type = 'application/octet-stream';
280
+ link.bind('dragstart', function (e) {
281
+ try {
282
+ e.originalEvent.dataTransfer.setData(
283
+ 'DownloadURL',
284
+ [type, name, url].join(':')
285
+ );
286
+ } catch (err) {}
287
+ });
288
+ },
289
+
290
+ _adjustMaxNumberOfFiles: function (operand) {
291
+ if (typeof this.options.maxNumberOfFiles === 'number') {
292
+ this.options.maxNumberOfFiles += operand;
293
+ if (this.options.maxNumberOfFiles < 1) {
294
+ this._disableFileInputButton();
295
+ } else {
296
+ this._enableFileInputButton();
297
+ }
298
+ }
299
+ },
300
+
301
+ _formatFileSize: function (bytes) {
302
+ if (typeof bytes !== 'number') {
303
+ return '';
304
+ }
305
+ if (bytes >= 1000000000) {
306
+ return (bytes / 1000000000).toFixed(2) + ' GB';
307
+ }
308
+ if (bytes >= 1000000) {
309
+ return (bytes / 1000000).toFixed(2) + ' MB';
310
+ }
311
+ return (bytes / 1000).toFixed(2) + ' KB';
312
+ },
313
+
314
+ _hasError: function (file) {
315
+ if (file.error) {
316
+ return file.error;
317
+ }
318
+ // The number of added files is subtracted from
319
+ // maxNumberOfFiles before validation, so we check if
320
+ // maxNumberOfFiles is below 0 (instead of below 1):
321
+ if (this.options.maxNumberOfFiles < 0) {
322
+ return 'maxNumberOfFiles';
323
+ }
324
+ // Files are accepted if either the file type or the file name
325
+ // matches against the acceptFileTypes regular expression, as
326
+ // only browsers with support for the File API report the type:
327
+ if (!(this.options.acceptFileTypes.test(file.type) ||
328
+ this.options.acceptFileTypes.test(file.name))) {
329
+ return 'acceptFileTypes';
330
+ }
331
+ if (this.options.maxFileSize &&
332
+ file.size > this.options.maxFileSize) {
333
+ return 'maxFileSize';
334
+ }
335
+ if (typeof file.size === 'number' &&
336
+ file.size < this.options.minFileSize) {
337
+ return 'minFileSize';
338
+ }
339
+ return null;
340
+ },
341
+
342
+ _validate: function (files) {
343
+ var that = this,
344
+ valid = !!files.length;
345
+ $.each(files, function (index, file) {
346
+ file.error = that._hasError(file);
347
+ if (file.error) {
348
+ valid = false;
349
+ }
350
+ });
351
+ return valid;
352
+ },
353
+
354
+ _renderTemplate: function (func, files) {
355
+ if (!func) {
356
+ return $();
357
+ }
358
+ var result = func({
359
+ files: files,
360
+ formatFileSize: this._formatFileSize,
361
+ options: this.options
362
+ });
363
+ if (result instanceof $) {
364
+ return result;
365
+ }
366
+
367
+ return $(this.options.templatesContainer).html(result).children();
368
+ },
369
+
370
+ _renderPreview: function (file, node) {
371
+ var that = this,
372
+ options = this.options,
373
+ deferred = $.Deferred();
374
+ return ((loadImage && loadImage(
375
+ file,
376
+ function (img) {
377
+ node.append(img);
378
+ that._forceReflow(node);
379
+ that._transition(node).done(function () {
380
+ deferred.resolveWith(node);
381
+ });
382
+ if (!$.contains(document.body, node[0])) {
383
+ // If the element is not part of the DOM,
384
+ // transition events are not triggered,
385
+ // so we have to resolve manually:
386
+ deferred.resolveWith(node);
387
+ }
388
+ },
389
+ {
390
+ maxWidth: options.previewMaxWidth,
391
+ maxHeight: options.previewMaxHeight,
392
+ canvas: options.previewAsCanvas
393
+ }
394
+ )) || deferred.resolveWith(node)) && deferred;
395
+ },
396
+
397
+ _renderPreviews: function (files, nodes) {
398
+ var that = this,
399
+ options = this.options;
400
+ nodes.find('.preview span').each(function (index, element) {
401
+ var file = files[index];
402
+ if (options.previewSourceFileTypes.test(file.type) &&
403
+ ($.type(options.previewSourceMaxFileSize) !== 'number' ||
404
+ file.size < options.previewSourceMaxFileSize)) {
405
+ that._processingQueue = that._processingQueue.pipe(function () {
406
+ var deferred = $.Deferred();
407
+ that._renderPreview(file, $(element)).done(
408
+ function () {
409
+ deferred.resolveWith(that);
410
+ }
411
+ );
412
+ return deferred.promise();
413
+ });
414
+ }
415
+ });
416
+ return this._processingQueue;
417
+ },
418
+
419
+ _renderUpload: function (files) {
420
+ return this._renderTemplate(
421
+ this.options.uploadTemplate,
422
+ files
423
+ );
424
+ },
425
+
426
+ _renderDownload: function (files) {
427
+ return this._renderTemplate(
428
+ this.options.downloadTemplate,
429
+ files
430
+ ).find('a[download]').each(this._enableDragToDesktop).end();
431
+ },
432
+
433
+ _startHandler: function (e) {
434
+ e.preventDefault();
435
+ var button = $(this),
436
+ template = button.closest('.template-upload'),
437
+ data = template.data('data');
438
+ if (data && data.submit && !data.jqXHR && data.submit()) {
439
+ button.prop('disabled', true);
440
+ }
441
+ },
442
+
443
+ _cancelHandler: function (e) {
444
+ e.preventDefault();
445
+ var template = $(this).closest('.template-upload'),
446
+ data = template.data('data') || {};
447
+ if (!data.jqXHR) {
448
+ data.errorThrown = 'abort';
449
+ e.data.fileupload._trigger('fail', e, data);
450
+ } else {
451
+ data.jqXHR.abort();
452
+ }
453
+ },
454
+
455
+ _deleteHandler: function (e) {
456
+ e.preventDefault();
457
+ var button = $(this);
458
+ e.data.fileupload._trigger('destroy', e, {
459
+ context: button.closest('.template-download'),
460
+ url: button.attr('data-url'),
461
+ type: button.attr('data-type') || 'DELETE',
462
+ dataType: e.data.fileupload.options.dataType
463
+ });
464
+ },
465
+
466
+ _forceReflow: function (node) {
467
+ this._reflow = $.support.transition &&
468
+ node.length && node[0].offsetWidth;
469
+ },
470
+
471
+ _transition: function (node) {
472
+ var that = this,
473
+ deferred = $.Deferred();
474
+ if ($.support.transition && node.hasClass('fade')) {
475
+ node.bind(
476
+ $.support.transition.end,
477
+ function (e) {
478
+ // Make sure we don't respond to other transitions events
479
+ // in the container element, e.g. from button elements:
480
+ if (e.target === node[0]) {
481
+ node.unbind($.support.transition.end);
482
+ deferred.resolveWith(node);
483
+ }
484
+ }
485
+ ).toggleClass('in');
486
+ } else {
487
+ node.toggleClass('in');
488
+ deferred.resolveWith(node);
489
+ }
490
+ return deferred;
491
+ },
492
+
493
+ _initButtonBarEventHandlers: function () {
494
+ var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
495
+ filesList = this.options.filesContainer,
496
+ ns = this.options.namespace;
497
+ fileUploadButtonBar.find('.start')
498
+ .bind('click.' + ns, function (e) {
499
+ e.preventDefault();
500
+ filesList.find('.start button').click();
501
+ });
502
+ fileUploadButtonBar.find('.cancel')
503
+ .bind('click.' + ns, function (e) {
504
+ e.preventDefault();
505
+ filesList.find('.cancel button').click();
506
+ });
507
+ fileUploadButtonBar.find('.delete')
508
+ .bind('click.' + ns, function (e) {
509
+ e.preventDefault();
510
+ filesList.find('.delete input:checked')
511
+ .siblings('button').click();
512
+ fileUploadButtonBar.find('.toggle')
513
+ .prop('checked', false);
514
+ });
515
+ fileUploadButtonBar.find('.toggle')
516
+ .bind('change.' + ns, function (e) {
517
+ filesList.find('.delete input').prop(
518
+ 'checked',
519
+ $(this).is(':checked')
520
+ );
521
+ });
522
+ },
523
+
524
+ _destroyButtonBarEventHandlers: function () {
525
+ this.element.find('.fileupload-buttonbar button')
526
+ .unbind('click.' + this.options.namespace);
527
+ this.element.find('.fileupload-buttonbar .toggle')
528
+ .unbind('change.' + this.options.namespace);
529
+ },
530
+
531
+ _initEventHandlers: function () {
532
+ parentWidget.prototype._initEventHandlers.call(this);
533
+ var eventData = {fileupload: this};
534
+ this.options.filesContainer
535
+ .delegate(
536
+ '.start button',
537
+ 'click.' + this.options.namespace,
538
+ eventData,
539
+ this._startHandler
540
+ )
541
+ .delegate(
542
+ '.cancel a',
543
+ 'click.' + this.options.namespace,
544
+ eventData,
545
+ this._cancelHandler
546
+ )
547
+ .delegate(
548
+ '.delete a',
549
+ 'click.' + this.options.namespace,
550
+ eventData,
551
+ this._deleteHandler
552
+ );
553
+ this._initButtonBarEventHandlers();
554
+ },
555
+
556
+ _destroyEventHandlers: function () {
557
+ var options = this.options;
558
+ this._destroyButtonBarEventHandlers();
559
+ options.filesContainer
560
+ .undelegate('.start button', 'click.' + options.namespace)
561
+ .undelegate('.cancel a', 'click.' + options.namespace)
562
+ .undelegate('.delete a', 'click.' + options.namespace);
563
+ parentWidget.prototype._destroyEventHandlers.call(this);
564
+ },
565
+
566
+ _enableFileInputButton: function () {
567
+ this.element.find('.fileinput-button input')
568
+ .prop('disabled', false)
569
+ .parent().removeClass('disabled');
570
+ },
571
+
572
+ _disableFileInputButton: function () {
573
+ this.element.find('.fileinput-button input')
574
+ .prop('disabled', true)
575
+ .parent().addClass('disabled');
576
+ },
577
+
578
+ _initTemplates: function () {
579
+ var options = this.options;
580
+ options.templatesContainer = document.createElement(
581
+ options.filesContainer.prop('nodeName')
582
+ );
583
+ if (tmpl) {
584
+ if (options.uploadTemplateId) {
585
+ options.uploadTemplate = tmpl(options.uploadTemplateId);
586
+ }
587
+ if (options.downloadTemplateId) {
588
+ options.downloadTemplate = tmpl(options.downloadTemplateId);
589
+ }
590
+ }
591
+ },
592
+
593
+ _initFilesContainer: function () {
594
+ var options = this.options;
595
+ if (options.filesContainer === undefined) {
596
+ options.filesContainer = this.element.find('.files');
597
+ } else if (!(options.filesContainer instanceof $)) {
598
+ options.filesContainer = $(options.filesContainer);
599
+ }
600
+ },
601
+
602
+ _initSpecialOptions: function () {
603
+ parentWidget.prototype._initSpecialOptions.call(this);
604
+ this._initFilesContainer();
605
+ this._initTemplates();
606
+ },
607
+
608
+ _create: function () {
609
+ parentWidget.prototype._create.call(this);
610
+ this._refreshOptionsList.push(
611
+ 'filesContainer',
612
+ 'uploadTemplateId',
613
+ 'downloadTemplateId'
614
+ );
615
+ if (!$.blueimpIP) {
616
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
617
+ this.resize = function () {
618
+ return this._processingQueue;
619
+ };
620
+ }
621
+ },
622
+
623
+ enable: function () {
624
+ parentWidget.prototype.enable.call(this);
625
+ this.element.find('input, button').prop('disabled', false);
626
+ this._enableFileInputButton();
627
+ },
628
+
629
+ disable: function () {
630
+ this.element.find('input, button').prop('disabled', true);
631
+ this._disableFileInputButton();
632
+ parentWidget.prototype.disable.call(this);
633
+ }
634
+
635
+ });
636
+
637
+ }));