jquery.fileupload-ui.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. /*
  2. * jQuery File Upload User Interface Plugin 7.3
  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. /*jslint nomen: true, unparam: true, regexp: true */
  12. /*global define, window, URL, webkitURL, FileReader */
  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. 'load-image',
  21. './jquery.fileupload-fp'
  22. ], factory);
  23. } else {
  24. // Browser globals:
  25. factory(
  26. window.jQuery,
  27. window.tmpl,
  28. window.loadImage
  29. );
  30. }
  31. }(function ($, tmpl, loadImage) {
  32. 'use strict';
  33. // The UI version extends the file upload widget
  34. // and adds complete user interface interaction:
  35. $.widget('blueimp.fileupload', $.blueimp.fileupload, {
  36. options: {
  37. // By default, files added to the widget are uploaded as soon
  38. // as the user clicks on the start buttons. To enable automatic
  39. // uploads, set the following option to true:
  40. autoUpload: false,
  41. // The following option limits the number of files that are
  42. // allowed to be uploaded using this widget:
  43. maxNumberOfFiles: undefined,
  44. // The maximum allowed file size:
  45. maxFileSize: undefined,
  46. // The minimum allowed file size:
  47. minFileSize: undefined,
  48. // The regular expression for allowed file types, matches
  49. // against either file type or file name:
  50. acceptFileTypes: /.+$/i,
  51. // The regular expression to define for which files a preview
  52. // image is shown, matched against the file type:
  53. previewSourceFileTypes: /^image\/(gif|jpeg|png)$/,
  54. // The maximum file size of images that are to be displayed as preview:
  55. previewSourceMaxFileSize: 5000000, // 5MB
  56. // The maximum width of the preview images:
  57. previewMaxWidth: 80,
  58. // The maximum height of the preview images:
  59. previewMaxHeight: 80,
  60. // By default, preview images are displayed as canvas elements
  61. // if supported by the browser. Set the following option to false
  62. // to always display preview images as img elements:
  63. previewAsCanvas: true,
  64. // The ID of the upload template:
  65. uploadTemplateId: 'template-upload',
  66. // The ID of the download template:
  67. downloadTemplateId: 'template-download',
  68. // The container for the list of files. If undefined, it is set to
  69. // an element with class "files" inside of the widget element:
  70. filesContainer: undefined,
  71. // By default, files are appended to the files container.
  72. // Set the following option to true, to prepend files instead:
  73. prependFiles: false,
  74. // The expected data type of the upload response, sets the dataType
  75. // option of the $.ajax upload requests:
  76. dataType: 'json',
  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('blueimp-fileupload') ||
  82. $(this).data('fileupload'),
  83. options = that.options,
  84. files = data.files;
  85. $(this).fileupload('process', data).done(function () {
  86. that._adjustMaxNumberOfFiles(-files.length);
  87. data.maxNumberOfFilesAdjusted = true;
  88. data.files.valid = data.isValidated = that._validate(files);
  89. data.context = that._renderUpload(files).data('data', data);
  90. options.filesContainer[
  91. options.prependFiles ? 'prepend' : 'append'
  92. ](data.context);
  93. that._renderPreviews(data);
  94. that._forceReflow(data.context);
  95. that._transition(data.context).done(
  96. function () {
  97. if ((that._trigger('added', e, data) !== false) &&
  98. (options.autoUpload || data.autoUpload) &&
  99. data.autoUpload !== false && data.isValidated) {
  100. data.submit();
  101. }
  102. }
  103. );
  104. });
  105. },
  106. // Callback for the start of each file upload request:
  107. send: function (e, data) {
  108. var that = $(this).data('blueimp-fileupload') ||
  109. $(this).data('fileupload');
  110. if (!data.isValidated) {
  111. if (!data.maxNumberOfFilesAdjusted) {
  112. that._adjustMaxNumberOfFiles(-data.files.length);
  113. data.maxNumberOfFilesAdjusted = true;
  114. }
  115. if (!that._validate(data.files)) {
  116. return false;
  117. }
  118. }
  119. if (data.context && data.dataType &&
  120. data.dataType.substr(0, 6) === 'iframe') {
  121. // Iframe Transport does not support progress events.
  122. // In lack of an indeterminate progress bar, we set
  123. // the progress to 100%, showing the full animated bar:
  124. data.context
  125. .find('.progress').addClass(
  126. !$.support.transition && 'progress-animated'
  127. )
  128. .attr('aria-valuenow', 100)
  129. .find('.bar').css(
  130. 'width',
  131. '100%'
  132. );
  133. }
  134. return that._trigger('sent', e, data);
  135. },
  136. // Callback for successful uploads:
  137. done: function (e, data) {
  138. var that = $(this).data('blueimp-fileupload') ||
  139. $(this).data('fileupload'),
  140. files = that._getFilesFromResponse(data),
  141. template,
  142. deferred;
  143. if (data.context) {
  144. data.context.each(function (index) {
  145. var file = files[index] ||
  146. {error: 'Empty file upload result'},
  147. deferred = that._addFinishedDeferreds();
  148. if (file.error) {
  149. that._adjustMaxNumberOfFiles(1);
  150. }
  151. that._transition($(this)).done(
  152. function () {
  153. var node = $(this);
  154. template = that._renderDownload([file])
  155. .replaceAll(node);
  156. that._forceReflow(template);
  157. that._transition(template).done(
  158. function () {
  159. data.context = $(this);
  160. that._trigger('completed', e, data);
  161. that._trigger('finished', e, data);
  162. deferred.resolve();
  163. App.initFancybox(); //added by keenthemes
  164. App.initUniform('.fileupload-checkbox'); //added by keenthemes
  165. }
  166. );
  167. }
  168. );
  169. });
  170. } else {
  171. if (files.length) {
  172. $.each(files, function (index, file) {
  173. if (data.maxNumberOfFilesAdjusted && file.error) {
  174. that._adjustMaxNumberOfFiles(1);
  175. } else if (!data.maxNumberOfFilesAdjusted &&
  176. !file.error) {
  177. that._adjustMaxNumberOfFiles(-1);
  178. }
  179. });
  180. data.maxNumberOfFilesAdjusted = true;
  181. }
  182. template = that._renderDownload(files)
  183. .appendTo(that.options.filesContainer);
  184. that._forceReflow(template);
  185. deferred = that._addFinishedDeferreds();
  186. that._transition(template).done(
  187. function () {
  188. data.context = $(this);
  189. that._trigger('completed', e, data);
  190. that._trigger('finished', e, data);
  191. deferred.resolve();
  192. App.initFancybox(); //added by keenthemes
  193. App.initUniform('.fileupload-checkbox'); //added by keenthemes
  194. }
  195. );
  196. }
  197. },
  198. // Callback for failed (abort or error) uploads:
  199. fail: function (e, data) {
  200. var that = $(this).data('blueimp-fileupload') ||
  201. $(this).data('fileupload'),
  202. template,
  203. deferred;
  204. if (data.maxNumberOfFilesAdjusted) {
  205. that._adjustMaxNumberOfFiles(data.files.length);
  206. }
  207. if (data.context) {
  208. data.context.each(function (index) {
  209. if (data.errorThrown !== 'abort') {
  210. var file = data.files[index];
  211. file.error = file.error || data.errorThrown ||
  212. true;
  213. deferred = that._addFinishedDeferreds();
  214. that._transition($(this)).done(
  215. function () {
  216. var node = $(this);
  217. template = that._renderDownload([file])
  218. .replaceAll(node);
  219. that._forceReflow(template);
  220. that._transition(template).done(
  221. function () {
  222. data.context = $(this);
  223. that._trigger('failed', e, data);
  224. that._trigger('finished', e, data);
  225. deferred.resolve();
  226. App.initFancybox(); //added by keenthemes
  227. App.initUniform('.fileupload-checkbox'); //added by keenthemes
  228. }
  229. );
  230. }
  231. );
  232. } else {
  233. deferred = that._addFinishedDeferreds();
  234. that._transition($(this)).done(
  235. function () {
  236. $(this).remove();
  237. that._trigger('failed', e, data);
  238. that._trigger('finished', e, data);
  239. deferred.resolve();
  240. App.initFancybox(); //added by keenthemes
  241. App.initUniform('.fileupload-checkbox'); //added by keenthemes
  242. }
  243. );
  244. }
  245. });
  246. } else if (data.errorThrown !== 'abort') {
  247. data.context = that._renderUpload(data.files)
  248. .appendTo(that.options.filesContainer)
  249. .data('data', data);
  250. that._forceReflow(data.context);
  251. deferred = that._addFinishedDeferreds();
  252. that._transition(data.context).done(
  253. function () {
  254. data.context = $(this);
  255. that._trigger('failed', e, data);
  256. that._trigger('finished', e, data);
  257. deferred.resolve();
  258. }
  259. );
  260. } else {
  261. that._trigger('failed', e, data);
  262. that._trigger('finished', e, data);
  263. that._addFinishedDeferreds().resolve();
  264. }
  265. },
  266. // Callback for upload progress events:
  267. progress: function (e, data) {
  268. if (data.context) {
  269. var progress = parseInt(data.loaded / data.total * 100, 10);
  270. data.context.find('.progress')
  271. .attr('aria-valuenow', progress)
  272. .find('.bar').css(
  273. 'width',
  274. progress + '%'
  275. );
  276. }
  277. },
  278. // Callback for global upload progress events:
  279. progressall: function (e, data) {
  280. var $this = $(this),
  281. progress = parseInt(data.loaded / data.total * 100, 10),
  282. globalProgressNode = $this.find('.fileupload-progress'),
  283. extendedProgressNode = globalProgressNode
  284. .find('.progress-extended');
  285. if (extendedProgressNode.length) {
  286. extendedProgressNode.html(
  287. ($this.data('blueimp-fileupload') || $this.data('fileupload'))
  288. ._renderExtendedProgress(data)
  289. );
  290. }
  291. globalProgressNode
  292. .find('.progress')
  293. .attr('aria-valuenow', progress)
  294. .find('.bar').css(
  295. 'width',
  296. progress + '%'
  297. );
  298. },
  299. // Callback for uploads start, equivalent to the global ajaxStart event:
  300. start: function (e) {
  301. var that = $(this).data('blueimp-fileupload') ||
  302. $(this).data('fileupload');
  303. that._resetFinishedDeferreds();
  304. that._transition($(this).find('.fileupload-progress')).done(
  305. function () {
  306. that._trigger('started', e);
  307. }
  308. );
  309. },
  310. // Callback for uploads stop, equivalent to the global ajaxStop event:
  311. stop: function (e) {
  312. var that = $(this).data('blueimp-fileupload') ||
  313. $(this).data('fileupload'),
  314. deferred = that._addFinishedDeferreds();
  315. $.when.apply($, that._getFinishedDeferreds())
  316. .done(function () {
  317. that._trigger('stopped', e);
  318. });
  319. that._transition($(this).find('.fileupload-progress')).done(
  320. function () {
  321. $(this).find('.progress')
  322. .attr('aria-valuenow', '0')
  323. .find('.bar').css('width', '0%');
  324. $(this).find('.progress-extended').html(' ');
  325. deferred.resolve();
  326. }
  327. );
  328. },
  329. // Callback for file deletion:
  330. destroy: function (e, data) {
  331. var that = $(this).data('blueimp-fileupload') ||
  332. $(this).data('fileupload');
  333. if (data.url) {
  334. $.ajax(data);
  335. that._adjustMaxNumberOfFiles(1);
  336. }
  337. that._transition(data.context).done(
  338. function () {
  339. $(this).remove();
  340. that._trigger('destroyed', e, data);
  341. }
  342. );
  343. }
  344. },
  345. _resetFinishedDeferreds: function () {
  346. this._finishedUploads = [];
  347. },
  348. _addFinishedDeferreds: function (deferred) {
  349. if (!deferred) {
  350. deferred = $.Deferred();
  351. }
  352. this._finishedUploads.push(deferred);
  353. return deferred;
  354. },
  355. _getFinishedDeferreds: function () {
  356. return this._finishedUploads;
  357. },
  358. _getFilesFromResponse: function (data) {
  359. if (data.result && $.isArray(data.result.files)) {
  360. return data.result.files;
  361. }
  362. return [];
  363. },
  364. // Link handler, that allows to download files
  365. // by drag & drop of the links to the desktop:
  366. _enableDragToDesktop: function () {
  367. var link = $(this),
  368. url = link.prop('href'),
  369. name = link.prop('download'),
  370. type = 'application/octet-stream';
  371. link.bind('dragstart', function (e) {
  372. try {
  373. e.originalEvent.dataTransfer.setData(
  374. 'DownloadURL',
  375. [type, name, url].join(':')
  376. );
  377. } catch (err) {}
  378. });
  379. },
  380. _adjustMaxNumberOfFiles: function (operand) {
  381. if (typeof this.options.maxNumberOfFiles === 'number') {
  382. this.options.maxNumberOfFiles += operand;
  383. if (this.options.maxNumberOfFiles < 1) {
  384. this._disableFileInputButton();
  385. } else {
  386. this._enableFileInputButton();
  387. }
  388. }
  389. },
  390. _formatFileSize: function (bytes) {
  391. if (typeof bytes !== 'number') {
  392. return '';
  393. }
  394. if (bytes >= 1000000000) {
  395. return (bytes / 1000000000).toFixed(2) + ' GB';
  396. }
  397. if (bytes >= 1000000) {
  398. return (bytes / 1000000).toFixed(2) + ' MB';
  399. }
  400. return (bytes / 1000).toFixed(2) + ' KB';
  401. },
  402. _formatBitrate: function (bits) {
  403. if (typeof bits !== 'number') {
  404. return '';
  405. }
  406. if (bits >= 1000000000) {
  407. return (bits / 1000000000).toFixed(2) + ' Gbit/s';
  408. }
  409. if (bits >= 1000000) {
  410. return (bits / 1000000).toFixed(2) + ' Mbit/s';
  411. }
  412. if (bits >= 1000) {
  413. return (bits / 1000).toFixed(2) + ' kbit/s';
  414. }
  415. return bits.toFixed(2) + ' bit/s';
  416. },
  417. _formatTime: function (seconds) {
  418. var date = new Date(seconds * 1000),
  419. days = parseInt(seconds / 86400, 10);
  420. days = days ? days + 'd ' : '';
  421. return days +
  422. ('0' + date.getUTCHours()).slice(-2) + ':' +
  423. ('0' + date.getUTCMinutes()).slice(-2) + ':' +
  424. ('0' + date.getUTCSeconds()).slice(-2);
  425. },
  426. _formatPercentage: function (floatValue) {
  427. return (floatValue * 100).toFixed(2) + ' %';
  428. },
  429. _renderExtendedProgress: function (data) {
  430. return this._formatBitrate(data.bitrate) + ' | ' +
  431. this._formatTime(
  432. (data.total - data.loaded) * 8 / data.bitrate
  433. ) + ' | ' +
  434. this._formatPercentage(
  435. data.loaded / data.total
  436. ) + ' | ' +
  437. this._formatFileSize(data.loaded) + ' / ' +
  438. this._formatFileSize(data.total);
  439. },
  440. _hasError: function (file) {
  441. if (file.error) {
  442. return file.error;
  443. }
  444. // The number of added files is subtracted from
  445. // maxNumberOfFiles before validation, so we check if
  446. // maxNumberOfFiles is below 0 (instead of below 1):
  447. if (this.options.maxNumberOfFiles < 0) {
  448. return 'Maximum number of files exceeded';
  449. }
  450. // Files are accepted if either the file type or the file name
  451. // matches against the acceptFileTypes regular expression, as
  452. // only browsers with support for the File API report the type:
  453. if (!(this.options.acceptFileTypes.test(file.type) ||
  454. this.options.acceptFileTypes.test(file.name))) {
  455. return 'Filetype not allowed';
  456. }
  457. if (this.options.maxFileSize &&
  458. file.size > this.options.maxFileSize) {
  459. return 'File is too big';
  460. }
  461. if (typeof file.size === 'number' &&
  462. file.size < this.options.minFileSize) {
  463. return 'File is too small';
  464. }
  465. return null;
  466. },
  467. _validate: function (files) {
  468. var that = this,
  469. valid = !!files.length;
  470. $.each(files, function (index, file) {
  471. file.error = that._hasError(file);
  472. if (file.error) {
  473. valid = false;
  474. }
  475. });
  476. return valid;
  477. },
  478. _renderTemplate: function (func, files) {
  479. if (!func) {
  480. return $();
  481. }
  482. var result = func({
  483. files: files,
  484. formatFileSize: this._formatFileSize,
  485. options: this.options
  486. });
  487. if (result instanceof $) {
  488. return result;
  489. }
  490. return $(this.options.templatesContainer).html(result).children();
  491. },
  492. _renderPreview: function (file, node) {
  493. var that = this,
  494. options = this.options,
  495. dfd = $.Deferred();
  496. return ((loadImage && loadImage(
  497. file,
  498. function (img) {
  499. node.append(img);
  500. that._forceReflow(node);
  501. that._transition(node).done(function () {
  502. dfd.resolveWith(node);
  503. });
  504. if (!$.contains(that.document[0].body, node[0])) {
  505. // If the element is not part of the DOM,
  506. // transition events are not triggered,
  507. // so we have to resolve manually:
  508. dfd.resolveWith(node);
  509. }
  510. },
  511. {
  512. maxWidth: options.previewMaxWidth,
  513. maxHeight: options.previewMaxHeight,
  514. canvas: options.previewAsCanvas
  515. }
  516. )) || dfd.resolveWith(node)) && dfd;
  517. },
  518. _renderPreviews: function (data) {
  519. var that = this,
  520. options = this.options;
  521. data.context.find('.preview span').each(function (index, element) {
  522. var file = data.files[index];
  523. if (options.previewSourceFileTypes.test(file.type) &&
  524. ($.type(options.previewSourceMaxFileSize) !== 'number' ||
  525. file.size < options.previewSourceMaxFileSize)) {
  526. that._processingQueue = that._processingQueue.pipe(function () {
  527. var dfd = $.Deferred(),
  528. ev = $.Event('previewdone', {
  529. target: element
  530. });
  531. that._renderPreview(file, $(element)).done(
  532. function () {
  533. that._trigger(ev.type, ev, data);
  534. dfd.resolveWith(that);
  535. }
  536. );
  537. return dfd.promise();
  538. });
  539. }
  540. });
  541. return this._processingQueue;
  542. },
  543. _renderUpload: function (files) {
  544. return this._renderTemplate(
  545. this.options.uploadTemplate,
  546. files
  547. );
  548. },
  549. _renderDownload: function (files) {
  550. return this._renderTemplate(
  551. this.options.downloadTemplate,
  552. files
  553. ).find('a[download]').each(this._enableDragToDesktop).end();
  554. },
  555. _startHandler: function (e) {
  556. e.preventDefault();
  557. var button = $(e.currentTarget),
  558. template = button.closest('.template-upload'),
  559. data = template.data('data');
  560. if (data && data.submit && !data.jqXHR && data.submit()) {
  561. button.prop('disabled', true);
  562. }
  563. },
  564. _cancelHandler: function (e) {
  565. e.preventDefault();
  566. var template = $(e.currentTarget).closest('.template-upload'),
  567. data = template.data('data') || {};
  568. if (!data.jqXHR) {
  569. data.errorThrown = 'abort';
  570. this._trigger('fail', e, data);
  571. } else {
  572. data.jqXHR.abort();
  573. }
  574. },
  575. _deleteHandler: function (e) {
  576. e.preventDefault();
  577. var button = $(e.currentTarget);
  578. this._trigger('destroy', e, $.extend({
  579. context: button.closest('.template-download'),
  580. type: 'DELETE',
  581. dataType: this.options.dataType
  582. }, button.data()));
  583. },
  584. _forceReflow: function (node) {
  585. return $.support.transition && node.length &&
  586. node[0].offsetWidth;
  587. },
  588. _transition: function (node) {
  589. var dfd = $.Deferred();
  590. if ($.support.transition && node.hasClass('fade')) {
  591. node.bind(
  592. $.support.transition.end,
  593. function (e) {
  594. // Make sure we don't respond to other transitions events
  595. // in the container element, e.g. from button elements:
  596. if (e.target === node[0]) {
  597. node.unbind($.support.transition.end);
  598. dfd.resolveWith(node);
  599. }
  600. }
  601. ).toggleClass('in');
  602. } else {
  603. node.toggleClass('in');
  604. dfd.resolveWith(node);
  605. }
  606. return dfd;
  607. },
  608. _initButtonBarEventHandlers: function () {
  609. var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
  610. filesList = this.options.filesContainer;
  611. this._on(fileUploadButtonBar.find('.start'), {
  612. click: function (e) {
  613. e.preventDefault();
  614. filesList.find('.start button').click();
  615. }
  616. });
  617. this._on(fileUploadButtonBar.find('.cancel'), {
  618. click: function (e) {
  619. e.preventDefault();
  620. filesList.find('.cancel button').click();
  621. }
  622. });
  623. this._on(fileUploadButtonBar.find('.delete'), {
  624. click: function (e) {
  625. e.preventDefault();
  626. filesList.find('.delete input:checked').parents('.checker') //modifed by keenthemes
  627. .siblings('button').click();
  628. fileUploadButtonBar.find('.toggle') //added by keenthemes
  629. .prop('checked', false);
  630. jQuery.uniform.update(fileUploadButtonBar.find('.toggle')); //added by keenthemes
  631. }
  632. });
  633. this._on(fileUploadButtonBar.find('.toggle'), {
  634. change: function (e) {
  635. filesList.find('.delete input').prop(
  636. 'checked',
  637. $(e.currentTarget).is(':checked')
  638. );
  639. jQuery.uniform.update(filesList.find('.delete input')); //added by keenthemes
  640. }
  641. });
  642. },
  643. _destroyButtonBarEventHandlers: function () {
  644. this._off(
  645. this.element.find('.fileupload-buttonbar button'),
  646. 'click'
  647. );
  648. this._off(
  649. this.element.find('.fileupload-buttonbar .toggle'),
  650. 'change.'
  651. );
  652. },
  653. _initEventHandlers: function () {
  654. this._super();
  655. this._on(this.options.filesContainer, {
  656. 'click .start button': this._startHandler,
  657. 'click .cancel button': this._cancelHandler,
  658. 'click .delete button': this._deleteHandler
  659. });
  660. this._initButtonBarEventHandlers();
  661. },
  662. _destroyEventHandlers: function () {
  663. this._destroyButtonBarEventHandlers();
  664. this._off(this.options.filesContainer, 'click');
  665. this._super();
  666. },
  667. _enableFileInputButton: function () {
  668. this.element.find('.fileinput-button input')
  669. .prop('disabled', false)
  670. .parent().removeClass('disabled');
  671. },
  672. _disableFileInputButton: function () {
  673. this.element.find('.fileinput-button input')
  674. .prop('disabled', true)
  675. .parent().addClass('disabled');
  676. },
  677. _initTemplates: function () {
  678. var options = this.options;
  679. options.templatesContainer = this.document[0].createElement(
  680. options.filesContainer.prop('nodeName')
  681. );
  682. if (tmpl) {
  683. if (options.uploadTemplateId) {
  684. options.uploadTemplate = tmpl(options.uploadTemplateId);
  685. }
  686. if (options.downloadTemplateId) {
  687. options.downloadTemplate = tmpl(options.downloadTemplateId);
  688. }
  689. }
  690. },
  691. _initFilesContainer: function () {
  692. var options = this.options;
  693. if (options.filesContainer === undefined) {
  694. options.filesContainer = this.element.find('.files');
  695. } else if (!(options.filesContainer instanceof $)) {
  696. options.filesContainer = $(options.filesContainer);
  697. }
  698. },
  699. _stringToRegExp: function (str) {
  700. var parts = str.split('/'),
  701. modifiers = parts.pop();
  702. parts.shift();
  703. return new RegExp(parts.join('/'), modifiers);
  704. },
  705. _initRegExpOptions: function () {
  706. var options = this.options;
  707. if ($.type(options.acceptFileTypes) === 'string') {
  708. options.acceptFileTypes = this._stringToRegExp(
  709. options.acceptFileTypes
  710. );
  711. }
  712. if ($.type(options.previewSourceFileTypes) === 'string') {
  713. options.previewSourceFileTypes = this._stringToRegExp(
  714. options.previewSourceFileTypes
  715. );
  716. }
  717. },
  718. _initSpecialOptions: function () {
  719. this._super();
  720. this._initFilesContainer();
  721. this._initTemplates();
  722. this._initRegExpOptions();
  723. },
  724. _setOption: function (key, value) {
  725. this._super(key, value);
  726. if (key === 'maxNumberOfFiles') {
  727. this._adjustMaxNumberOfFiles(0);
  728. }
  729. },
  730. _create: function () {
  731. this._super();
  732. this._refreshOptionsList.push(
  733. 'filesContainer',
  734. 'uploadTemplateId',
  735. 'downloadTemplateId'
  736. );
  737. if (!this._processingQueue) {
  738. this._processingQueue = $.Deferred().resolveWith(this).promise();
  739. this.process = function () {
  740. return this._processingQueue;
  741. };
  742. }
  743. this._resetFinishedDeferreds();
  744. },
  745. enable: function () {
  746. var wasDisabled = false;
  747. if (this.options.disabled) {
  748. wasDisabled = true;
  749. }
  750. this._super();
  751. if (wasDisabled) {
  752. this.element.find('input, button').prop('disabled', false);
  753. this._enableFileInputButton();
  754. }
  755. },
  756. disable: function () {
  757. if (!this.options.disabled) {
  758. this.element.find('input, button').prop('disabled', true);
  759. this._disableFileInputButton();
  760. }
  761. this._super();
  762. }
  763. });
  764. }));