card-mod-script 0.14.2 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/data/real.yml +50 -0
  3. data/lib/ansi2html.rb +69 -0
  4. data/lib/card/mod/script.rb +1 -0
  5. data/set/abstract/00_script.rb +4 -4
  6. data/set/abstract/02_coffee_script.rb +9 -1
  7. data/set/all/head_javascript.rb +13 -22
  8. data/set/right/script.rb +1 -1
  9. data/set/type/coffee_script.rb +6 -0
  10. data/set/type/java_script.rb +6 -0
  11. data/set/type/local_script_folder_group.rb +2 -0
  12. data/set/type/local_script_manifest_group.rb +2 -0
  13. data/set/type_plus_right/mod/script.rb +1 -5
  14. data/set/type_plus_right/set/script.rb +3 -1
  15. metadata +13 -119
  16. data/assets/script/decko/autosave.js.coffee +0 -30
  17. data/assets/script/decko/bridge.js.coffee +0 -31
  18. data/assets/script/decko/card_menu.js.coffee +0 -26
  19. data/assets/script/decko/components.js.coffee +0 -49
  20. data/assets/script/decko/decko.js.coffee +0 -82
  21. data/assets/script/decko/doubleclick.js.coffee +0 -30
  22. data/assets/script/decko/editor.js.coffee +0 -57
  23. data/assets/script/decko/filter.js.coffee +0 -183
  24. data/assets/script/decko/filter_items.js.coffee +0 -128
  25. data/assets/script/decko/filter_links.js.coffee +0 -81
  26. data/assets/script/decko/follow.js.coffee +0 -22
  27. data/assets/script/decko/layout.js.coffee +0 -76
  28. data/assets/script/decko/link_editor.js.coffee +0 -61
  29. data/assets/script/decko/mod.js.coffee +0 -79
  30. data/assets/script/decko/modal.js.coffee +0 -113
  31. data/assets/script/decko/name_editor.js.coffee +0 -40
  32. data/assets/script/decko/navbox.js.coffee +0 -74
  33. data/assets/script/decko/nest_editor.js.coffee +0 -166
  34. data/assets/script/decko/nest_editor_name.js.coffee +0 -102
  35. data/assets/script/decko/nest_editor_options.js.coffee +0 -93
  36. data/assets/script/decko/nest_editor_rules.js.coffee +0 -3
  37. data/assets/script/decko/overlay.js.coffee +0 -54
  38. data/assets/script/decko/pointer_config.js.coffee +0 -79
  39. data/assets/script/decko/pointer_list_editor.js.coffee +0 -67
  40. data/assets/script/decko/recaptcha.js.coffee +0 -19
  41. data/assets/script/decko/selectable_filtered_content.js.coffee +0 -12
  42. data/assets/script/decko/slot.js.coffee +0 -182
  43. data/assets/script/decko/slot_ready.js.coffee +0 -12
  44. data/assets/script/decko/slotter.js.coffee +0 -268
  45. data/assets/script/decko/type_editor.js.coffee +0 -21
  46. data/assets/script/decko/upload.js.coffee +0 -64
  47. data/assets/script/jquery-ui.min.js +0 -13
  48. data/assets/script/jquery.autosize.js +0 -274
  49. data/assets/script/manifest.yml +0 -57
  50. data/db/migrate_core_cards/20200804112348_add_mod_script_assets_type.rb +0 -30
  51. data/vendor/jquery_file_upload/LICENSE.txt +0 -20
  52. data/vendor/jquery_file_upload/README.md +0 -224
  53. data/vendor/jquery_file_upload/SECURITY.md +0 -227
  54. data/vendor/jquery_file_upload/VULNERABILITIES.md +0 -118
  55. data/vendor/jquery_file_upload/cors/postmessage.html +0 -85
  56. data/vendor/jquery_file_upload/cors/result.html +0 -26
  57. data/vendor/jquery_file_upload/css/jquery.fileupload-noscript.css +0 -22
  58. data/vendor/jquery_file_upload/css/jquery.fileupload-ui-noscript.css +0 -17
  59. data/vendor/jquery_file_upload/css/jquery.fileupload-ui.css +0 -68
  60. data/vendor/jquery_file_upload/css/jquery.fileupload.css +0 -36
  61. data/vendor/jquery_file_upload/docker-compose.yml +0 -55
  62. data/vendor/jquery_file_upload/img/loading.gif +0 -0
  63. data/vendor/jquery_file_upload/img/progressbar.gif +0 -0
  64. data/vendor/jquery_file_upload/index.html +0 -357
  65. data/vendor/jquery_file_upload/js/cors/jquery.postmessage-transport.js +0 -126
  66. data/vendor/jquery_file_upload/js/cors/jquery.xdr-transport.js +0 -97
  67. data/vendor/jquery_file_upload/js/demo.js +0 -75
  68. data/vendor/jquery_file_upload/js/jquery.fileupload-audio.js +0 -101
  69. data/vendor/jquery_file_upload/js/jquery.fileupload-image.js +0 -347
  70. data/vendor/jquery_file_upload/js/jquery.fileupload-process.js +0 -170
  71. data/vendor/jquery_file_upload/js/jquery.fileupload-ui.js +0 -759
  72. data/vendor/jquery_file_upload/js/jquery.fileupload-validate.js +0 -119
  73. data/vendor/jquery_file_upload/js/jquery.fileupload-video.js +0 -101
  74. data/vendor/jquery_file_upload/js/jquery.fileupload.js +0 -1604
  75. data/vendor/jquery_file_upload/js/jquery.iframe-transport.js +0 -227
  76. data/vendor/jquery_file_upload/js/vendor/jquery.ui.widget.js +0 -805
  77. data/vendor/jquery_file_upload/package-lock.json +0 -6853
  78. data/vendor/jquery_file_upload/package.json +0 -116
  79. data/vendor/jquery_file_upload/server/gae-python/app.yaml +0 -18
  80. data/vendor/jquery_file_upload/server/gae-python/main.py +0 -204
  81. data/vendor/jquery_file_upload/server/gae-python/static/favicon.ico +0 -0
  82. data/vendor/jquery_file_upload/server/gae-python/static/robots.txt +0 -2
  83. data/vendor/jquery_file_upload/server/php/Dockerfile +0 -44
  84. data/vendor/jquery_file_upload/server/php/UploadHandler.php +0 -1480
  85. data/vendor/jquery_file_upload/server/php/index.php +0 -15
  86. data/vendor/jquery_file_upload/server/php/php.ini +0 -5
  87. data/vendor/jquery_file_upload/test/index.html +0 -49
  88. data/vendor/jquery_file_upload/test/unit.js +0 -989
  89. data/vendor/jquery_file_upload/test/vendor/chai.js +0 -10854
  90. data/vendor/jquery_file_upload/test/vendor/mocha.css +0 -325
  91. data/vendor/jquery_file_upload/test/vendor/mocha.js +0 -18178
  92. data/vendor/jquery_file_upload/wdio/LICENSE.txt +0 -20
  93. data/vendor/jquery_file_upload/wdio/assets/black+white-3x2.jpg +0 -0
  94. data/vendor/jquery_file_upload/wdio/assets/black+white-60x40.gif +0 -0
  95. data/vendor/jquery_file_upload/wdio/conf/chrome.js +0 -40
  96. data/vendor/jquery_file_upload/wdio/conf/firefox.js +0 -25
  97. data/vendor/jquery_file_upload/wdio/hooks/index.js +0 -36
  98. data/vendor/jquery_file_upload/wdio/test/pages/file-upload.js +0 -79
  99. data/vendor/jquery_file_upload/wdio/test/specs/01-file-upload.js +0 -25
  100. data/vendor/jquery_file_upload/wdio/wdio.conf.js +0 -4
  101. data/vendor/jquery_rails/CHANGELOG.md +0 -359
  102. data/vendor/jquery_rails/CONTRIBUTING.md +0 -132
  103. data/vendor/jquery_rails/Gemfile +0 -22
  104. data/vendor/jquery_rails/MIT-LICENSE +0 -21
  105. data/vendor/jquery_rails/README.md +0 -75
  106. data/vendor/jquery_rails/Rakefile +0 -59
  107. data/vendor/jquery_rails/VERSIONS.md +0 -62
  108. data/vendor/jquery_rails/jquery-rails.gemspec +0 -26
  109. data/vendor/jquery_rails/lib/jquery/assert_select.rb +0 -149
  110. data/vendor/jquery_rails/lib/jquery/rails/engine.rb +0 -6
  111. data/vendor/jquery_rails/lib/jquery/rails/version.rb +0 -9
  112. data/vendor/jquery_rails/lib/jquery/rails.rb +0 -8
  113. data/vendor/jquery_rails/lib/jquery-rails.rb +0 -1
  114. data/vendor/jquery_rails/test/assert_select_jquery_test.rb +0 -85
  115. data/vendor/jquery_rails/test/test_helper.rb +0 -6
  116. data/vendor/jquery_rails/vendor/assets/javascripts/jquery.js +0 -11008
  117. data/vendor/jquery_rails/vendor/assets/javascripts/jquery.min.js +0 -5
  118. data/vendor/jquery_rails/vendor/assets/javascripts/jquery.min.map +0 -1
  119. data/vendor/jquery_rails/vendor/assets/javascripts/jquery2.js +0 -9814
  120. data/vendor/jquery_rails/vendor/assets/javascripts/jquery2.min.js +0 -4
  121. data/vendor/jquery_rails/vendor/assets/javascripts/jquery2.min.map +0 -1
  122. data/vendor/jquery_rails/vendor/assets/javascripts/jquery3.js +0 -10364
  123. data/vendor/jquery_rails/vendor/assets/javascripts/jquery3.min.js +0 -2
  124. data/vendor/jquery_rails/vendor/assets/javascripts/jquery3.min.map +0 -1
  125. data/vendor/jquery_rails/vendor/assets/javascripts/jquery_ujs.js +0 -555
