summaryrefslogtreecommitdiff
path: root/ikiwiki/jquery.fileupload-ui.js
blob: 61897ba5528a37e9f1aa75516e7ec1612adb26f2 (plain)
  1. /*
  2.  * jQuery File Upload User Interface Plugin 5.0.13
  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://creativecommons.org/licenses/MIT/
  10. */
  11. /*jslint nomen: true, unparam: true, regexp: true */
  12. /*global window, document, URL, webkitURL, FileReader, jQuery */
  13. (function ($) {
  14. 'use strict';
  15. // The UI version extends the basic fileupload widget and adds
  16. // a complete user interface based on the given upload/download
  17. // templates.
  18. $.widget('blueimpUI.fileupload', $.blueimp.fileupload, {
  19. options: {
  20. // By default, files added to the widget are uploaded as soon
  21. // as the user clicks on the start buttons. To enable automatic
  22. // uploads, set the following option to true:
  23. autoUpload: true,
  24. // The file upload template that is given as first argument to the
  25. // jQuery.tmpl method to render the file uploads:
  26. uploadTemplate: $('#template-upload'),
  27. // The file download template, that is given as first argument to the
  28. // jQuery.tmpl method to render the file downloads:
  29. downloadTemplate: $('#template-download'),
  30. // The expected data type of the upload response, sets the dataType
  31. // option of the $.ajax upload requests:
  32. dataType: 'json',
  33. // The add callback is invoked as soon as files are added to the fileupload
  34. // widget (via file input selection, drag & drop or add API call).
  35. // See the basic file upload widget for more information:
  36. add: function (e, data) {
  37. var that = $(this).data('fileupload');
  38. data.isAdjusted = true;
  39. data.isValidated = that._validate(data.files);
  40. data.context = that._renderUpload(data.files)
  41. .appendTo($(this).find('.files')).fadeIn(function () {
  42. // Fix for IE7 and lower:
  43. $(this).show();
  44. }).data('data', data);
  45. if ((that.options.autoUpload || data.autoUpload) &&
  46. data.isValidated) {
  47. data.jqXHR = data.submit();
  48. }
  49. },
  50. // Callback for the start of each file upload request:
  51. send: function (e, data) {
  52. if (!data.isValidated) {
  53. var that = $(this).data('fileupload');
  54. if (!that._validate(data.files)) {
  55. return false;
  56. }
  57. }
  58. if (data.context && data.dataType &&
  59. data.dataType.substr(0, 6) === 'iframe') {
  60. // Iframe Transport does not support progress events.
  61. // In lack of an indeterminate progress bar, we set
  62. // the progress to 100%, showing the full animated bar:
  63. data.context.find('.ui-progressbar').progressbar(
  64. 'value',
  65. parseInt(100, 10)
  66. );
  67. }
  68. },
  69. // Callback for successful uploads:
  70. done: function (e, data) {
  71. var that = $(this).data('fileupload');
  72. if (data.context) {
  73. data.context.each(function (index) {
  74. var file = ($.isArray(data.result) &&
  75. data.result[index]) || {error: 'emptyResult'};
  76. $(this).fadeOut(function () {
  77. that._renderDownload([file])
  78. .css('display', 'none')
  79. .replaceAll(this)
  80. .fadeIn(function () {
  81. // Fix for IE7 and lower:
  82. $(this).show();
  83. });
  84. });
  85. });
  86. } else {
  87. that._renderDownload(data.result)
  88. .css('display', 'none')
  89. .appendTo($(this).find('.files'))
  90. .fadeIn(function () {
  91. // Fix for IE7 and lower:
  92. $(this).show();
  93. });
  94. }
  95. },
  96. // Callback for failed (abort or error) uploads:
  97. fail: function (e, data) {
  98. var that = $(this).data('fileupload');
  99. if (data.context) {
  100. data.context.each(function (index) {
  101. $(this).fadeOut(function () {
  102. if (data.errorThrown !== 'abort') {
  103. var file = data.files[index];
  104. file.error = file.error || data.errorThrown
  105. || true;
  106. that._renderDownload([file])
  107. .css('display', 'none')
  108. .replaceAll(this)
  109. .fadeIn(function () {
  110. // Fix for IE7 and lower:
  111. $(this).show();
  112. });
  113. } else {
  114. data.context.remove();
  115. }
  116. });
  117. });
  118. } else if (data.errorThrown !== 'abort') {
  119. data.context = that._renderUpload(data.files)
  120. .css('display', 'none')
  121. .appendTo($(this).find('.files'))
  122. .fadeIn(function () {
  123. // Fix for IE7 and lower:
  124. $(this).show();
  125. }).data('data', data);
  126. }
  127. },
  128. // Callback for upload progress events:
  129. progress: function (e, data) {
  130. if (data.context) {
  131. data.context.find('.ui-progressbar').progressbar(
  132. 'value',
  133. parseInt(data.loaded / data.total * 100, 10)
  134. );
  135. }
  136. },
  137. // Callback for global upload progress events:
  138. progressall: function (e, data) {
  139. $(this).find('.fileupload-progressbar').progressbar(
  140. 'value',
  141. parseInt(data.loaded / data.total * 100, 10)
  142. );
  143. },
  144. // Callback for uploads start, equivalent to the global ajaxStart event:
  145. start: function () {
  146. $(this).find('.fileupload-progressbar')
  147. .progressbar('value', 0).fadeIn();
  148. },
  149. // Callback for uploads stop, equivalent to the global ajaxStop event:
  150. stop: function () {
  151. $(this).find('.fileupload-progressbar').fadeOut();
  152. },
  153. },
  154. _createObjectURL: function (file) {
  155. var undef = 'undefined',
  156. urlAPI = (typeof window.createObjectURL !== undef && window) ||
  157. (typeof URL !== undef && URL) ||
  158. (typeof webkitURL !== undef && webkitURL);
  159. return urlAPI ? urlAPI.createObjectURL(file) : false;
  160. },
  161. _revokeObjectURL: function (url) {
  162. var undef = 'undefined',
  163. urlAPI = (typeof window.revokeObjectURL !== undef && window) ||
  164. (typeof URL !== undef && URL) ||
  165. (typeof webkitURL !== undef && webkitURL);
  166. return urlAPI ? urlAPI.revokeObjectURL(url) : false;
  167. },
  168. // Link handler, that allows to download files
  169. // by drag & drop of the links to the desktop:
  170. _enableDragToDesktop: function () {
  171. var link = $(this),
  172. url = link.prop('href'),
  173. name = decodeURIComponent(url.split('/').pop())
  174. .replace(/:/g, '-'),
  175. type = 'application/octet-stream';
  176. link.bind('dragstart', function (e) {
  177. try {
  178. e.originalEvent.dataTransfer.setData(
  179. 'DownloadURL',
  180. [type, name, url].join(':')
  181. );
  182. } catch (err) {}
  183. });
  184. },
  185. _hasError: function (file) {
  186. if (file.error) {
  187. return file.error;
  188. }
  189. return null;
  190. },
  191. _validate: function (files) {
  192. var that = this,
  193. valid;
  194. $.each(files, function (index, file) {
  195. file.error = that._hasError(file);
  196. valid = !file.error;
  197. });
  198. return valid;
  199. },
  200. _uploadTemplateHelper: function (file) {
  201. return file;
  202. },
  203. _renderUploadTemplate: function (files) {
  204. var that = this;
  205. return $.tmpl(
  206. this.options.uploadTemplate,
  207. $.map(files, function (file) {
  208. return that._uploadTemplateHelper(file);
  209. })
  210. );
  211. },
  212. _renderUpload: function (files) {
  213. var that = this,
  214. options = this.options,
  215. tmpl = this._renderUploadTemplate(files);
  216. if (!(tmpl instanceof $)) {
  217. return $();
  218. }
  219. tmpl.css('display', 'none');
  220. // .slice(1).remove().end().first() removes all but the first
  221. // element and selects only the first for the jQuery collection:
  222. tmpl.find('.progress div').slice(1).remove().end().first()
  223. .progressbar();
  224. tmpl.find('.start button').slice(
  225. this.options.autoUpload ? 0 : 1
  226. ).remove().end().first()
  227. .button({
  228. text: false,
  229. icons: {primary: 'ui-icon-circle-arrow-e'}
  230. });
  231. tmpl.find('.cancel button').slice(1).remove().end().first()
  232. .button({
  233. text: false,
  234. icons: {primary: 'ui-icon-cancel'}
  235. });
  236. return tmpl;
  237. },
  238. _downloadTemplateHelper: function (file) {
  239. return file;
  240. },
  241. _renderDownloadTemplate: function (files) {
  242. var that = this;
  243. return $.tmpl(
  244. this.options.downloadTemplate,
  245. $.map(files, function (file) {
  246. return that._downloadTemplateHelper(file);
  247. })
  248. );
  249. },
  250. _renderDownload: function (files) {
  251. var tmpl = this._renderDownloadTemplate(files);
  252. if (!(tmpl instanceof $)) {
  253. return $();
  254. }
  255. tmpl.css('display', 'none');
  256. tmpl.find('a').each(this._enableDragToDesktop);
  257. return tmpl;
  258. },
  259. _startHandler: function (e) {
  260. e.preventDefault();
  261. var tmpl = $(this).closest('.template-upload'),
  262. data = tmpl.data('data');
  263. if (data && data.submit && !data.jqXHR) {
  264. data.jqXHR = data.submit();
  265. $(this).fadeOut();
  266. }
  267. },
  268. _cancelHandler: function (e) {
  269. e.preventDefault();
  270. var tmpl = $(this).closest('.template-upload'),
  271. data = tmpl.data('data') || {};
  272. if (!data.jqXHR) {
  273. data.errorThrown = 'abort';
  274. e.data.fileupload._trigger('fail', e, data);
  275. } else {
  276. data.jqXHR.abort();
  277. }
  278. },
  279. _initEventHandlers: function () {
  280. $.blueimp.fileupload.prototype._initEventHandlers.call(this);
  281. var filesList = this.element.find('.files'),
  282. eventData = {fileupload: this};
  283. filesList.find('.start button')
  284. .live(
  285. 'click.' + this.options.namespace,
  286. eventData,
  287. this._startHandler
  288. );
  289. filesList.find('.cancel button')
  290. .live(
  291. 'click.' + this.options.namespace,
  292. eventData,
  293. this._cancelHandler
  294. );
  295. },
  296. _destroyEventHandlers: function () {
  297. var filesList = this.element.find('.files');
  298. filesList.find('.start button')
  299. .die('click.' + this.options.namespace);
  300. filesList.find('.cancel button')
  301. .die('click.' + this.options.namespace);
  302. $.blueimp.fileupload.prototype._destroyEventHandlers.call(this);
  303. },
  304. _initTemplates: function () {
  305. // Handle cases where the templates are defined
  306. // after the widget library has been included:
  307. if (this.options.uploadTemplate instanceof $ &&
  308. !this.options.uploadTemplate.length) {
  309. this.options.uploadTemplate = $(
  310. this.options.uploadTemplate.selector
  311. );
  312. }
  313. if (this.options.downloadTemplate instanceof $ &&
  314. !this.options.downloadTemplate.length) {
  315. this.options.downloadTemplate = $(
  316. this.options.downloadTemplate.selector
  317. );
  318. }
  319. },
  320. _create: function () {
  321. $.blueimp.fileupload.prototype._create.call(this);
  322. this._initTemplates();
  323. },
  324. enable: function () {
  325. $.blueimp.fileupload.prototype.enable.call(this);
  326. },
  327. disable: function () {
  328. $.blueimp.fileupload.prototype.disable.call(this);
  329. }
  330. });
  331. }(jQuery));