jquery.fileupload-ui.js 30 KB

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