@@ -1,1604 +0,0 @@
1
- /*
2
- * jQuery File Upload Plugin
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
- * https://opensource.org/licenses/MIT
10
- */
11
-
12
- /* global define, require */
13
- /* eslint-disable new-cap */
14
-
15
- (function (factory) {
16
- 'use strict';
17
- if (typeof define === 'function' && define.amd) {
18
- // Register as an anonymous AMD module:
19
- define(['jquery', 'jquery-ui/ui/widget'], factory);
20
- } else if (typeof exports === 'object') {
21
- // Node/CommonJS:
22
- factory(require('jquery'), require('./vendor/jquery.ui.widget'));
23
- } else {
24
- // Browser globals:
25
- factory(window.jQuery);
26
- }
27
- })(function ($) {
28
- 'use strict';
29
-
30
- // Detect file input support, based on
31
- // https://viljamis.com/2012/file-upload-support-on-mobile/
32
- $.support.fileInput = !(
33
- new RegExp(
34
- // Handle devices which give false positives for the feature detection:
35
- '(Android (1\\.[0156]|2\\.[01]))' +
36
- '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
37
- '|(w(eb)?OSBrowser)|(webOS)' +
38
- '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
39
- ).test(window.navigator.userAgent) ||
40
- // Feature detection for all other devices:
41
- $('<input type="file"/>').prop('disabled')
42
- );
43
-
44
- // The FileReader API is not actually used, but works as feature detection,
45
- // as some Safari versions (5?) support XHR file uploads via the FormData API,
46
- // but not non-multipart XHR file uploads.
47
- // window.XMLHttpRequestUpload is not available on IE10, so we check for
48
- // window.ProgressEvent instead to detect XHR2 file upload capability:
49
- $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
50
- $.support.xhrFormDataFileUpload = !!window.FormData;
51
-
52
- // Detect support for Blob slicing (required for chunked uploads):
53
- $.support.blobSlice =
54
- window.Blob &&
55
- (Blob.prototype.slice ||
56
- Blob.prototype.webkitSlice ||
57
- Blob.prototype.mozSlice);
58
-
59
- /**
60
- * Helper function to create drag handlers for dragover/dragenter/dragleave
61
- *
62
- * @param {string} type Event type
63
- * @returns {Function} Drag handler
64
- */
65
- function getDragHandler(type) {
66
- var isDragOver = type === 'dragover';
67
- return function (e) {
68
- e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
69
- var dataTransfer = e.dataTransfer;
70
- if (
71
- dataTransfer &&
72
- $.inArray('Files', dataTransfer.types) !== -1 &&
73
- this._trigger(type, $.Event(type, { delegatedEvent: e })) !== false
74
- ) {
75
- e.preventDefault();
76
- if (isDragOver) {
77
- dataTransfer.dropEffect = 'copy';
78
- }
79
- }
80
- };
81
- }
82
-
83
- // The fileupload widget listens for change events on file input fields defined
84
- // via fileInput setting and paste or drop events of the given dropZone.
85
- // In addition to the default jQuery Widget methods, the fileupload widget
86
- // exposes the "add" and "send" methods, to add or directly send files using
87
- // the fileupload API.
88
- // By default, files added via file input selection, paste, drag & drop or
89
- // "add" method are uploaded immediately, but it is possible to override
90
- // the "add" callback option to queue file uploads.
91
- $.widget('blueimp.fileupload', {
92
- options: {
93
- // The drop target element(s), by the default the complete document.
94
- // Set to null to disable drag & drop support:
95
- dropZone: $(document),
96
- // The paste target element(s), by the default undefined.
97
- // Set to a DOM node or jQuery object to enable file pasting:
98
- pasteZone: undefined,
99
- // The file input field(s), that are listened to for change events.
100
- // If undefined, it is set to the file input fields inside
101
- // of the widget element on plugin initialization.
102
- // Set to null to disable the change listener.
103
- fileInput: undefined,
104
- // By default, the file input field is replaced with a clone after
105
- // each input field change event. This is required for iframe transport
106
- // queues and allows change events to be fired for the same file
107
- // selection, but can be disabled by setting the following option to false:
108
- replaceFileInput: true,
109
- // The parameter name for the file form data (the request argument name).
110
- // If undefined or empty, the name property of the file input field is
111
- // used, or "files[]" if the file input name property is also empty,
112
- // can be a string or an array of strings:
113
- paramName: undefined,
114
- // By default, each file of a selection is uploaded using an individual
115
- // request for XHR type uploads. Set to false to upload file
116
- // selections in one request each:
117
- singleFileUploads: true,
118
- // To limit the number of files uploaded with one XHR request,
119
- // set the following option to an integer greater than 0:
120
- limitMultiFileUploads: undefined,
121
- // The following option limits the number of files uploaded with one
122
- // XHR request to keep the request size under or equal to the defined
123
- // limit in bytes:
124
- limitMultiFileUploadSize: undefined,
125
- // Multipart file uploads add a number of bytes to each uploaded file,
126
- // therefore the following option adds an overhead for each file used
127
- // in the limitMultiFileUploadSize configuration:
128
- limitMultiFileUploadSizeOverhead: 512,
129
- // Set the following option to true to issue all file upload requests
130
- // in a sequential order:
131
- sequentialUploads: false,
132
- // To limit the number of concurrent uploads,
133
- // set the following option to an integer greater than 0:
134
- limitConcurrentUploads: undefined,
135
- // Set the following option to true to force iframe transport uploads:
136
- forceIframeTransport: false,
137
- // Set the following option to the location of a redirect url on the
138
- // origin server, for cross-domain iframe transport uploads:
139
- redirect: undefined,
140
- // The parameter name for the redirect url, sent as part of the form
141
- // data and set to 'redirect' if this option is empty:
142
- redirectParamName: undefined,
143
- // Set the following option to the location of a postMessage window,
144
- // to enable postMessage transport uploads:
145
- postMessage: undefined,
146
- // By default, XHR file uploads are sent as multipart/form-data.
147
- // The iframe transport is always using multipart/form-data.
148
- // Set to false to enable non-multipart XHR uploads:
149
- multipart: true,
150
- // To upload large files in smaller chunks, set the following option
151
- // to a preferred maximum chunk size. If set to 0, null or undefined,
152
- // or the browser does not support the required Blob API, files will
153
- // be uploaded as a whole.
154
- maxChunkSize: undefined,
155
- // When a non-multipart upload or a chunked multipart upload has been
156
- // aborted, this option can be used to resume the upload by setting
157
- // it to the size of the already uploaded bytes. This option is most
158
- // useful when modifying the options object inside of the "add" or
159
- // "send" callbacks, as the options are cloned for each file upload.
160
- uploadedBytes: undefined,
161
- // By default, failed (abort or error) file uploads are removed from the
162
- // global progress calculation. Set the following option to false to
163
- // prevent recalculating the global progress data:
164
- recalculateProgress: true,
165
- // Interval in milliseconds to calculate and trigger progress events:
166
- progressInterval: 100,
167
- // Interval in milliseconds to calculate progress bitrate:
168
- bitrateInterval: 500,
169
- // By default, uploads are started automatically when adding files:
170
- autoUpload: true,
171
- // By default, duplicate file names are expected to be handled on
172
- // the server-side. If this is not possible (e.g. when uploading
173
- // files directly to Amazon S3), the following option can be set to
174
- // an empty object or an object mapping existing filenames, e.g.:
175
- // { "image.jpg": true, "image (1).jpg": true }
176
- // If it is set, all files will be uploaded with unique filenames,
177
- // adding increasing number suffixes if necessary, e.g.:
178
- // "image (2).jpg"
179
- uniqueFilenames: undefined,
180
-
181
- // Error and info messages:
182
- messages: {
183
- uploadedBytes: 'Uploaded bytes exceed file size'
184
- },
185
-
186
- // Translation function, gets the message key to be translated
187
- // and an object with context specific data as arguments:
188
- i18n: function (message, context) {
189
- // eslint-disable-next-line no-param-reassign
190
- message = this.messages[message] || message.toString();
191
- if (context) {
192
- $.each(context, function (key, value) {
193
- // eslint-disable-next-line no-param-reassign
194
- message = message.replace('{' + key + '}', value);
195
- });
196
- }
197
- return message;
198
- },
199
-
200
- // Additional form data to be sent along with the file uploads can be set
201
- // using this option, which accepts an array of objects with name and
202
- // value properties, a function returning such an array, a FormData
203
- // object (for XHR file uploads), or a simple object.
204
- // The form of the first fileInput is given as parameter to the function:
205
- formData: function (form) {
206
- return form.serializeArray();
207
- },
208
-
209
- // The add callback is invoked as soon as files are added to the fileupload
210
- // widget (via file input selection, drag & drop, paste or add API call).
211
- // If the singleFileUploads option is enabled, this callback will be
212
- // called once for each file in the selection for XHR file uploads, else
213
- // once for each file selection.
214
- //
215
- // The upload starts when the submit method is invoked on the data parameter.
216
- // The data object contains a files property holding the added files
217
- // and allows you to override plugin options as well as define ajax settings.
218
- //
219
- // Listeners for this callback can also be bound the following way:
220
- // .on('fileuploadadd', func);
221
- //
222
- // data.submit() returns a Promise object and allows to attach additional
223
- // handlers using jQuery's Deferred callbacks:
224
- // data.submit().done(func).fail(func).always(func);
225
- add: function (e, data) {
226
- if (e.isDefaultPrevented()) {
227
- return false;
228
- }
229
- if (
230
- data.autoUpload ||
231
- (data.autoUpload !== false &&
232
- $(this).fileupload('option', 'autoUpload'))
233
- ) {
234
- data.process().done(function () {
235
- data.submit();
236
- });
237
- }
238
- },
239
-
240
- // Other callbacks:
241
-
242
- // Callback for the submit event of each file upload:
243
- // submit: function (e, data) {}, // .on('fileuploadsubmit', func);
244
-
245
- // Callback for the start of each file upload request:
246
- // send: function (e, data) {}, // .on('fileuploadsend', func);
247
-
248
- // Callback for successful uploads:
249
- // done: function (e, data) {}, // .on('fileuploaddone', func);
250
-
251
- // Callback for failed (abort or error) uploads:
252
- // fail: function (e, data) {}, // .on('fileuploadfail', func);
253
-
254
- // Callback for completed (success, abort or error) requests:
255
- // always: function (e, data) {}, // .on('fileuploadalways', func);
256
-
257
- // Callback for upload progress events:
258
- // progress: function (e, data) {}, // .on('fileuploadprogress', func);
259
-
260
- // Callback for global upload progress events:
261
- // progressall: function (e, data) {}, // .on('fileuploadprogressall', func);
262
-
263
- // Callback for uploads start, equivalent to the global ajaxStart event:
264
- // start: function (e) {}, // .on('fileuploadstart', func);
265
-
266
- // Callback for uploads stop, equivalent to the global ajaxStop event:
267
- // stop: function (e) {}, // .on('fileuploadstop', func);
268
-
269
- // Callback for change events of the fileInput(s):
270
- // change: function (e, data) {}, // .on('fileuploadchange', func);
271
-
272
- // Callback for paste events to the pasteZone(s):
273
- // paste: function (e, data) {}, // .on('fileuploadpaste', func);
274
-
275
- // Callback for drop events of the dropZone(s):
276
- // drop: function (e, data) {}, // .on('fileuploaddrop', func);
277
-
278
- // Callback for dragover events of the dropZone(s):
279
- // dragover: function (e) {}, // .on('fileuploaddragover', func);
280
-
281
- // Callback before the start of each chunk upload request (before form data initialization):
282
- // chunkbeforesend: function (e, data) {}, // .on('fileuploadchunkbeforesend', func);
283
-
284
- // Callback for the start of each chunk upload request:
285
- // chunksend: function (e, data) {}, // .on('fileuploadchunksend', func);
286
-
287
- // Callback for successful chunk uploads:
288
- // chunkdone: function (e, data) {}, // .on('fileuploadchunkdone', func);
289
-
290
- // Callback for failed (abort or error) chunk uploads:
291
- // chunkfail: function (e, data) {}, // .on('fileuploadchunkfail', func);
292
-
293
- // Callback for completed (success, abort or error) chunk upload requests:
294
- // chunkalways: function (e, data) {}, // .on('fileuploadchunkalways', func);
295
-
296
- // The plugin options are used as settings object for the ajax calls.
297
- // The following are jQuery ajax settings required for the file uploads:
298
- processData: false,
299
- contentType: false,
300
- cache: false,
301
- timeout: 0
302
- },
303
-
304
- // jQuery versions before 1.8 require promise.pipe if the return value is
305
- // used, as promise.then in older versions has a different behavior, see:
306
- // https://blog.jquery.com/2012/08/09/jquery-1-8-released/
307
- // https://bugs.jquery.com/ticket/11010
308
- // https://github.com/blueimp/jQuery-File-Upload/pull/3435
309
- _promisePipe: (function () {
310
- var parts = $.fn.jquery.split('.');
311
- return Number(parts[0]) > 1 || Number(parts[1]) > 7 ? 'then' : 'pipe';
312
- })(),
313
-
314
- // A list of options that require reinitializing event listeners and/or
315
- // special initialization code:
316
- _specialOptions: [
317
- 'fileInput',
318
- 'dropZone',
319
- 'pasteZone',
320
- 'multipart',
321
- 'forceIframeTransport'
322
- ],
323
-
324
- _blobSlice:
325
- $.support.blobSlice &&
326
- function () {
327
- var slice = this.slice || this.webkitSlice || this.mozSlice;
328
- return slice.apply(this, arguments);
329
- },
330
-
331
- _BitrateTimer: function () {
332
- this.timestamp = Date.now ? Date.now() : new Date().getTime();
333
- this.loaded = 0;
334
- this.bitrate = 0;
335
- this.getBitrate = function (now, loaded, interval) {
336
- var timeDiff = now - this.timestamp;
337
- if (!this.bitrate || !interval || timeDiff > interval) {
338
- this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
339
- this.loaded = loaded;
340
- this.timestamp = now;
341
- }
342
- return this.bitrate;
343
- };
344
- },
345
-
346
- _isXHRUpload: function (options) {
347
- return (
348
- !options.forceIframeTransport &&
349
- ((!options.multipart && $.support.xhrFileUpload) ||
350
- $.support.xhrFormDataFileUpload)
351
- );
352
- },
353
-
354
- _getFormData: function (options) {
355
- var formData;
356
- if ($.type(options.formData) === 'function') {
357
- return options.formData(options.form);
358
- }
359
- if ($.isArray(options.formData)) {
360
- return options.formData;
361
- }
362
- if ($.type(options.formData) === 'object') {
363
- formData = [];
364
- $.each(options.formData, function (name, value) {
365
- formData.push({ name: name, value: value });
366
- });
367
- return formData;
368
- }
369
- return [];
370
- },
371
-
372
- _getTotal: function (files) {
373
- var total = 0;
374
- $.each(files, function (index, file) {
375
- total += file.size || 1;
376
- });
377
- return total;
378
- },
379
-
380
- _initProgressObject: function (obj) {
381
- var progress = {
382
- loaded: 0,
383
- total: 0,
384
- bitrate: 0
385
- };
386
- if (obj._progress) {
387
- $.extend(obj._progress, progress);
388
- } else {
389
- obj._progress = progress;
390
- }
391
- },
392
-
393
- _initResponseObject: function (obj) {
394
- var prop;
395
- if (obj._response) {
396
- for (prop in obj._response) {
397
- if (Object.prototype.hasOwnProperty.call(obj._response, prop)) {
398
- delete obj._response[prop];
399
- }
400
- }
401
- } else {
402
- obj._response = {};
403
- }
404
- },
405
-
406
- _onProgress: function (e, data) {
407
- if (e.lengthComputable) {
408
- var now = Date.now ? Date.now() : new Date().getTime(),
409
- loaded;
410
- if (
411
- data._time &&
412
- data.progressInterval &&
413
- now - data._time < data.progressInterval &&
414
- e.loaded !== e.total
415
- ) {
416
- return;
417
- }
418
- data._time = now;
419
- loaded =
420
- Math.floor(
421
- (e.loaded / e.total) * (data.chunkSize || data._progress.total)
422
- ) + (data.uploadedBytes || 0);
423
- // Add the difference from the previously loaded state
424
- // to the global loaded counter:
425
- this._progress.loaded += loaded - data._progress.loaded;
426
- this._progress.bitrate = this._bitrateTimer.getBitrate(
427
- now,
428
- this._progress.loaded,
429
- data.bitrateInterval
430
- );
431
- data._progress.loaded = data.loaded = loaded;
432
- data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
433
- now,
434
- loaded,
435
- data.bitrateInterval
436
- );
437
- // Trigger a custom progress event with a total data property set
438
- // to the file size(s) of the current upload and a loaded data
439
- // property calculated accordingly:
440
- this._trigger(
441
- 'progress',
442
- $.Event('progress', { delegatedEvent: e }),
443
- data
444
- );
445
- // Trigger a global progress event for all current file uploads,
446
- // including ajax calls queued for sequential file uploads:
447
- this._trigger(
448
- 'progressall',
449
- $.Event('progressall', { delegatedEvent: e }),
450
- this._progress
451
- );
452
- }
453
- },
454
-
455
- _initProgressListener: function (options) {
456
- var that = this,
457
- xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
458
- // Access to the native XHR object is required to add event listeners
459
- // for the upload progress event:
460
- if (xhr.upload) {
461
- $(xhr.upload).on('progress', function (e) {
462
- var oe = e.originalEvent;
463
- // Make sure the progress event properties get copied over:
464
- e.lengthComputable = oe.lengthComputable;
465
- e.loaded = oe.loaded;
466
- e.total = oe.total;
467
- that._onProgress(e, options);
468
- });
469
- options.xhr = function () {
470
- return xhr;
471
- };
472
- }
473
- },
474
-
475
- _deinitProgressListener: function (options) {
476
- var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
477
- if (xhr.upload) {
478
- $(xhr.upload).off('progress');
479
- }
480
- },
481
-
482
- _isInstanceOf: function (type, obj) {
483
- // Cross-frame instanceof check
484
- return Object.prototype.toString.call(obj) === '[object ' + type + ']';
485
- },
486
-
487
- _getUniqueFilename: function (name, map) {
488
- // eslint-disable-next-line no-param-reassign
489
- name = String(name);
490
- if (map[name]) {
491
- // eslint-disable-next-line no-param-reassign
492
- name = name.replace(
493
- /(?: \(([\d]+)\))?(\.[^.]+)?$/,
494
- function (_, p1, p2) {
495
- var index = p1 ? Number(p1) + 1 : 1;
496
- var ext = p2 || '';
497
- return ' (' + index + ')' + ext;
498
- }
499
- );
500
- return this._getUniqueFilename(name, map);
501
- }
502
- map[name] = true;
503
- return name;
504
- },
505
-
506
- _initXHRData: function (options) {
507
- var that = this,
508
- formData,
509
- file = options.files[0],
510
- // Ignore non-multipart setting if not supported:
511
- multipart = options.multipart || !$.support.xhrFileUpload,
512
- paramName =
513
- $.type(options.paramName) === 'array'
514
- ? options.paramName[0]
515
- : options.paramName;
516
- options.headers = $.extend({}, options.headers);
517
- if (options.contentRange) {
518
- options.headers['Content-Range'] = options.contentRange;
519
- }
520
- if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
521
- options.headers['Content-Disposition'] =
522
- 'attachment; filename="' +
523
- encodeURI(file.uploadName || file.name) +
524
- '"';
525
- }
526
- if (!multipart) {
527
- options.contentType = file.type || 'application/octet-stream';
528
- options.data = options.blob || file;
529
- } else if ($.support.xhrFormDataFileUpload) {
530
- if (options.postMessage) {
531
- // window.postMessage does not allow sending FormData
532
- // objects, so we just add the File/Blob objects to
533
- // the formData array and let the postMessage window
534
- // create the FormData object out of this array:
535
- formData = this._getFormData(options);
536
- if (options.blob) {
537
- formData.push({
538
- name: paramName,
539
- value: options.blob
540
- });
541
- } else {
542
- $.each(options.files, function (index, file) {
543
- formData.push({
544
- name:
545
- ($.type(options.paramName) === 'array' &&
546
- options.paramName[index]) ||
547
- paramName,
548
- value: file
549
- });
550
- });
551
- }
552
- } else {
553
- if (that._isInstanceOf('FormData', options.formData)) {
554
- formData = options.formData;
555
- } else {
556
- formData = new FormData();
557
- $.each(this._getFormData(options), function (index, field) {
558
- formData.append(field.name, field.value);
559
- });
560
- }
561
- if (options.blob) {
562
- formData.append(
563
- paramName,
564
- options.blob,
565
- file.uploadName || file.name
566
- );
567
- } else {
568
- $.each(options.files, function (index, file) {
569
- // This check allows the tests to run with
570
- // dummy objects:
571
- if (
572
- that._isInstanceOf('File', file) ||
573
- that._isInstanceOf('Blob', file)
574
- ) {
575
- var fileName = file.uploadName || file.name;
576
- if (options.uniqueFilenames) {
577
- fileName = that._getUniqueFilename(
578
- fileName,
579
- options.uniqueFilenames
580
- );
581
- }
582
- formData.append(
583
- ($.type(options.paramName) === 'array' &&
584
- options.paramName[index]) ||
585
- paramName,
586
- file,
587
- fileName
588
- );
589
- }
590
- });
591
- }
592
- }
593
- options.data = formData;
594
- }
595
- // Blob reference is not needed anymore, free memory:
596
- options.blob = null;
597
- },
598
-
599
- _initIframeSettings: function (options) {
600
- var targetHost = $('<a></a>').prop('href', options.url).prop('host');
601
- // Setting the dataType to iframe enables the iframe transport:
602
- options.dataType = 'iframe ' + (options.dataType || '');
603
- // The iframe transport accepts a serialized array as form data:
604
- options.formData = this._getFormData(options);
605
- // Add redirect url to form data on cross-domain uploads:
606
- if (options.redirect && targetHost && targetHost !== location.host) {
607
- options.formData.push({
608
- name: options.redirectParamName || 'redirect',
609
- value: options.redirect
610
- });
611
- }
612
- },
613
-
614
- _initDataSettings: function (options) {
615
- if (this._isXHRUpload(options)) {
616
- if (!this._chunkedUpload(options, true)) {
617
- if (!options.data) {
618
- this._initXHRData(options);
619
- }
620
- this._initProgressListener(options);
621
- }
622
- if (options.postMessage) {
623
- // Setting the dataType to postmessage enables the
624
- // postMessage transport:
625
- options.dataType = 'postmessage ' + (options.dataType || '');
626
- }
627
- } else {
628
- this._initIframeSettings(options);
629
- }
630
- },
631
-
632
- _getParamName: function (options) {
633
- var fileInput = $(options.fileInput),
634
- paramName = options.paramName;
635
- if (!paramName) {
636
- paramName = [];
637
- fileInput.each(function () {
638
- var input = $(this),
639
- name = input.prop('name') || 'files[]',
640
- i = (input.prop('files') || [1]).length;
641
- while (i) {
642
- paramName.push(name);
643
- i -= 1;
644
- }
645
- });
646
- if (!paramName.length) {
647
- paramName = [fileInput.prop('name') || 'files[]'];
648
- }
649
- } else if (!$.isArray(paramName)) {
650
- paramName = [paramName];
651
- }
652
- return paramName;
653
- },
654
-
655
- _initFormSettings: function (options) {
656
- // Retrieve missing options from the input field and the
657
- // associated form, if available:
658
- if (!options.form || !options.form.length) {
659
- options.form = $(options.fileInput.prop('form'));
660
- // If the given file input doesn't have an associated form,
661
- // use the default widget file input's form:
662
- if (!options.form.length) {
663
- options.form = $(this.options.fileInput.prop('form'));
664
- }
665
- }
666
- options.paramName = this._getParamName(options);
667
- if (!options.url) {
668
- options.url = options.form.prop('action') || location.href;
669
- }
670
- // The HTTP request method must be "POST" or "PUT":
671
- options.type = (
672
- options.type ||
673
- ($.type(options.form.prop('method')) === 'string' &&
674
- options.form.prop('method')) ||
675
- ''
676
- ).toUpperCase();
677
- if (
678
- options.type !== 'POST' &&
679
- options.type !== 'PUT' &&
680
- options.type !== 'PATCH'
681
- ) {
682
- options.type = 'POST';
683
- }
684
- if (!options.formAcceptCharset) {
685
- options.formAcceptCharset = options.form.attr('accept-charset');
686
- }
687
- },
688
-
689
- _getAJAXSettings: function (data) {
690
- var options = $.extend({}, this.options, data);
691
- this._initFormSettings(options);
692
- this._initDataSettings(options);
693
- return options;
694
- },
695
-
696
- // jQuery 1.6 doesn't provide .state(),
697
- // while jQuery 1.8+ removed .isRejected() and .isResolved():
698
- _getDeferredState: function (deferred) {
699
- if (deferred.state) {
700
- return deferred.state();
701
- }
702
- if (deferred.isResolved()) {
703
- return 'resolved';
704
- }
705
- if (deferred.isRejected()) {
706
- return 'rejected';
707
- }
708
- return 'pending';
709
- },
710
-
711
- // Maps jqXHR callbacks to the equivalent
712
- // methods of the given Promise object:
713
- _enhancePromise: function (promise) {
714
- promise.success = promise.done;
715
- promise.error = promise.fail;
716
- promise.complete = promise.always;
717
- return promise;
718
- },
719
-
720
- // Creates and returns a Promise object enhanced with
721
- // the jqXHR methods abort, success, error and complete:
722
- _getXHRPromise: function (resolveOrReject, context, args) {
723
- var dfd = $.Deferred(),
724
- promise = dfd.promise();
725
- // eslint-disable-next-line no-param-reassign
726
- context = context || this.options.context || promise;
727
- if (resolveOrReject === true) {
728
- dfd.resolveWith(context, args);
729
- } else if (resolveOrReject === false) {
730
- dfd.rejectWith(context, args);
731
- }
732
- promise.abort = dfd.promise;
733
- return this._enhancePromise(promise);
734
- },
735
-
736
- // Adds convenience methods to the data callback argument:
737
- _addConvenienceMethods: function (e, data) {
738
- var that = this,
739
- getPromise = function (args) {
740
- return $.Deferred().resolveWith(that, args).promise();
741
- };
742
- data.process = function (resolveFunc, rejectFunc) {
743
- if (resolveFunc || rejectFunc) {
744
- data._processQueue = this._processQueue = (this._processQueue ||
745
- getPromise([this]))
746
- [that._promisePipe](function () {
747
- if (data.errorThrown) {
748
- return $.Deferred().rejectWith(that, [data]).promise();
749
- }
750
- return getPromise(arguments);
751
- })
752
- [that._promisePipe](resolveFunc, rejectFunc);
753
- }
754
- return this._processQueue || getPromise([this]);
755
- };
756
- data.submit = function () {
757
- if (this.state() !== 'pending') {
758
- data.jqXHR = this.jqXHR =
759
- that._trigger(
760
- 'submit',
761
- $.Event('submit', { delegatedEvent: e }),
762
- this
763
- ) !== false && that._onSend(e, this);
764
- }
765
- return this.jqXHR || that._getXHRPromise();
766
- };
767
- data.abort = function () {
768
- if (this.jqXHR) {
769
- return this.jqXHR.abort();
770
- }
771
- this.errorThrown = 'abort';
772
- that._trigger('fail', null, this);
773
- return that._getXHRPromise(false);
774
- };
775
- data.state = function () {
776
- if (this.jqXHR) {
777
- return that._getDeferredState(this.jqXHR);
778
- }
779
- if (this._processQueue) {
780
- return that._getDeferredState(this._processQueue);
781
- }
782
- };
783
- data.processing = function () {
784
- return (
785
- !this.jqXHR &&
786
- this._processQueue &&
787
- that._getDeferredState(this._processQueue) === 'pending'
788
- );
789
- };
790
- data.progress = function () {
791
- return this._progress;
792
- };
793
- data.response = function () {
794
- return this._response;
795
- };
796
- },
797
-
798
- // Parses the Range header from the server response
799
- // and returns the uploaded bytes:
800
- _getUploadedBytes: function (jqXHR) {
801
- var range = jqXHR.getResponseHeader('Range'),
802
- parts = range && range.split('-'),
803
- upperBytesPos = parts && parts.length > 1 && parseInt(parts[1], 10);
804
- return upperBytesPos && upperBytesPos + 1;
805
- },
806
-
807
- // Uploads a file in multiple, sequential requests
808
- // by splitting the file up in multiple blob chunks.
809
- // If the second parameter is true, only tests if the file
810
- // should be uploaded in chunks, but does not invoke any
811
- // upload requests:
812
- _chunkedUpload: function (options, testOnly) {
813
- options.uploadedBytes = options.uploadedBytes || 0;
814
- var that = this,
815
- file = options.files[0],
816
- fs = file.size,
817
- ub = options.uploadedBytes,
818
- mcs = options.maxChunkSize || fs,
819
- slice = this._blobSlice,
820
- dfd = $.Deferred(),
821
- promise = dfd.promise(),
822
- jqXHR,
823
- upload;
824
- if (
825
- !(
826
- this._isXHRUpload(options) &&
827
- slice &&
828
- (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)
829
- ) ||
830
- options.data
831
- ) {
832
- return false;
833
- }
834
- if (testOnly) {
835
- return true;
836
- }
837
- if (ub >= fs) {
838
- file.error = options.i18n('uploadedBytes');
839
- return this._getXHRPromise(false, options.context, [
840
- null,
841
- 'error',
842
- file.error
843
- ]);
844
- }
845
- // The chunk upload method:
846
- upload = function () {
847
- // Clone the options object for each chunk upload:
848
- var o = $.extend({}, options),
849
- currentLoaded = o._progress.loaded;
850
- o.blob = slice.call(
851
- file,
852
- ub,
853
- ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
854
- file.type
855
- );
856
- // Store the current chunk size, as the blob itself
857
- // will be dereferenced after data processing:
858
- o.chunkSize = o.blob.size;
859
- // Expose the chunk bytes position range:
860
- o.contentRange =
861
- 'bytes ' + ub + '-' + (ub + o.chunkSize - 1) + '/' + fs;
862
- // Trigger chunkbeforesend to allow form data to be updated for this chunk
863
- that._trigger('chunkbeforesend', null, o);
864
- // Process the upload data (the blob and potential form data):
865
- that._initXHRData(o);
866
- // Add progress listeners for this chunk upload:
867
- that._initProgressListener(o);
868
- jqXHR = (
869
- (that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
870
- that._getXHRPromise(false, o.context)
871
- )
872
- .done(function (result, textStatus, jqXHR) {
873
- ub = that._getUploadedBytes(jqXHR) || ub + o.chunkSize;
874
- // Create a progress event if no final progress event
875
- // with loaded equaling total has been triggered
876
- // for this chunk:
877
- if (currentLoaded + o.chunkSize - o._progress.loaded) {
878
- that._onProgress(
879
- $.Event('progress', {
880
- lengthComputable: true,
881
- loaded: ub - o.uploadedBytes,
882
- total: ub - o.uploadedBytes
883
- }),
884
- o
885
- );
886
- }
887
- options.uploadedBytes = o.uploadedBytes = ub;
888
- o.result = result;
889
- o.textStatus = textStatus;
890
- o.jqXHR = jqXHR;
891
- that._trigger('chunkdone', null, o);
892
- that._trigger('chunkalways', null, o);
893
- if (ub < fs) {
894
- // File upload not yet complete,
895
- // continue with the next chunk:
896
- upload();
897
- } else {
898
- dfd.resolveWith(o.context, [result, textStatus, jqXHR]);
899
- }
900
- })
901
- .fail(function (jqXHR, textStatus, errorThrown) {
902
- o.jqXHR = jqXHR;
903
- o.textStatus = textStatus;
904
- o.errorThrown = errorThrown;
905
- that._trigger('chunkfail', null, o);
906
- that._trigger('chunkalways', null, o);
907
- dfd.rejectWith(o.context, [jqXHR, textStatus, errorThrown]);
908
- })
909
- .always(function () {
910
- that._deinitProgressListener(o);
911
- });
912
- };
913
- this._enhancePromise(promise);
914
- promise.abort = function () {
915
- return jqXHR.abort();
916
- };
917
- upload();
918
- return promise;
919
- },
920
-
921
- _beforeSend: function (e, data) {
922
- if (this._active === 0) {
923
- // the start callback is triggered when an upload starts
924
- // and no other uploads are currently running,
925
- // equivalent to the global ajaxStart event:
926
- this._trigger('start');
927
- // Set timer for global bitrate progress calculation:
928
- this._bitrateTimer = new this._BitrateTimer();
929
- // Reset the global progress values:
930
- this._progress.loaded = this._progress.total = 0;
931
- this._progress.bitrate = 0;
932
- }
933
- // Make sure the container objects for the .response() and
934
- // .progress() methods on the data object are available
935
- // and reset to their initial state:
936
- this._initResponseObject(data);
937
- this._initProgressObject(data);
938
- data._progress.loaded = data.loaded = data.uploadedBytes || 0;
939
- data._progress.total = data.total = this._getTotal(data.files) || 1;
940
- data._progress.bitrate = data.bitrate = 0;
941
- this._active += 1;
942
- // Initialize the global progress values:
943
- this._progress.loaded += data.loaded;
944
- this._progress.total += data.total;
945
- },
946
-
947
- _onDone: function (result, textStatus, jqXHR, options) {
948
- var total = options._progress.total,
949
- response = options._response;
950
- if (options._progress.loaded < total) {
951
- // Create a progress event if no final progress event
952
- // with loaded equaling total has been triggered:
953
- this._onProgress(
954
- $.Event('progress', {
955
- lengthComputable: true,
956
- loaded: total,
957
- total: total
958
- }),
959
- options
960
- );
961
- }
962
- response.result = options.result = result;
963
- response.textStatus = options.textStatus = textStatus;
964
- response.jqXHR = options.jqXHR = jqXHR;
965
- this._trigger('done', null, options);
966
- },
967
-
968
- _onFail: function (jqXHR, textStatus, errorThrown, options) {
969
- var response = options._response;
970
- if (options.recalculateProgress) {
971
- // Remove the failed (error or abort) file upload from
972
- // the global progress calculation:
973
- this._progress.loaded -= options._progress.loaded;
974
- this._progress.total -= options._progress.total;
975
- }
976
- response.jqXHR = options.jqXHR = jqXHR;
977
- response.textStatus = options.textStatus = textStatus;
978
- response.errorThrown = options.errorThrown = errorThrown;
979
- this._trigger('fail', null, options);
980
- },
981
-
982
- _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
983
- // jqXHRorResult, textStatus and jqXHRorError are added to the
984
- // options object via done and fail callbacks
985
- this._trigger('always', null, options);
986
- },
987
-
988
- _onSend: function (e, data) {
989
- if (!data.submit) {
990
- this._addConvenienceMethods(e, data);
991
- }
992
- var that = this,
993
- jqXHR,
994
- aborted,
995
- slot,
996
- pipe,
997
- options = that._getAJAXSettings(data),
998
- send = function () {
999
- that._sending += 1;
1000
- // Set timer for bitrate progress calculation:
1001
- options._bitrateTimer = new that._BitrateTimer();
1002
- jqXHR =
1003
- jqXHR ||
1004
- (
1005
- ((aborted ||
1006
- that._trigger(
1007
- 'send',
1008
- $.Event('send', { delegatedEvent: e }),
1009
- options
1010
- ) === false) &&
1011
- that._getXHRPromise(false, options.context, aborted)) ||
1012
- that._chunkedUpload(options) ||
1013
- $.ajax(options)
1014
- )
1015
- .done(function (result, textStatus, jqXHR) {
1016
- that._onDone(result, textStatus, jqXHR, options);
1017
- })
1018
- .fail(function (jqXHR, textStatus, errorThrown) {
1019
- that._onFail(jqXHR, textStatus, errorThrown, options);
1020
- })
1021
- .always(function (jqXHRorResult, textStatus, jqXHRorError) {
1022
- that._deinitProgressListener(options);
1023
- that._onAlways(
1024
- jqXHRorResult,
1025
- textStatus,
1026
- jqXHRorError,
1027
- options
1028
- );
1029
- that._sending -= 1;
1030
- that._active -= 1;
1031
- if (
1032
- options.limitConcurrentUploads &&
1033
- options.limitConcurrentUploads > that._sending
1034
- ) {
1035
- // Start the next queued upload,
1036
- // that has not been aborted:
1037
- var nextSlot = that._slots.shift();
1038
- while (nextSlot) {
1039
- if (that._getDeferredState(nextSlot) === 'pending') {
1040
- nextSlot.resolve();
1041
- break;
1042
- }
1043
- nextSlot = that._slots.shift();
1044
- }
1045
- }
1046
- if (that._active === 0) {
1047
- // The stop callback is triggered when all uploads have
1048
- // been completed, equivalent to the global ajaxStop event:
1049
- that._trigger('stop');
1050
- }
1051
- });
1052
- return jqXHR;
1053
- };
1054
- this._beforeSend(e, options);
1055
- if (
1056
- this.options.sequentialUploads ||
1057
- (this.options.limitConcurrentUploads &&
1058
- this.options.limitConcurrentUploads <= this._sending)
1059
- ) {
1060
- if (this.options.limitConcurrentUploads > 1) {
1061
- slot = $.Deferred();
1062
- this._slots.push(slot);
1063
- pipe = slot[that._promisePipe](send);
1064
- } else {
1065
- this._sequence = this._sequence[that._promisePipe](send, send);
1066
- pipe = this._sequence;
1067
- }
1068
- // Return the piped Promise object, enhanced with an abort method,
1069
- // which is delegated to the jqXHR object of the current upload,
1070
- // and jqXHR callbacks mapped to the equivalent Promise methods:
1071
- pipe.abort = function () {
1072
- aborted = [undefined, 'abort', 'abort'];
1073
- if (!jqXHR) {
1074
- if (slot) {
1075
- slot.rejectWith(options.context, aborted);
1076
- }
1077
- return send();
1078
- }
1079
- return jqXHR.abort();
1080
- };
1081
- return this._enhancePromise(pipe);
1082
- }
1083
- return send();
1084
- },
1085
-
1086
- _onAdd: function (e, data) {
1087
- var that = this,
1088
- result = true,
1089
- options = $.extend({}, this.options, data),
1090
- files = data.files,
1091
- filesLength = files.length,
1092
- limit = options.limitMultiFileUploads,
1093
- limitSize = options.limitMultiFileUploadSize,
1094
- overhead = options.limitMultiFileUploadSizeOverhead,
1095
- batchSize = 0,
1096
- paramName = this._getParamName(options),
1097
- paramNameSet,
1098
- paramNameSlice,
1099
- fileSet,
1100
- i,
1101
- j = 0;
1102
- if (!filesLength) {
1103
- return false;
1104
- }
1105
- if (limitSize && files[0].size === undefined) {
1106
- limitSize = undefined;
1107
- }
1108
- if (
1109
- !(options.singleFileUploads || limit || limitSize) ||
1110
- !this._isXHRUpload(options)
1111
- ) {
1112
- fileSet = [files];
1113
- paramNameSet = [paramName];
1114
- } else if (!(options.singleFileUploads || limitSize) && limit) {
1115
- fileSet = [];
1116
- paramNameSet = [];
1117
- for (i = 0; i < filesLength; i += limit) {
1118
- fileSet.push(files.slice(i, i + limit));
1119
- paramNameSlice = paramName.slice(i, i + limit);
1120
- if (!paramNameSlice.length) {
1121
- paramNameSlice = paramName;
1122
- }
1123
- paramNameSet.push(paramNameSlice);
1124
- }
1125
- } else if (!options.singleFileUploads && limitSize) {
1126
- fileSet = [];
1127
- paramNameSet = [];
1128
- for (i = 0; i < filesLength; i = i + 1) {
1129
- batchSize += files[i].size + overhead;
1130
- if (
1131
- i + 1 === filesLength ||
1132
- batchSize + files[i + 1].size + overhead > limitSize ||
1133
- (limit && i + 1 - j >= limit)
1134
- ) {
1135
- fileSet.push(files.slice(j, i + 1));
1136
- paramNameSlice = paramName.slice(j, i + 1);
1137
- if (!paramNameSlice.length) {
1138
- paramNameSlice = paramName;
1139
- }
1140
- paramNameSet.push(paramNameSlice);
1141
- j = i + 1;
1142
- batchSize = 0;
1143
- }
1144
- }
1145
- } else {
1146
- paramNameSet = paramName;
1147
- }
1148
- data.originalFiles = files;
1149
- $.each(fileSet || files, function (index, element) {
1150
- var newData = $.extend({}, data);
1151
- newData.files = fileSet ? element : [element];
1152
- newData.paramName = paramNameSet[index];
1153
- that._initResponseObject(newData);
1154
- that._initProgressObject(newData);
1155
- that._addConvenienceMethods(e, newData);
1156
- result = that._trigger(
1157
- 'add',
1158
- $.Event('add', { delegatedEvent: e }),
1159
- newData
1160
- );
1161
- return result;
1162
- });
1163
- return result;
1164
- },
1165
-
1166
- _replaceFileInput: function (data) {
1167
- var input = data.fileInput,
1168
- inputClone = input.clone(true),
1169
- restoreFocus = input.is(document.activeElement);
1170
- // Add a reference for the new cloned file input to the data argument:
1171
- data.fileInputClone = inputClone;
1172
- $('<form></form>').append(inputClone)[0].reset();
1173
- // Detaching allows to insert the fileInput on another form
1174
- // without losing the file input value:
1175
- input.after(inputClone).detach();
1176
- // If the fileInput had focus before it was detached,
1177
- // restore focus to the inputClone.
1178
- if (restoreFocus) {
1179
- inputClone.trigger('focus');
1180
- }
1181
- // Avoid memory leaks with the detached file input:
1182
- $.cleanData(input.off('remove'));
1183
- // Replace the original file input element in the fileInput
1184
- // elements set with the clone, which has been copied including
1185
- // event handlers:
1186
- this.options.fileInput = this.options.fileInput.map(function (i, el) {
1187
- if (el === input[0]) {
1188
- return inputClone[0];
1189
- }
1190
- return el;
1191
- });
1192
- // If the widget has been initialized on the file input itself,
1193
- // override this.element with the file input clone:
1194
- if (input[0] === this.element[0]) {
1195
- this.element = inputClone;
1196
- }
1197
- },
1198
-
1199
- _handleFileTreeEntry: function (entry, path) {
1200
- var that = this,
1201
- dfd = $.Deferred(),
1202
- entries = [],
1203
- dirReader,
1204
- errorHandler = function (e) {
1205
- if (e && !e.entry) {
1206
- e.entry = entry;
1207
- }
1208
- // Since $.when returns immediately if one
1209
- // Deferred is rejected, we use resolve instead.
1210
- // This allows valid files and invalid items
1211
- // to be returned together in one set:
1212
- dfd.resolve([e]);
1213
- },
1214
- successHandler = function (entries) {
1215
- that
1216
- ._handleFileTreeEntries(entries, path + entry.name + '/')
1217
- .done(function (files) {
1218
- dfd.resolve(files);
1219
- })
1220
- .fail(errorHandler);
1221
- },
1222
- readEntries = function () {
1223
- dirReader.readEntries(function (results) {
1224
- if (!results.length) {
1225
- successHandler(entries);
1226
- } else {
1227
- entries = entries.concat(results);
1228
- readEntries();
1229
- }
1230
- }, errorHandler);
1231
- };
1232
- // eslint-disable-next-line no-param-reassign
1233
- path = path || '';
1234
- if (entry.isFile) {
1235
- if (entry._file) {
1236
- // Workaround for Chrome bug #149735
1237
- entry._file.relativePath = path;
1238
- dfd.resolve(entry._file);
1239
- } else {
1240
- entry.file(function (file) {
1241
- file.relativePath = path;
1242
- dfd.resolve(file);
1243
- }, errorHandler);
1244
- }
1245
- } else if (entry.isDirectory) {
1246
- dirReader = entry.createReader();
1247
- readEntries();
1248
- } else {
1249
- // Return an empty list for file system items
1250
- // other than files or directories:
1251
- dfd.resolve([]);
1252
- }
1253
- return dfd.promise();
1254
- },
1255
-
1256
- _handleFileTreeEntries: function (entries, path) {
1257
- var that = this;
1258
- return $.when
1259
- .apply(
1260
- $,
1261
- $.map(entries, function (entry) {
1262
- return that._handleFileTreeEntry(entry, path);
1263
- })
1264
- )
1265
- [this._promisePipe](function () {
1266
- return Array.prototype.concat.apply([], arguments);
1267
- });
1268
- },
1269
-
1270
- _getDroppedFiles: function (dataTransfer) {
1271
- // eslint-disable-next-line no-param-reassign
1272
- dataTransfer = dataTransfer || {};
1273
- var items = dataTransfer.items;
1274
- if (
1275
- items &&
1276
- items.length &&
1277
- (items[0].webkitGetAsEntry || items[0].getAsEntry)
1278
- ) {
1279
- return this._handleFileTreeEntries(
1280
- $.map(items, function (item) {
1281
- var entry;
1282
- if (item.webkitGetAsEntry) {
1283
- entry = item.webkitGetAsEntry();
1284
- if (entry) {
1285
- // Workaround for Chrome bug #149735:
1286
- entry._file = item.getAsFile();
1287
- }
1288
- return entry;
1289
- }
1290
- return item.getAsEntry();
1291
- })
1292
- );
1293
- }
1294
- return $.Deferred().resolve($.makeArray(dataTransfer.files)).promise();
1295
- },
1296
-
1297
- _getSingleFileInputFiles: function (fileInput) {
1298
- // eslint-disable-next-line no-param-reassign
1299
- fileInput = $(fileInput);
1300
- var entries = fileInput.prop('entries'),
1301
- files,
1302
- value;
1303
- if (entries && entries.length) {
1304
- return this._handleFileTreeEntries(entries);
1305
- }
1306
- files = $.makeArray(fileInput.prop('files'));
1307
- if (!files.length) {
1308
- value = fileInput.prop('value');
1309
- if (!value) {
1310
- return $.Deferred().resolve([]).promise();
1311
- }
1312
- // If the files property is not available, the browser does not
1313
- // support the File API and we add a pseudo File object with
1314
- // the input value as name with path information removed:
1315
- files = [{ name: value.replace(/^.*\\/, '') }];
1316
- } else if (files[0].name === undefined && files[0].fileName) {
1317
- // File normalization for Safari 4 and Firefox 3:
1318
- $.each(files, function (index, file) {
1319
- file.name = file.fileName;
1320
- file.size = file.fileSize;
1321
- });
1322
- }
1323
- return $.Deferred().resolve(files).promise();
1324
- },
1325
-
1326
- _getFileInputFiles: function (fileInput) {
1327
- if (!(fileInput instanceof $) || fileInput.length === 1) {
1328
- return this._getSingleFileInputFiles(fileInput);
1329
- }
1330
- return $.when
1331
- .apply($, $.map(fileInput, this._getSingleFileInputFiles))
1332
- [this._promisePipe](function () {
1333
- return Array.prototype.concat.apply([], arguments);
1334
- });
1335
- },
1336
-
1337
- _onChange: function (e) {
1338
- var that = this,
1339
- data = {
1340
- fileInput: $(e.target),
1341
- form: $(e.target.form)
1342
- };
1343
- this._getFileInputFiles(data.fileInput).always(function (files) {
1344
- data.files = files;
1345
- if (that.options.replaceFileInput) {
1346
- that._replaceFileInput(data);
1347
- }
1348
- if (
1349
- that._trigger(
1350
- 'change',
1351
- $.Event('change', { delegatedEvent: e }),
1352
- data
1353
- ) !== false
1354
- ) {
1355
- that._onAdd(e, data);
1356
- }
1357
- });
1358
- },
1359
-
1360
- _onPaste: function (e) {
1361
- var items =
1362
- e.originalEvent &&
1363
- e.originalEvent.clipboardData &&
1364
- e.originalEvent.clipboardData.items,
1365
- data = { files: [] };
1366
- if (items && items.length) {
1367
- $.each(items, function (index, item) {
1368
- var file = item.getAsFile && item.getAsFile();
1369
- if (file) {
1370
- data.files.push(file);
1371
- }
1372
- });
1373
- if (
1374
- this._trigger(
1375
- 'paste',
1376
- $.Event('paste', { delegatedEvent: e }),
1377
- data
1378
- ) !== false
1379
- ) {
1380
- this._onAdd(e, data);
1381
- }
1382
- }
1383
- },
1384
-
1385
- _onDrop: function (e) {
1386
- e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1387
- var that = this,
1388
- dataTransfer = e.dataTransfer,
1389
- data = {};
1390
- if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
1391
- e.preventDefault();
1392
- this._getDroppedFiles(dataTransfer).always(function (files) {
1393
- data.files = files;
1394
- if (
1395
- that._trigger(
1396
- 'drop',
1397
- $.Event('drop', { delegatedEvent: e }),
1398
- data
1399
- ) !== false
1400
- ) {
1401
- that._onAdd(e, data);
1402
- }
1403
- });
1404
- }
1405
- },
1406
-
1407
- _onDragOver: getDragHandler('dragover'),
1408
-
1409
- _onDragEnter: getDragHandler('dragenter'),
1410
-
1411
- _onDragLeave: getDragHandler('dragleave'),
1412
-
1413
- _initEventHandlers: function () {
1414
- if (this._isXHRUpload(this.options)) {
1415
- this._on(this.options.dropZone, {
1416
- dragover: this._onDragOver,
1417
- drop: this._onDrop,
1418
- // event.preventDefault() on dragenter is required for IE10+:
1419
- dragenter: this._onDragEnter,
1420
- // dragleave is not required, but added for completeness:
1421
- dragleave: this._onDragLeave
1422
- });
1423
- this._on(this.options.pasteZone, {
1424
- paste: this._onPaste
1425
- });
1426
- }
1427
- if ($.support.fileInput) {
1428
- this._on(this.options.fileInput, {
1429
- change: this._onChange
1430
- });
1431
- }
1432
- },
1433
-
1434
- _destroyEventHandlers: function () {
1435
- this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
1436
- this._off(this.options.pasteZone, 'paste');
1437
- this._off(this.options.fileInput, 'change');
1438
- },
1439
-
1440
- _destroy: function () {
1441
- this._destroyEventHandlers();
1442
- },
1443
-
1444
- _setOption: function (key, value) {
1445
- var reinit = $.inArray(key, this._specialOptions) !== -1;
1446
- if (reinit) {
1447
- this._destroyEventHandlers();
1448
- }
1449
- this._super(key, value);
1450
- if (reinit) {
1451
- this._initSpecialOptions();
1452
- this._initEventHandlers();
1453
- }
1454
- },
1455
-
1456
- _initSpecialOptions: function () {
1457
- var options = this.options;
1458
- if (options.fileInput === undefined) {
1459
- options.fileInput = this.element.is('input[type="file"]')
1460
- ? this.element
1461
- : this.element.find('input[type="file"]');
1462
- } else if (!(options.fileInput instanceof $)) {
1463
- options.fileInput = $(options.fileInput);
1464
- }
1465
- if (!(options.dropZone instanceof $)) {
1466
- options.dropZone = $(options.dropZone);
1467
- }
1468
- if (!(options.pasteZone instanceof $)) {
1469
- options.pasteZone = $(options.pasteZone);
1470
- }
1471
- },
1472
-
1473
- _getRegExp: function (str) {
1474
- var parts = str.split('/'),
1475
- modifiers = parts.pop();
1476
- parts.shift();
1477
- return new RegExp(parts.join('/'), modifiers);
1478
- },
1479
-
1480
- _isRegExpOption: function (key, value) {
1481
- return (
1482
- key !== 'url' &&
1483
- $.type(value) === 'string' &&
1484
- /^\/.*\/[igm]{0,3}$/.test(value)
1485
- );
1486
- },
1487
-
1488
- _initDataAttributes: function () {
1489
- var that = this,
1490
- options = this.options,
1491
- data = this.element.data();
1492
- // Initialize options set via HTML5 data-attributes:
1493
- $.each(this.element[0].attributes, function (index, attr) {
1494
- var key = attr.name.toLowerCase(),
1495
- value;
1496
- if (/^data-/.test(key)) {
1497
- // Convert hyphen-ated key to camelCase:
1498
- key = key.slice(5).replace(/-[a-z]/g, function (str) {
1499
- return str.charAt(1).toUpperCase();
1500
- });
1501
- value = data[key];
1502
- if (that._isRegExpOption(key, value)) {
1503
- value = that._getRegExp(value);
1504
- }
1505
- options[key] = value;
1506
- }
1507
- });
1508
- },
1509
-
1510
- _create: function () {
1511
- this._initDataAttributes();
1512
- this._initSpecialOptions();
1513
- this._slots = [];
1514
- this._sequence = this._getXHRPromise(true);
1515
- this._sending = this._active = 0;
1516
- this._initProgressObject(this);
1517
- this._initEventHandlers();
1518
- },
1519
-
1520
- // This method is exposed to the widget API and allows to query
1521
- // the number of active uploads:
1522
- active: function () {
1523
- return this._active;
1524
- },
1525
-
1526
- // This method is exposed to the widget API and allows to query
1527
- // the widget upload progress.
1528
- // It returns an object with loaded, total and bitrate properties
1529
- // for the running uploads:
1530
- progress: function () {
1531
- return this._progress;
1532
- },
1533
-
1534
- // This method is exposed to the widget API and allows adding files
1535
- // using the fileupload API. The data parameter accepts an object which
1536
- // must have a files property and can contain additional options:
1537
- // .fileupload('add', {files: filesList});
1538
- add: function (data) {
1539
- var that = this;
1540
- if (!data || this.options.disabled) {
1541
- return;
1542
- }
1543
- if (data.fileInput && !data.files) {
1544
- this._getFileInputFiles(data.fileInput).always(function (files) {
1545
- data.files = files;
1546
- that._onAdd(null, data);
1547
- });
1548
- } else {
1549
- data.files = $.makeArray(data.files);
1550
- this._onAdd(null, data);
1551
- }
1552
- },
1553
-
1554
- // This method is exposed to the widget API and allows sending files
1555
- // using the fileupload API. The data parameter accepts an object which
1556
- // must have a files or fileInput property and can contain additional options:
1557
- // .fileupload('send', {files: filesList});
1558
- // The method returns a Promise object for the file upload call.
1559
- send: function (data) {
1560
- if (data && !this.options.disabled) {
1561
- if (data.fileInput && !data.files) {
1562
- var that = this,
1563
- dfd = $.Deferred(),
1564
- promise = dfd.promise(),
1565
- jqXHR,
1566
- aborted;
1567
- promise.abort = function () {
1568
- aborted = true;
1569
- if (jqXHR) {
1570
- return jqXHR.abort();
1571
- }
1572
- dfd.reject(null, 'abort', 'abort');
1573
- return promise;
1574
- };
1575
- this._getFileInputFiles(data.fileInput).always(function (files) {
1576
- if (aborted) {
1577
- return;
1578
- }
1579
- if (!files.length) {
1580
- dfd.reject();
1581
- return;
1582
- }
1583
- data.files = files;
1584
- jqXHR = that._onSend(null, data);
1585
- jqXHR.then(
1586
- function (result, textStatus, jqXHR) {
1587
- dfd.resolve(result, textStatus, jqXHR);
1588
- },
1589
- function (jqXHR, textStatus, errorThrown) {
1590
- dfd.reject(jqXHR, textStatus, errorThrown);
1591
- }
1592
- );
1593
- });
1594
- return this._enhancePromise(promise);
1595
- }
1596
- data.files = $.makeArray(data.files);
1597
- if (data.files.length) {
1598
- return this._onSend(null, data);
1599
- }
1600
- }
1601
- return this._getXHRPromise(false, data && data.context);
1602
- }
1603
- });
1604
- });