jquery.fileupload-ui.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*
  2. * jQuery File Upload User Interface Plugin 9.6.1
  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. /* jshint nomen:false */
  12. /* global define, require, window */
  13. (function (factory) {
  14. 'use strict';
  15. if (typeof define === 'function' && define.amd) {
  16. // Register as an anonymous AMD module:
  17. define([
  18. 'jquery',
  19. 'tmpl',
  20. './jquery.fileupload-image',
  21. './jquery.fileupload-audio',
  22. './jquery.fileupload-video',
  23. './jquery.fileupload-validate'
  24. ], factory);
  25. } else if (typeof exports === 'object') {
  26. // Node/CommonJS:
  27. factory(
  28. require('jquery'),
  29. require('tmpl')
  30. );
  31. } else {
  32. // Browser globals:
  33. factory(
  34. window.jQuery,
  35. window.tmpl
  36. );
  37. }
  38. }(function ($, tmpl) {
  39. 'use strict';
  40. $.blueimp.fileupload.prototype._specialOptions.push(
  41. 'filesContainer',
  42. 'uploadTemplateId',
  43. 'downloadTemplateId'
  44. );
  45. // The UI version extends the file upload widget
  46. // and adds complete user interface interaction:
  47. $.widget('blueimp.fileupload', $.blueimp.fileupload, {
  48. options: {
  49. // By default, files added to the widget are uploaded as soon
  50. // as the user clicks on the start buttons. To enable automatic
  51. // uploads, set the following option to true:
  52. autoUpload: false,
  53. // The ID of the upload template:
  54. uploadTemplateId: 'template-upload',
  55. // The ID of the download template:
  56. downloadTemplateId: 'template-download',
  57. // The container for the list of files. If undefined, it is set to
  58. // an element with class "files" inside of the widget element:
  59. filesContainer: undefined,
  60. // By default, files are appended to the files container.
  61. // Set the following option to true, to prepend files instead:
  62. prependFiles: false,
  63. // The expected data type of the upload response, sets the dataType
  64. // option of the $.ajax upload requests:
  65. dataType: 'json',
  66. // Error and info messages:
  67. messages: {
  68. unknownError: 'Unknown error'
  69. },
  70. // Function returning the current number of files,
  71. // used by the maxNumberOfFiles validation:
  72. getNumberOfFiles: function () {
  73. return this.filesContainer.children()
  74. .not('.processing').length;
  75. },
  76. // Callback to retrieve the list of files from the server response:
  77. getFilesFromResponse: function (data) {
  78. if (data.result && $.isArray(data.result.files)) {
  79. return data.result.files;
  80. }
  81. return [];
  82. },
  83. // The add callback is invoked as soon as files are added to the fileupload
  84. // widget (via file input selection, drag & drop or add API call).
  85. // See the basic file upload widget for more information:
  86. add: function (e, data) {
  87. if (e.isDefaultPrevented()) {
  88. return false;
  89. }
  90. //添加文件的时候需要检查当前的文件筐中是否有文件
  91. //添加的逻辑是向文件筐中加文件,所以肯定需要去掉暂无文件的提示
  92. $(".noFileWarning").hide();
  93. var $this = $(this),
  94. that = $this.data('blueimp-fileupload') ||
  95. $this.data('fileupload'),
  96. options = that.options;
  97. data.context = that._renderUpload(data.files)
  98. .data('data', data)
  99. .addClass('processing');
  100. options.filesContainer[
  101. options.prependFiles ? 'prepend' : 'append'
  102. ](data.context);
  103. that._forceReflow(data.context);
  104. that._transition(data.context);
  105. data.process(function () {
  106. return $this.fileupload('process', data);
  107. }).always(function () {
  108. data.context.each(function (index) {
  109. $(this).find('.size').text(
  110. that._formatFileSize(data.files[index].size)
  111. );
  112. }).removeClass('processing');
  113. that._renderPreviews(data);
  114. }).done(function () {
  115. data.context.find('.start').prop('disabled', false);
  116. if ((that._trigger('added', e, data) !== false) &&
  117. (options.autoUpload || data.autoUpload) &&
  118. data.autoUpload !== false) {
  119. data.submit();
  120. }
  121. }).fail(function () {
  122. if (data.files.error) {
  123. data.context.each(function (index) {
  124. var error = data.files[index].error;
  125. if (error) {
  126. $(this).find('.error').text(error);
  127. }
  128. });
  129. }
  130. });
  131. },
  132. // Callback for the start of each file upload request:
  133. send: function (e, data) {
  134. if (e.isDefaultPrevented()) {
  135. return false;
  136. }
  137. var that = $(this).data('blueimp-fileupload') ||
  138. $(this).data('fileupload');
  139. if (data.context && data.dataType &&
  140. data.dataType.substr(0, 6) === 'iframe') {
  141. // Iframe Transport does not support progress events.
  142. // In lack of an indeterminate progress bar, we set
  143. // the progress to 100%, showing the full animated bar:
  144. data.context
  145. .find('.progress').addClass(
  146. !$.support.transition && 'progress-animated'
  147. )
  148. .attr('aria-valuenow', 100)
  149. .children().first().css(
  150. 'width',
  151. '100%'
  152. );
  153. }
  154. return that._trigger('sent', e, data);
  155. },
  156. // Callback for successful uploads:
  157. done: function (e, data) {
  158. if (e.isDefaultPrevented()) {
  159. return false;
  160. }
  161. var that = $(this).data('blueimp-fileupload') ||
  162. $(this).data('fileupload'),
  163. getFilesFromResponse = data.getFilesFromResponse ||
  164. that.options.getFilesFromResponse,
  165. files = getFilesFromResponse(data),
  166. template,
  167. deferred;
  168. if (data.context) {
  169. data.context.each(function (index) {
  170. var file = files[index] ||
  171. {error: 'Empty file upload result'};
  172. deferred = that._addFinishedDeferreds();
  173. that._transition($(this)).done(
  174. function () {
  175. var node = $(this);
  176. template = that._renderDownload([file])
  177. .replaceAll(node);
  178. that._forceReflow(template);
  179. that._transition(template).done(
  180. function () {
  181. data.context = $(this);
  182. that._trigger('completed', e, data);
  183. that._trigger('finished', e, data);
  184. deferred.resolve();
  185. }
  186. );
  187. }
  188. );
  189. });
  190. } else {
  191. template = that._renderDownload(files)[
  192. that.options.prependFiles ? 'prependTo' : 'appendTo'
  193. ](that.options.filesContainer);
  194. that._forceReflow(template);
  195. deferred = that._addFinishedDeferreds();
  196. that._transition(template).done(
  197. function () {
  198. data.context = $(this);
  199. that._trigger('completed', e, data);
  200. that._trigger('finished', e, data);
  201. deferred.resolve();
  202. }
  203. );
  204. }
  205. },
  206. // Callback for failed (abort or error) uploads:
  207. fail: function (e, data) {
  208. if (e.isDefaultPrevented()) {
  209. return false;
  210. }
  211. var that = $(this).data('blueimp-fileupload') ||
  212. $(this).data('fileupload'),
  213. template,
  214. deferred;
  215. if (data.context) {
  216. data.context.each(function (index) {
  217. if (data.errorThrown !== 'abort') {
  218. var file = data.files[index];
  219. file.error = file.error || data.errorThrown ||
  220. data.i18n('unknownError');
  221. deferred = that._addFinishedDeferreds();
  222. that._transition($(this)).done(
  223. function () {
  224. var node = $(this);
  225. template = that._renderDownload([file])
  226. .replaceAll(node);
  227. that._forceReflow(template);
  228. that._transition(template).done(
  229. function () {
  230. data.context = $(this);
  231. that._trigger('failed', e, data);
  232. that._trigger('finished', e, data);
  233. deferred.resolve();
  234. }
  235. );
  236. }
  237. );
  238. } else {
  239. deferred = that._addFinishedDeferreds();
  240. that._transition($(this)).done(
  241. function () {
  242. $(this).remove();
  243. that._trigger('failed', e, data);
  244. that._trigger('finished', e, data);
  245. deferred.resolve();
  246. }
  247. );
  248. }
  249. });
  250. } else if (data.errorThrown !== 'abort') {
  251. data.context = that._renderUpload(data.files)[
  252. that.options.prependFiles ? 'prependTo' : 'appendTo'
  253. ](that.options.filesContainer)
  254. .data('data', data);
  255. that._forceReflow(data.context);
  256. deferred = that._addFinishedDeferreds();
  257. that._transition(data.context).done(
  258. function () {
  259. data.context = $(this);
  260. that._trigger('failed', e, data);
  261. that._trigger('finished', e, data);
  262. deferred.resolve();
  263. }
  264. );
  265. } else {
  266. that._trigger('failed', e, data);
  267. that._trigger('finished', e, data);
  268. that._addFinishedDeferreds().resolve();
  269. }
  270. },
  271. // Callback for upload progress events:
  272. progress: function (e, data) {
  273. if (e.isDefaultPrevented()) {
  274. return false;
  275. }
  276. var progress = Math.floor(data.loaded / data.total * 100);
  277. if (data.context) {
  278. data.context.each(function () {
  279. $(this).find('.progress')
  280. .attr('aria-valuenow', progress)
  281. .children().first().css(
  282. 'width',
  283. progress + '%'
  284. );
  285. });
  286. }
  287. },
  288. // Callback for global upload progress events:
  289. progressall: function (e, data) {
  290. if (e.isDefaultPrevented()) {
  291. return false;
  292. }
  293. var $this = $(this),
  294. progress = Math.floor(data.loaded / data.total * 100),
  295. globalProgressNode = $this.find('.fileupload-progress'),
  296. extendedProgressNode = globalProgressNode
  297. .find('.progress-extended');
  298. if (extendedProgressNode.length) {
  299. extendedProgressNode.html(
  300. ($this.data('blueimp-fileupload') || $this.data('fileupload'))
  301. ._renderExtendedProgress(data)
  302. );
  303. }
  304. globalProgressNode
  305. .find('.progress')
  306. .attr('aria-valuenow', progress)
  307. .children().first().css(
  308. 'width',
  309. progress + '%'
  310. );
  311. },
  312. // Callback for uploads start, equivalent to the global ajaxStart event:
  313. start: function (e) {
  314. if (e.isDefaultPrevented()) {
  315. return false;
  316. }
  317. var that = $(this).data('blueimp-fileupload') ||
  318. $(this).data('fileupload');
  319. that._resetFinishedDeferreds();
  320. that._transition($(this).find('.fileupload-progress')).done(
  321. function () {
  322. that._trigger('started', e);
  323. }
  324. );
  325. },
  326. // Callback for uploads stop, equivalent to the global ajaxStop event:
  327. stop: function (e) {
  328. if (e.isDefaultPrevented()) {
  329. return false;
  330. }
  331. var that = $(this).data('blueimp-fileupload') ||
  332. $(this).data('fileupload'),
  333. deferred = that._addFinishedDeferreds();
  334. $.when.apply($, that._getFinishedDeferreds())
  335. .done(function () {
  336. that._trigger('stopped', e);
  337. });
  338. that._transition($(this).find('.fileupload-progress')).done(
  339. function () {
  340. $(this).find('.progress')
  341. .attr('aria-valuenow', '0')
  342. .children().first().css('width', '0%');
  343. $(this).find('.progress-extended').html(' ');
  344. deferred.resolve();
  345. }
  346. );
  347. },
  348. processstart: function (e) {
  349. if (e.isDefaultPrevented()) {
  350. return false;
  351. }
  352. $(this).addClass('fileupload-processing');
  353. },
  354. processstop: function (e) {
  355. if (e.isDefaultPrevented()) {
  356. return false;
  357. }
  358. $(this).removeClass('fileupload-processing');
  359. },
  360. // Callback for file deletion:
  361. destroy: function (e, data) {
  362. if (e.isDefaultPrevented()) {
  363. return false;
  364. }
  365. var that = $(this).data('blueimp-fileupload') ||
  366. $(this).data('fileupload'),
  367. removeNode = function () {
  368. that._transition(data.context).done(
  369. function () {
  370. $(this).remove();
  371. that._trigger('destroyed', e, data);
  372. }
  373. );
  374. };
  375. if (data.url) {
  376. data.dataType = data.dataType || that.options.dataType;
  377. $.ajax(data).done(removeNode).fail(function () {
  378. that._trigger('destroyfailed', e, data);
  379. });
  380. } else {
  381. removeNode();
  382. }
  383. }
  384. },
  385. _resetFinishedDeferreds: function () {
  386. this._finishedUploads = [];
  387. },
  388. _addFinishedDeferreds: function (deferred) {
  389. if (!deferred) {
  390. deferred = $.Deferred();
  391. }
  392. this._finishedUploads.push(deferred);
  393. return deferred;
  394. },
  395. _getFinishedDeferreds: function () {
  396. return this._finishedUploads;
  397. },
  398. // Link handler, that allows to download files
  399. // by drag & drop of the links to the desktop:
  400. _enableDragToDesktop: function () {
  401. var link = $(this),
  402. url = link.prop('href'),
  403. name = link.prop('download'),
  404. type = 'application/octet-stream';
  405. link.bind('dragstart', function (e) {
  406. try {
  407. e.originalEvent.dataTransfer.setData(
  408. 'DownloadURL',
  409. [type, name, url].join(':')
  410. );
  411. } catch (ignore) {
  412. }
  413. });
  414. },
  415. _formatFileSize: function (bytes) {
  416. if (typeof bytes !== 'number') {
  417. return '';
  418. }
  419. if (bytes >= 1000000000) {
  420. return (bytes / 1000000000).toFixed(2) + ' GB';
  421. }
  422. if (bytes >= 1000000) {
  423. return (bytes / 1000000).toFixed(2) + ' MB';
  424. }
  425. return (bytes / 1000).toFixed(2) + ' KB';
  426. },
  427. _formatBitrate: function (bits) {
  428. if (typeof bits !== 'number') {
  429. return '';
  430. }
  431. if (bits >= 1000000000) {
  432. return (bits / 1000000000).toFixed(2) + ' Gbit/s';
  433. }
  434. if (bits >= 1000000) {
  435. return (bits / 1000000).toFixed(2) + ' Mbit/s';
  436. }
  437. if (bits >= 1000) {
  438. return (bits / 1000).toFixed(2) + ' kbit/s';
  439. }
  440. return bits.toFixed(2) + ' bit/s';
  441. },
  442. _formatTime: function (seconds) {
  443. var date = new Date(seconds * 1000),
  444. days = Math.floor(seconds / 86400);
  445. days = days ? days + 'd ' : '';
  446. return days +
  447. ('0' + date.getUTCHours()).slice(-2) + ':' +
  448. ('0' + date.getUTCMinutes()).slice(-2) + ':' +
  449. ('0' + date.getUTCSeconds()).slice(-2);
  450. },
  451. _formatPercentage: function (floatValue) {
  452. return (floatValue * 100).toFixed(2) + ' %';
  453. },
  454. _renderExtendedProgress: function (data) {
  455. return this._formatBitrate(data.bitrate) + ' | ' +
  456. this._formatTime(
  457. (data.total - data.loaded) * 8 / data.bitrate
  458. ) + ' | ' +
  459. this._formatPercentage(
  460. data.loaded / data.total
  461. ) + ' | ' +
  462. this._formatFileSize(data.loaded) + ' / ' +
  463. this._formatFileSize(data.total);
  464. },
  465. _renderTemplate: function (func, files) {
  466. if (!func) {
  467. return $();
  468. }
  469. var result = func({
  470. files: files,
  471. formatFileSize: this._formatFileSize,
  472. options: this.options
  473. });
  474. if (result instanceof $) {
  475. return result;
  476. }
  477. return $(this.options.templatesContainer).html(result).children();
  478. },
  479. _renderPreviews: function (data) {
  480. data.context.find('.preview').each(function (index, elm) {
  481. $(elm).append(data.files[index].preview);
  482. });
  483. },
  484. _renderUpload: function (files) {
  485. return this._renderTemplate(
  486. this.options.uploadTemplate,
  487. files
  488. );
  489. },
  490. _renderDownload: function (files) {
  491. return this._renderTemplate(
  492. this.options.downloadTemplate,
  493. files
  494. ).find('a[download]').each(this._enableDragToDesktop).end();
  495. },
  496. _startHandler: function (e) {
  497. e.preventDefault();
  498. var button = $(e.currentTarget),
  499. template = button.closest('.template-upload'),
  500. data = template.data('data');
  501. button.prop('disabled', true);
  502. if (data && data.submit) {
  503. data.submit();
  504. }
  505. },
  506. _cancelHandler: function (e) {
  507. e.preventDefault();
  508. var button = $(e.currentTarget);
  509. //需要在删除的时候与angular内保存上传成功文件信息是数组做交互
  510. var fileName = button.parents(".template-download").find(".name span").html();
  511. var newAngularArray = [];
  512. angular.element(document.body).scope().ctl.finishUploadArray.forEach(function (item, index) {
  513. if (item.FILESNAME != fileName) {
  514. newAngularArray.push(item);
  515. }
  516. })
  517. angular.element(document.body).scope().ctl.finishUploadArray = newAngularArray;
  518. angular.element(document.body).scope().$apply();
  519. console.log(angular.element(document.body).scope().ctl.finishUploadArray);
  520. var template = $(e.currentTarget)
  521. .closest('.template-upload,.template-download'),
  522. data = template.data('data') || {};
  523. data.context = data.context || template;
  524. if (data.abort) {
  525. data.abort();
  526. } else {
  527. data.errorThrown = 'abort';
  528. this._trigger('fail', e, data);
  529. }
  530. //取消之后也需要查看文件框中是否还有文件,没有文件的话打开暂无文件的提示、
  531. setTimeout(function () {
  532. var uploadNum = $(".fileList .template-upload").length;
  533. var downloadNum = $(".fileList .template-download").length;
  534. if (uploadNum == 0 && downloadNum == 0) {
  535. $(".noFileWarning").show();
  536. }
  537. }, 200)
  538. },
  539. _deleteHandler: function (e) {
  540. e.preventDefault();
  541. var button = $(e.currentTarget);
  542. //需要在删除的时候与angular内保存上传成功文件信息是数组做交互
  543. var fileName = button.parents(".template-download").find(".name span").html();
  544. var newAngularArray = [];
  545. angular.element(document.body).scope().ctl.finishUploadArray.forEach(function (item, index) {
  546. if (item.FILESNAME != fileName) {
  547. newAngularArray.push(item);
  548. }
  549. })
  550. angular.element(document.body).scope().ctl.finishUploadArray = newAngularArray;
  551. angular.element(document.body).scope().$apply();
  552. this._trigger('destroy', e, $.extend({
  553. context: button.closest('.template-download'),
  554. type: 'DELETE'
  555. }, button.data()));
  556. //取消之后也需要查看文件框中是否还有文件,没有文件的话打开暂无文件的提示、
  557. setTimeout(function () {
  558. var uploadNum = $(".fileList .template-upload").length;
  559. var downloadNum = $(".fileList .template-download").length;
  560. if (uploadNum == 0 && downloadNum == 0) {
  561. $(".noFileWarning").show();
  562. }
  563. }, 1000)
  564. },
  565. _forceReflow: function (node) {
  566. return $.support.transition && node.length &&
  567. node[0].offsetWidth;
  568. },
  569. _transition: function (node) {
  570. var dfd = $.Deferred();
  571. if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
  572. node.bind(
  573. $.support.transition.end,
  574. function (e) {
  575. // Make sure we don't respond to other transitions events
  576. // in the container element, e.g. from button elements:
  577. if (e.target === node[0]) {
  578. node.unbind($.support.transition.end);
  579. dfd.resolveWith(node);
  580. }
  581. }
  582. ).toggleClass('in');
  583. } else {
  584. node.toggleClass('in');
  585. dfd.resolveWith(node);
  586. }
  587. return dfd;
  588. },
  589. _initButtonBarEventHandlers: function () {
  590. var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
  591. filesList = this.options.filesContainer;
  592. this._on(fileUploadButtonBar.find('.start'), {
  593. click: function (e) {
  594. e.preventDefault();
  595. filesList.find('.start').click();
  596. }
  597. });
  598. this._on(fileUploadButtonBar.find('.cancel'), {
  599. click: function (e) {
  600. e.preventDefault();
  601. filesList.find('.cancel').click();
  602. }
  603. });
  604. this._on(fileUploadButtonBar.find('.delete'), {
  605. click: function (e) {
  606. e.preventDefault();
  607. filesList.find('.toggle:checked')
  608. .closest('.template-download')
  609. .find('.delete').click();
  610. fileUploadButtonBar.find('.toggle')
  611. .prop('checked', false);
  612. }
  613. });
  614. this._on(fileUploadButtonBar.find('.toggle'), {
  615. change: function (e) {
  616. filesList.find('.toggle').prop(
  617. 'checked',
  618. $(e.currentTarget).is(':checked')
  619. );
  620. }
  621. });
  622. },
  623. _destroyButtonBarEventHandlers: function () {
  624. this._off(
  625. this.element.find('.fileupload-buttonbar')
  626. .find('.start, .cancel, .delete'),
  627. 'click'
  628. );
  629. this._off(
  630. this.element.find('.fileupload-buttonbar .toggle'),
  631. 'change.'
  632. );
  633. },
  634. _initEventHandlers: function () {
  635. this._super();
  636. this._on(this.options.filesContainer, {
  637. 'click .start': this._startHandler,
  638. 'click .cancel': this._cancelHandler,
  639. 'click .delete': this._deleteHandler
  640. });
  641. this._initButtonBarEventHandlers();
  642. },
  643. _destroyEventHandlers: function () {
  644. this._destroyButtonBarEventHandlers();
  645. this._off(this.options.filesContainer, 'click');
  646. this._super();
  647. },
  648. _enableFileInputButton: function () {
  649. this.element.find('.fileinput-button input')
  650. .prop('disabled', false)
  651. .parent().removeClass('disabled');
  652. },
  653. _disableFileInputButton: function () {
  654. this.element.find('.fileinput-button input')
  655. .prop('disabled', true)
  656. .parent().addClass('disabled');
  657. },
  658. _initTemplates: function () {
  659. var options = this.options;
  660. options.templatesContainer = this.document[0].createElement(
  661. options.filesContainer.prop('nodeName')
  662. );
  663. if (tmpl) {
  664. if (options.uploadTemplateId) {
  665. options.uploadTemplate = tmpl(options.uploadTemplateId);
  666. }
  667. if (options.downloadTemplateId) {
  668. options.downloadTemplate = tmpl(options.downloadTemplateId);
  669. }
  670. }
  671. },
  672. _initFilesContainer: function () {
  673. var options = this.options;
  674. if (options.filesContainer === undefined) {
  675. options.filesContainer = this.element.find('.files');
  676. } else if (!(options.filesContainer instanceof $)) {
  677. options.filesContainer = $(options.filesContainer);
  678. }
  679. },
  680. _initSpecialOptions: function () {
  681. this._super();
  682. this._initFilesContainer();
  683. this._initTemplates();
  684. },
  685. _create: function () {
  686. this._super();
  687. this._resetFinishedDeferreds();
  688. if (!$.support.fileInput) {
  689. this._disableFileInputButton();
  690. }
  691. },
  692. enable: function () {
  693. var wasDisabled = false;
  694. if (this.options.disabled) {
  695. wasDisabled = true;
  696. }
  697. this._super();
  698. if (wasDisabled) {
  699. this.element.find('input, button').prop('disabled', false);
  700. this._enableFileInputButton();
  701. }
  702. },
  703. disable: function () {
  704. if (!this.options.disabled) {
  705. this.element.find('input, button').prop('disabled', true);
  706. this._disableFileInputButton();
  707. }
  708. this._super();
  709. }
  710. });
  711. }));