· 7 years ago · Apr 06, 2019, 06:30 PM
1"use strict";
2
3var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
4
5function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
6
7function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
8
9function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
11/*
12 *
13 * More info at [www.dropzonejs.com](http://www.dropzonejs.com)
14 *
15 * Copyright (c) 2012, Matias Meno
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this software and associated documentation files (the "Software"), to deal
19 * in the Software without restriction, including without limitation the rights
20 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 * copies of the Software, and to permit persons to whom the Software is
22 * furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included in
25 * all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 * THE SOFTWARE.
34 *
35 */
36
37// The Emitter class provides the ability to call `.on()` on Dropzone to listen
38// to events.
39// It is strongly based on component's emitter class, and I removed the
40// functionality because of the dependency hell with different frameworks.
41var Emitter = function () {
42 function Emitter() {
43 _classCallCheck(this, Emitter);
44 }
45
46 _createClass(Emitter, [{
47 key: "on",
48
49 // Add an event listener for given event
50 value: function on(event, fn) {
51 this._callbacks = this._callbacks || {};
52 // Create namespace for this event
53 if (!this._callbacks[event]) {
54 this._callbacks[event] = [];
55 }
56 this._callbacks[event].push(fn);
57 return this;
58 }
59 }, {
60 key: "emit",
61 value: function emit(event) {
62 this._callbacks = this._callbacks || {};
63 var callbacks = this._callbacks[event];
64
65 if (callbacks) {
66 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
67 args[_key - 1] = arguments[_key];
68 }
69
70 for (var _iterator = callbacks, _isArray = true, _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
71 var _ref;
72
73 if (_isArray) {
74 if (_i >= _iterator.length) break;
75 _ref = _iterator[_i++];
76 } else {
77 _i = _iterator.next();
78 if (_i.done) break;
79 _ref = _i.value;
80 }
81
82 var callback = _ref;
83
84 callback.apply(this, args);
85 }
86 }
87
88 return this;
89 }
90
91 // Remove event listener for given event. If fn is not provided, all event
92 // listeners for that event will be removed. If neither is provided, all
93 // event listeners will be removed.
94
95 }, {
96 key: "off",
97 value: function off(event, fn) {
98 if (!this._callbacks || arguments.length === 0) {
99 this._callbacks = {};
100 return this;
101 }
102
103 // specific event
104 var callbacks = this._callbacks[event];
105 if (!callbacks) {
106 return this;
107 }
108
109 // remove all handlers
110 if (arguments.length === 1) {
111 delete this._callbacks[event];
112 return this;
113 }
114
115 // remove specific handler
116 for (var i = 0; i < callbacks.length; i++) {
117 var callback = callbacks[i];
118 if (callback === fn) {
119 callbacks.splice(i, 1);
120 break;
121 }
122 }
123
124 return this;
125 }
126 }]);
127
128 return Emitter;
129}();
130
131var Dropzone = function (_Emitter) {
132 _inherits(Dropzone, _Emitter);
133
134 _createClass(Dropzone, null, [{
135 key: "initClass",
136 value: function initClass() {
137
138 // Exposing the emitter class, mainly for tests
139 this.prototype.Emitter = Emitter;
140
141 /*
142 This is a list of all available events you can register on a dropzone object.
143 You can register an event handler like this:
144 dropzone.on("dragEnter", function() { });
145 */
146 this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"];
147
148 this.prototype.defaultOptions = {
149 /**
150 * Has to be specified on elements other than form (or when the form
151 * doesn't have an `action` attribute). You can also
152 * provide a function that will be called with `files` and
153 * must return the url (since `v3.12.0`)
154 */
155 url: null,
156
157 /**
158 * Can be changed to `"put"` if necessary. You can also provide a function
159 * that will be called with `files` and must return the method (since `v3.12.0`).
160 */
161 method: "post",
162
163 /**
164 * Will be set on the XHRequest.
165 */
166 withCredentials: false,
167
168 /**
169 * The timeout for the XHR requests in milliseconds (since `v4.4.0`).
170 */
171 timeout: 30000,
172
173 /**
174 * How many file uploads to process in parallel (See the
175 * Enqueuing file uploads* documentation section for more info)
176 */
177 parallelUploads: 2,
178
179 /**
180 * Whether to send multiple files in one request. If
181 * this it set to true, then the fallback file input element will
182 * have the `multiple` attribute as well. This option will
183 * also trigger additional events (like `processingmultiple`). See the events
184 * documentation section for more information.
185 */
186 uploadMultiple: false,
187
188 /**
189 * Whether you want files to be uploaded in chunks to your server. This can't be
190 * used in combination with `uploadMultiple`.
191 *
192 * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload.
193 */
194 chunking: false,
195
196 /**
197 * If `chunking` is enabled, this defines whether **every** file should be chunked,
198 * even if the file size is below chunkSize. This means, that the additional chunk
199 * form data will be submitted and the `chunksUploaded` callback will be invoked.
200 */
201 forceChunking: false,
202
203 /**
204 * If `chunking` is `true`, then this defines the chunk size in bytes.
205 */
206 chunkSize: 2000000,
207
208 /**
209 * If `true`, the individual chunks of a file are being uploaded simultaneously.
210 */
211 parallelChunkUploads: false,
212
213 /**
214 * Whether a chunk should be retried if it fails.
215 */
216 retryChunks: false,
217
218 /**
219 * If `retryChunks` is true, how many times should it be retried.
220 */
221 retryChunksLimit: 3,
222
223 /**
224 * If not `null` defines how many files this Dropzone handles. If it exceeds,
225 * the event `maxfilesexceeded` will be called. The dropzone element gets the
226 * class `dz-max-files-reached` accordingly so you can provide visual feedback.
227 */
228 maxFilesize: 256,
229
230 /**
231 * The name of the file param that gets transferred.
232 * **NOTE**: If you have the option `uploadMultiple` set to `true`, then
233 * Dropzone will append `[]` to the name.
234 */
235 paramName: "file",
236
237 /**
238 * Whether thumbnails for images should be generated
239 */
240 createImageThumbnails: true,
241
242 /**
243 * In MB. When the filename exceeds this limit, the thumbnail will not be generated.
244 */
245 maxThumbnailFilesize: 10,
246
247 /**
248 * If `null`, the ratio of the image will be used to calculate it.
249 */
250 thumbnailWidth: 120,
251
252 /**
253 * The same as `thumbnailWidth`. If both are null, images will not be resized.
254 */
255 thumbnailHeight: 120,
256
257 /**
258 * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided.
259 * Can be either `contain` or `crop`.
260 */
261 thumbnailMethod: 'crop',
262
263 /**
264 * If set, images will be resized to these dimensions before being **uploaded**.
265 * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect
266 * ratio of the file will be preserved.
267 *
268 * The `options.transformFile` function uses these options, so if the `transformFile` function
269 * is overridden, these options don't do anything.
270 */
271 resizeWidth: null,
272
273 /**
274 * See `resizeWidth`.
275 */
276 resizeHeight: null,
277
278 /**
279 * The mime type of the resized image (before it gets uploaded to the server).
280 * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`.
281 * See `resizeWidth` for more information.
282 */
283 resizeMimeType: null,
284
285 /**
286 * The quality of the resized images. See `resizeWidth`.
287 */
288 resizeQuality: 0.8,
289
290 /**
291 * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided.
292 * Can be either `contain` or `crop`.
293 */
294 resizeMethod: 'contain',
295
296 /**
297 * The base that is used to calculate the filesize. You can change this to
298 * 1024 if you would rather display kibibytes, mebibytes, etc...
299 * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`.
300 * You can change this to `1024` if you don't care about validity.
301 */
302 filesizeBase: 1000,
303
304 /**
305 * Can be used to limit the maximum number of files that will be handled by this Dropzone
306 */
307 maxFiles: null,
308
309 /**
310 * An optional object to send additional headers to the server. Eg:
311 * `{ "My-Awesome-Header": "header value" }`
312 */
313 headers: null,
314
315 /**
316 * If `true`, the dropzone element itself will be clickable, if `false`
317 * nothing will be clickable.
318 *
319 * You can also pass an HTML element, a CSS selector (for multiple elements)
320 * or an array of those. In that case, all of those elements will trigger an
321 * upload when clicked.
322 */
323 clickable: true,
324
325 /**
326 * Whether hidden files in directories should be ignored.
327 */
328 ignoreHiddenFiles: true,
329
330 /**
331 * The default implementation of `accept` checks the file's mime type or
332 * extension against this list. This is a comma separated list of mime
333 * types or file extensions.
334 *
335 * Eg.: `image/*,application/pdf,.psd`
336 *
337 * If the Dropzone is `clickable` this option will also be used as
338 * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept)
339 * parameter on the hidden file input as well.
340 */
341 acceptedFiles: null,
342
343 /**
344 * **Deprecated!**
345 * Use acceptedFiles instead.
346 */
347 acceptedMimeTypes: null,
348
349 /**
350 * If false, files will be added to the queue but the queue will not be
351 * processed automatically.
352 * This can be useful if you need some additional user input before sending
353 * files (or if you want want all files sent at once).
354 * If you're ready to send the file simply call `myDropzone.processQueue()`.
355 *
356 * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation
357 * section for more information.
358 */
359 autoProcessQueue: true,
360
361 /**
362 * If false, files added to the dropzone will not be queued by default.
363 * You'll have to call `enqueueFile(file)` manually.
364 */
365 autoQueue: true,
366
367 /**
368 * If `true`, this will add a link to every file preview to remove or cancel (if
369 * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation`
370 * and `dictRemoveFile` options are used for the wording.
371 */
372 addRemoveLinks: false,
373
374 /**
375 * Defines where to display the file previews – if `null` the
376 * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS
377 * selector. The element should have the `dropzone-previews` class so
378 * the previews are displayed properly.
379 */
380 previewsContainer: null,
381
382 /**
383 * This is the element the hidden input field (which is used when clicking on the
384 * dropzone to trigger file selection) will be appended to. This might
385 * be important in case you use frameworks to switch the content of your page.
386 *
387 * Can be a selector string, or an element directly.
388 */
389 hiddenInputContainer: "body",
390
391 /**
392 * If null, no capture type will be specified
393 * If camera, mobile devices will skip the file selection and choose camera
394 * If microphone, mobile devices will skip the file selection and choose the microphone
395 * If camcorder, mobile devices will skip the file selection and choose the camera in video mode
396 * On apple devices multiple must be set to false. AcceptedFiles may need to
397 * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*").
398 */
399 capture: null,
400
401 /**
402 * **Deprecated**. Use `renameFile` instead.
403 */
404 renameFilename: null,
405
406 /**
407 * A function that is invoked before the file is uploaded to the server and renames the file.
408 * This function gets the `File` as argument and can use the `file.name`. The actual name of the
409 * file that gets used during the upload can be accessed through `file.upload.filename`.
410 */
411 renameFile: null,
412
413 /**
414 * If `true` the fallback will be forced. This is very useful to test your server
415 * implementations first and make sure that everything works as
416 * expected without dropzone if you experience problems, and to test
417 * how your fallbacks will look.
418 */
419 forceFallback: false,
420
421 /**
422 * The text used before any files are dropped.
423 */
424 dictDefaultMessage: "Drop files here to upload",
425
426 /**
427 * The text that replaces the default message text it the browser is not supported.
428 */
429 dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
430
431 /**
432 * The text that will be added before the fallback form.
433 * If you provide a fallback element yourself, or if this option is `null` this will
434 * be ignored.
435 */
436 dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
437
438 /**
439 * If the filesize is too big.
440 * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values.
441 */
442 dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
443
444 /**
445 * If the file doesn't match the file type.
446 */
447 dictInvalidFileType: "You can't upload files of this type.",
448
449 /**
450 * If the server response was invalid.
451 * `{{statusCode}}` will be replaced with the servers status code.
452 */
453 dictResponseError: "Server responded with {{statusCode}} code.",
454
455 /**
456 * If `addRemoveLinks` is true, the text to be used for the cancel upload link.
457 */
458 dictCancelUpload: "Cancel upload",
459
460 /**
461 * The text that is displayed if an upload was manually canceled
462 */
463 dictUploadCanceled: "Upload canceled.",
464
465 /**
466 * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload.
467 */
468 dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
469
470 /**
471 * If `addRemoveLinks` is true, the text to be used to remove a file.
472 */
473 dictRemoveFile: "Remove file",
474
475 /**
476 * If this is not null, then the user will be prompted before removing a file.
477 */
478 dictRemoveFileConfirmation: null,
479
480 /**
481 * Displayed if `maxFiles` is st and exceeded.
482 * The string `{{maxFiles}}` will be replaced by the configuration value.
483 */
484 dictMaxFilesExceeded: "You can not upload any more files.",
485
486 /**
487 * Allows you to translate the different units. Starting with `tb` for terabytes and going down to
488 * `b` for bytes.
489 */
490 dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" },
491 /**
492 * Called when dropzone initialized
493 * You can add event listeners here
494 */
495 init: function init() {},
496
497
498 /**
499 * Can be an **object** of additional parameters to transfer to the server, **or** a `Function`
500 * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case
501 * of a function, this needs to return a map.
502 *
503 * The default implementation does nothing for normal uploads, but adds relevant information for
504 * chunked uploads.
505 *
506 * This is the same as adding hidden input fields in the form element.
507 */
508 params: function params(files, xhr, chunk) {
509 if (chunk) {
510 return {
511 dzuuid: chunk.file.upload.uuid,
512 dzchunkindex: chunk.index,
513 dztotalfilesize: chunk.file.size,
514 dzchunksize: this.options.chunkSize,
515 dztotalchunkcount: chunk.file.upload.totalChunkCount,
516 dzchunkbyteoffset: chunk.index * this.options.chunkSize
517 };
518 }
519 },
520
521
522 /**
523 * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File)
524 * and a `done` function as parameters.
525 *
526 * If the done function is invoked without arguments, the file is "accepted" and will
527 * be processed. If you pass an error message, the file is rejected, and the error
528 * message will be displayed.
529 * This function will not be called if the file is too big or doesn't match the mime types.
530 */
531 accept: function accept(file, done) {
532 return done();
533 },
534
535
536 /**
537 * The callback that will be invoked when all chunks have been uploaded for a file.
538 * It gets the file for which the chunks have been uploaded as the first parameter,
539 * and the `done` function as second. `done()` needs to be invoked when everything
540 * needed to finish the upload process is done.
541 */
542 chunksUploaded: function chunksUploaded(file, done) {
543 done();
544 },
545
546 /**
547 * Gets called when the browser is not supported.
548 * The default implementation shows the fallback input field and adds
549 * a text.
550 */
551 fallback: function fallback() {
552 // This code should pass in IE7... :(
553 var messageElement = void 0;
554 this.element.className = this.element.className + " dz-browser-not-supported";
555
556 for (var _iterator2 = this.element.getElementsByTagName("div"), _isArray2 = true, _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
557 var _ref2;
558
559 if (_isArray2) {
560 if (_i2 >= _iterator2.length) break;
561 _ref2 = _iterator2[_i2++];
562 } else {
563 _i2 = _iterator2.next();
564 if (_i2.done) break;
565 _ref2 = _i2.value;
566 }
567
568 var child = _ref2;
569
570 if (/(^| )dz-message($| )/.test(child.className)) {
571 messageElement = child;
572 child.className = "dz-message"; // Removes the 'dz-default' class
573 break;
574 }
575 }
576 if (!messageElement) {
577 messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>");
578 this.element.appendChild(messageElement);
579 }
580
581 var span = messageElement.getElementsByTagName("span")[0];
582 if (span) {
583 if (span.textContent != null) {
584 span.textContent = this.options.dictFallbackMessage;
585 } else if (span.innerText != null) {
586 span.innerText = this.options.dictFallbackMessage;
587 }
588 }
589
590 return this.element.appendChild(this.getFallbackForm());
591 },
592
593
594 /**
595 * Gets called to calculate the thumbnail dimensions.
596 *
597 * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object containing:
598 *
599 * - `srcWidth` & `srcHeight` (required)
600 * - `trgWidth` & `trgHeight` (required)
601 * - `srcX` & `srcY` (optional, default `0`)
602 * - `trgX` & `trgY` (optional, default `0`)
603 *
604 * Those values are going to be used by `ctx.drawImage()`.
605 */
606 resize: function resize(file, width, height, resizeMethod) {
607 var info = {
608 srcX: 0,
609 srcY: 0,
610 srcWidth: file.width,
611 srcHeight: file.height
612 };
613
614 var srcRatio = file.width / file.height;
615
616 // Automatically calculate dimensions if not specified
617 if (width == null && height == null) {
618 width = info.srcWidth;
619 height = info.srcHeight;
620 } else if (width == null) {
621 width = height * srcRatio;
622 } else if (height == null) {
623 height = width / srcRatio;
624 }
625
626 // Make sure images aren't upscaled
627 width = Math.min(width, info.srcWidth);
628 height = Math.min(height, info.srcHeight);
629
630 var trgRatio = width / height;
631
632 if (info.srcWidth > width || info.srcHeight > height) {
633 // Image is bigger and needs rescaling
634 if (resizeMethod === 'crop') {
635 if (srcRatio > trgRatio) {
636 info.srcHeight = file.height;
637 info.srcWidth = info.srcHeight * trgRatio;
638 } else {
639 info.srcWidth = file.width;
640 info.srcHeight = info.srcWidth / trgRatio;
641 }
642 } else if (resizeMethod === 'contain') {
643 // Method 'contain'
644 if (srcRatio > trgRatio) {
645 height = width / srcRatio;
646 } else {
647 width = height * srcRatio;
648 }
649 } else {
650 throw new Error("Unknown resizeMethod '" + resizeMethod + "'");
651 }
652 }
653
654 info.srcX = (file.width - info.srcWidth) / 2;
655 info.srcY = (file.height - info.srcHeight) / 2;
656
657 info.trgWidth = width;
658 info.trgHeight = height;
659
660 return info;
661 },
662
663
664 /**
665 * Can be used to transform the file (for example, resize an image if necessary).
666 *
667 * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes
668 * images according to those dimensions.
669 *
670 * Gets the `file` as the first parameter, and a `done()` function as the second, that needs
671 * to be invoked with the file when the transformation is done.
672 */
673 transformFile: function transformFile(file, done) {
674 if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) {
675 return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done);
676 } else {
677 return done(file);
678 }
679 },
680
681
682 /**
683 * A string that contains the template used for each dropped
684 * file. Change it to fulfill your needs but make sure to properly
685 * provide all elements.
686 *
687 * If you want to use an actual HTML element instead of providing a String
688 * as a config option, you could create a div with the id `tpl`,
689 * put the template inside it and provide the element like this:
690 *
691 * document
692 * .querySelector('#tpl')
693 * .innerHTML
694 *
695 */
696 previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-image\"><img data-dz-thumbnail /></div>\n <div class=\"dz-details\">\n <div class=\"dz-size\"><span data-dz-size></span></div>\n <div class=\"dz-filename\"><span data-dz-name></span></div>\n </div>\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n <div class=\"dz-success-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n <title>Check</title>\n <defs></defs>\n <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n <path d=\"M23.5,31.8431458 L17.5852419,25.9283877 C16.0248253,24.3679711 13.4910294,24.366835 11.9289322,25.9289322 C10.3700136,27.4878508 10.3665912,30.0234455 11.9283877,31.5852419 L20.4147581,40.0716123 C20.5133999,40.1702541 20.6159315,40.2626649 20.7218615,40.3488435 C22.2835669,41.8725651 24.794234,41.8626202 26.3461564,40.3106978 L43.3106978,23.3461564 C44.8771021,21.7797521 44.8758057,19.2483887 43.3137085,17.6862915 C41.7547899,16.1273729 39.2176035,16.1255422 37.6538436,17.6893022 L23.5,31.8431458 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\" id=\"Oval-2\" stroke-opacity=\"0.198794158\" stroke=\"#747474\" fill-opacity=\"0.816519475\" fill=\"#FFFFFF\" sketch:type=\"MSShapeGroup\"></path>\n </g>\n </svg>\n </div>\n <div class=\"dz-error-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n <title>Error</title>\n <defs></defs>\n <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n <g id=\"Check-+-Oval-2\" sketch:type=\"MSLayerGroup\" stroke=\"#747474\" stroke-opacity=\"0.198794158\" fill=\"#FFFFFF\" fill-opacity=\"0.816519475\">\n <path d=\"M32.6568542,29 L38.3106978,23.3461564 C39.8771021,21.7797521 39.8758057,19.2483887 38.3137085,17.6862915 C36.7547899,16.1273729 34.2176035,16.1255422 32.6538436,17.6893022 L27,23.3431458 L21.3461564,17.6893022 C19.7823965,16.1255422 17.2452101,16.1273729 15.6862915,17.6862915 C14.1241943,19.2483887 14.1228979,21.7797521 15.6893022,23.3461564 L21.3431458,29 L15.6893022,34.6538436 C14.1228979,36.2202479 14.1241943,38.7516113 15.6862915,40.3137085 C17.2452101,41.8726271 19.7823965,41.8744578 21.3461564,40.3106978 L27,34.6568542 L32.6538436,40.3106978 C34.2176035,41.8744578 36.7547899,41.8726271 38.3137085,40.3137085 C39.8758057,38.7516113 39.8771021,36.2202479 38.3106978,34.6538436 L32.6568542,29 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\" id=\"Oval-2\" sketch:type=\"MSShapeGroup\"></path>\n </g>\n </g>\n </svg>\n </div>\n</div>",
697
698 // END OPTIONS
699 // (Required by the dropzone documentation parser)
700
701
702 /*
703 Those functions register themselves to the events on init and handle all
704 the user interface specific stuff. Overwriting them won't break the upload
705 but can break the way it's displayed.
706 You can overwrite them if you don't like the default behavior. If you just
707 want to add an additional event handler, register it on the dropzone object
708 and don't overwrite those options.
709 */
710
711 // Those are self explanatory and simply concern the DragnDrop.
712 drop: function drop(e) {
713 return this.element.classList.remove("dz-drag-hover");
714 },
715 dragstart: function dragstart(e) {},
716 dragend: function dragend(e) {
717 return this.element.classList.remove("dz-drag-hover");
718 },
719 dragenter: function dragenter(e) {
720 return this.element.classList.add("dz-drag-hover");
721 },
722 dragover: function dragover(e) {
723 return this.element.classList.add("dz-drag-hover");
724 },
725 dragleave: function dragleave(e) {
726 return this.element.classList.remove("dz-drag-hover");
727 },
728 paste: function paste(e) {},
729
730
731 // Called whenever there are no files left in the dropzone anymore, and the
732 // dropzone should be displayed as if in the initial state.
733 reset: function reset() {
734 return this.element.classList.remove("dz-started");
735 },
736
737
738 // Called when a file is added to the queue
739 // Receives `file`
740 addedfile: function addedfile(file) {
741 var _this2 = this;
742
743 if (this.element === this.previewsContainer) {
744 this.element.classList.add("dz-started");
745 }
746
747 if (this.previewsContainer) {
748 file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
749 file.previewTemplate = file.previewElement; // Backwards compatibility
750
751 this.previewsContainer.appendChild(file.previewElement);
752 for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]"), _isArray3 = true, _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
753 var _ref3;
754
755 if (_isArray3) {
756 if (_i3 >= _iterator3.length) break;
757 _ref3 = _iterator3[_i3++];
758 } else {
759 _i3 = _iterator3.next();
760 if (_i3.done) break;
761 _ref3 = _i3.value;
762 }
763
764 var node = _ref3;
765
766 node.textContent = file.name;
767 }
768 for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]"), _isArray4 = true, _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
769 if (_isArray4) {
770 if (_i4 >= _iterator4.length) break;
771 node = _iterator4[_i4++];
772 } else {
773 _i4 = _iterator4.next();
774 if (_i4.done) break;
775 node = _i4.value;
776 }
777
778 node.innerHTML = this.filesize(file.size);
779 }
780
781 if (this.options.addRemoveLinks) {
782 file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>" + this.options.dictRemoveFile + "</a>");
783 file.previewElement.appendChild(file._removeLink);
784 }
785
786 var removeFileEvent = function removeFileEvent(e) {
787 e.preventDefault();
788 e.stopPropagation();
789 if (file.status === Dropzone.UPLOADING) {
790 return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () {
791 return _this2.removeFile(file);
792 });
793 } else {
794 if (_this2.options.dictRemoveFileConfirmation) {
795 return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () {
796 return _this2.removeFile(file);
797 });
798 } else {
799 return _this2.removeFile(file);
800 }
801 }
802 };
803
804 for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]"), _isArray5 = true, _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
805 var _ref4;
806
807 if (_isArray5) {
808 if (_i5 >= _iterator5.length) break;
809 _ref4 = _iterator5[_i5++];
810 } else {
811 _i5 = _iterator5.next();
812 if (_i5.done) break;
813 _ref4 = _i5.value;
814 }
815
816 var removeLink = _ref4;
817
818 removeLink.addEventListener("click", removeFileEvent);
819 }
820 }
821 },
822
823
824 // Called whenever a file is removed.
825 removedfile: function removedfile(file) {
826 if (file.previewElement != null && file.previewElement.parentNode != null) {
827 file.previewElement.parentNode.removeChild(file.previewElement);
828 }
829 return this._updateMaxFilesReachedClass();
830 },
831
832
833 // Called when a thumbnail has been generated
834 // Receives `file` and `dataUrl`
835 thumbnail: function thumbnail(file, dataUrl) {
836 if (file.previewElement) {
837 file.previewElement.classList.remove("dz-file-preview");
838 for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]"), _isArray6 = true, _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
839 var _ref5;
840
841 if (_isArray6) {
842 if (_i6 >= _iterator6.length) break;
843 _ref5 = _iterator6[_i6++];
844 } else {
845 _i6 = _iterator6.next();
846 if (_i6.done) break;
847 _ref5 = _i6.value;
848 }
849
850 var thumbnailElement = _ref5;
851
852 thumbnailElement.alt = file.name;
853 thumbnailElement.src = dataUrl;
854 }
855
856 return setTimeout(function () {
857 return file.previewElement.classList.add("dz-image-preview");
858 }, 1);
859 }
860 },
861
862
863 // Called whenever an error occurs
864 // Receives `file` and `message`
865 error: function error(file, message) {
866 if (file.previewElement) {
867 file.previewElement.classList.add("dz-error");
868 if (typeof message !== "String" && message.error) {
869 message = message.error;
870 }
871 for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = true, _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
872 var _ref6;
873
874 if (_isArray7) {
875 if (_i7 >= _iterator7.length) break;
876 _ref6 = _iterator7[_i7++];
877 } else {
878 _i7 = _iterator7.next();
879 if (_i7.done) break;
880 _ref6 = _i7.value;
881 }
882
883 var node = _ref6;
884
885 node.textContent = message;
886 }
887 }
888 },
889 errormultiple: function errormultiple() {},
890
891
892 // Called when a file gets processed. Since there is a cue, not all added
893 // files are processed immediately.
894 // Receives `file`
895 processing: function processing(file) {
896 if (file.previewElement) {
897 file.previewElement.classList.add("dz-processing");
898 if (file._removeLink) {
899 return file._removeLink.innerHTML = this.options.dictCancelUpload;
900 }
901 }
902 },
903 processingmultiple: function processingmultiple() {},
904
905
906 // Called whenever the upload progress gets updated.
907 // Receives `file`, `progress` (percentage 0-100) and `bytesSent`.
908 // To get the total number of bytes of the file, use `file.size`
909 uploadprogress: function uploadprogress(file, progress, bytesSent) {
910 if (file.previewElement) {
911 for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"), _isArray8 = true, _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
912 var _ref7;
913
914 if (_isArray8) {
915 if (_i8 >= _iterator8.length) break;
916 _ref7 = _iterator8[_i8++];
917 } else {
918 _i8 = _iterator8.next();
919 if (_i8.done) break;
920 _ref7 = _i8.value;
921 }
922
923 var node = _ref7;
924
925 node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = progress + "%";
926 }
927 }
928 },
929
930
931 // Called whenever the total upload progress gets updated.
932 // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent
933 totaluploadprogress: function totaluploadprogress() {},
934
935
936 // Called just before the file is sent. Gets the `xhr` object as second
937 // parameter, so you can modify it (for example to add a CSRF token) and a
938 // `formData` object to add additional information.
939 sending: function sending() {},
940 sendingmultiple: function sendingmultiple() {},
941
942
943 // When the complete upload is finished and successful
944 // Receives `file`
945 success: function success(file) {
946 if (file.previewElement) {
947 return file.previewElement.classList.add("dz-success");
948 }
949 },
950 successmultiple: function successmultiple() {},
951
952
953 // When the upload is canceled.
954 canceled: function canceled(file) {
955 return this.emit("error", file, this.options.dictUploadCanceled);
956 },
957 canceledmultiple: function canceledmultiple() {},
958
959
960 // When the upload is finished, either with success or an error.
961 // Receives `file`
962 complete: function complete(file) {
963 if (file._removeLink) {
964 file._removeLink.innerHTML = this.options.dictRemoveFile;
965 }
966 if (file.previewElement) {
967 return file.previewElement.classList.add("dz-complete");
968 }
969 },
970 completemultiple: function completemultiple() {},
971 maxfilesexceeded: function maxfilesexceeded() {},
972 maxfilesreached: function maxfilesreached() {},
973 queuecomplete: function queuecomplete() {},
974 addedfiles: function addedfiles() {}
975 };
976
977 this.prototype._thumbnailQueue = [];
978 this.prototype._processingThumbnail = false;
979 }
980
981 // global utility
982
983 }, {
984 key: "extend",
985 value: function extend(target) {
986 for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
987 objects[_key2 - 1] = arguments[_key2];
988 }
989
990 for (var _iterator9 = objects, _isArray9 = true, _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
991 var _ref8;
992
993 if (_isArray9) {
994 if (_i9 >= _iterator9.length) break;
995 _ref8 = _iterator9[_i9++];
996 } else {
997 _i9 = _iterator9.next();
998 if (_i9.done) break;
999 _ref8 = _i9.value;
1000 }
1001
1002 var object = _ref8;
1003
1004 for (var key in object) {
1005 var val = object[key];
1006 target[key] = val;
1007 }
1008 }
1009 return target;
1010 }
1011 }]);
1012
1013 function Dropzone(el, options) {
1014 _classCallCheck(this, Dropzone);
1015
1016 var _this = _possibleConstructorReturn(this, (Dropzone.__proto__ || Object.getPrototypeOf(Dropzone)).call(this));
1017
1018 var fallback = void 0,
1019 left = void 0;
1020 _this.element = el;
1021 // For backwards compatibility since the version was in the prototype previously
1022 _this.version = Dropzone.version;
1023
1024 _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, "");
1025
1026 _this.clickableElements = [];
1027 _this.listeners = [];
1028 _this.files = []; // All files
1029
1030 if (typeof _this.element === "string") {
1031 _this.element = document.querySelector(_this.element);
1032 }
1033
1034 // Not checking if instance of HTMLElement or Element since IE9 is extremely weird.
1035 if (!_this.element || _this.element.nodeType == null) {
1036 throw new Error("Invalid dropzone element.");
1037 }
1038
1039 if (_this.element.dropzone) {
1040 throw new Error("Dropzone already attached.");
1041 }
1042
1043 // Now add this dropzone to the instances.
1044 Dropzone.instances.push(_this);
1045
1046 // Put the dropzone inside the element itself.
1047 _this.element.dropzone = _this;
1048
1049 var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {};
1050
1051 _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {});
1052
1053 // If the browser failed, just call the fallback and leave
1054 if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) {
1055 var _ret;
1056
1057 return _ret = _this.options.fallback.call(_this), _possibleConstructorReturn(_this, _ret);
1058 }
1059
1060 // @options.url = @element.getAttribute "action" unless @options.url?
1061 if (_this.options.url == null) {
1062 _this.options.url = _this.element.getAttribute("action");
1063 }
1064
1065 if (!_this.options.url) {
1066 throw new Error("No URL provided.");
1067 }
1068
1069 if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) {
1070 throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");
1071 }
1072
1073 if (_this.options.uploadMultiple && _this.options.chunking) {
1074 throw new Error('You cannot set both: uploadMultiple and chunking.');
1075 }
1076
1077 // Backwards compatibility
1078 if (_this.options.acceptedMimeTypes) {
1079 _this.options.acceptedFiles = _this.options.acceptedMimeTypes;
1080 delete _this.options.acceptedMimeTypes;
1081 }
1082
1083 // Backwards compatibility
1084 if (_this.options.renameFilename != null) {
1085 _this.options.renameFile = function (file) {
1086 return _this.options.renameFilename.call(_this, file.name, file);
1087 };
1088 }
1089
1090 _this.options.method = _this.options.method.toUpperCase();
1091
1092 if ((fallback = _this.getExistingFallback()) && fallback.parentNode) {
1093 // Remove the fallback
1094 fallback.parentNode.removeChild(fallback);
1095 }
1096
1097 // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false
1098 if (_this.options.previewsContainer !== false) {
1099 if (_this.options.previewsContainer) {
1100 _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer");
1101 } else {
1102 _this.previewsContainer = _this.element;
1103 }
1104 }
1105
1106 if (_this.options.clickable) {
1107 if (_this.options.clickable === true) {
1108 _this.clickableElements = [_this.element];
1109 } else {
1110 _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable");
1111 }
1112 }
1113
1114 _this.init();
1115 return _this;
1116 }
1117
1118 // Returns all files that have been accepted
1119
1120
1121 _createClass(Dropzone, [{
1122 key: "getAcceptedFiles",
1123 value: function getAcceptedFiles() {
1124 return this.files.filter(function (file) {
1125 return file.accepted;
1126 }).map(function (file) {
1127 return file;
1128 });
1129 }
1130
1131 // Returns all files that have been rejected
1132 // Not sure when that's going to be useful, but added for completeness.
1133
1134 }, {
1135 key: "getRejectedFiles",
1136 value: function getRejectedFiles() {
1137 return this.files.filter(function (file) {
1138 return !file.accepted;
1139 }).map(function (file) {
1140 return file;
1141 });
1142 }
1143 }, {
1144 key: "getFilesWithStatus",
1145 value: function getFilesWithStatus(status) {
1146 return this.files.filter(function (file) {
1147 return file.status === status;
1148 }).map(function (file) {
1149 return file;
1150 });
1151 }
1152
1153 // Returns all files that are in the queue
1154
1155 }, {
1156 key: "getQueuedFiles",
1157 value: function getQueuedFiles() {
1158 return this.getFilesWithStatus(Dropzone.QUEUED);
1159 }
1160 }, {
1161 key: "getUploadingFiles",
1162 value: function getUploadingFiles() {
1163 return this.getFilesWithStatus(Dropzone.UPLOADING);
1164 }
1165 }, {
1166 key: "getAddedFiles",
1167 value: function getAddedFiles() {
1168 return this.getFilesWithStatus(Dropzone.ADDED);
1169 }
1170
1171 // Files that are either queued or uploading
1172
1173 }, {
1174 key: "getActiveFiles",
1175 value: function getActiveFiles() {
1176 return this.files.filter(function (file) {
1177 return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED;
1178 }).map(function (file) {
1179 return file;
1180 });
1181 }
1182
1183 // The function that gets called when Dropzone is initialized. You
1184 // can (and should) setup event listeners inside this function.
1185
1186 }, {
1187 key: "init",
1188 value: function init() {
1189 var _this3 = this;
1190
1191 // In case it isn't set already
1192 if (this.element.tagName === "form") {
1193 this.element.setAttribute("enctype", "multipart/form-data");
1194 }
1195
1196 if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) {
1197 this.element.appendChild(Dropzone.createElement("<div class=\"dz-default dz-message\"><span>" + this.options.dictDefaultMessage + "</span></div>"));
1198 }
1199
1200 if (this.clickableElements.length) {
1201 var setupHiddenFileInput = function setupHiddenFileInput() {
1202 if (_this3.hiddenFileInput) {
1203 _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput);
1204 }
1205 _this3.hiddenFileInput = document.createElement("input");
1206 _this3.hiddenFileInput.setAttribute("type", "file");
1207 if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) {
1208 _this3.hiddenFileInput.setAttribute("multiple", "multiple");
1209 }
1210 _this3.hiddenFileInput.className = "dz-hidden-input";
1211
1212 if (_this3.options.acceptedFiles !== null) {
1213 _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles);
1214 }
1215 if (_this3.options.capture !== null) {
1216 _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture);
1217 }
1218
1219 // Not setting `display="none"` because some browsers don't accept clicks
1220 // on elements that aren't displayed.
1221 _this3.hiddenFileInput.style.visibility = "hidden";
1222 _this3.hiddenFileInput.style.position = "absolute";
1223 _this3.hiddenFileInput.style.top = "0";
1224 _this3.hiddenFileInput.style.left = "0";
1225 _this3.hiddenFileInput.style.height = "0";
1226 _this3.hiddenFileInput.style.width = "0";
1227 Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput);
1228 return _this3.hiddenFileInput.addEventListener("change", function () {
1229 var files = _this3.hiddenFileInput.files;
1230
1231 if (files.length) {
1232 for (var _iterator10 = files, _isArray10 = true, _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
1233 var _ref9;
1234
1235 if (_isArray10) {
1236 if (_i10 >= _iterator10.length) break;
1237 _ref9 = _iterator10[_i10++];
1238 } else {
1239 _i10 = _iterator10.next();
1240 if (_i10.done) break;
1241 _ref9 = _i10.value;
1242 }
1243
1244 var file = _ref9;
1245
1246 _this3.addFile(file);
1247 }
1248 }
1249 _this3.emit("addedfiles", files);
1250 return setupHiddenFileInput();
1251 });
1252 };
1253 setupHiddenFileInput();
1254 }
1255
1256 this.URL = window.URL !== null ? window.URL : window.webkitURL;
1257
1258 // Setup all event listeners on the Dropzone object itself.
1259 // They're not in @setupEventListeners() because they shouldn't be removed
1260 // again when the dropzone gets disabled.
1261 for (var _iterator11 = this.events, _isArray11 = true, _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
1262 var _ref10;
1263
1264 if (_isArray11) {
1265 if (_i11 >= _iterator11.length) break;
1266 _ref10 = _iterator11[_i11++];
1267 } else {
1268 _i11 = _iterator11.next();
1269 if (_i11.done) break;
1270 _ref10 = _i11.value;
1271 }
1272
1273 var eventName = _ref10;
1274
1275 this.on(eventName, this.options[eventName]);
1276 }
1277
1278 this.on("uploadprogress", function () {
1279 return _this3.updateTotalUploadProgress();
1280 });
1281
1282 this.on("removedfile", function () {
1283 return _this3.updateTotalUploadProgress();
1284 });
1285
1286 this.on("canceled", function (file) {
1287 return _this3.emit("complete", file);
1288 });
1289
1290 // Emit a `queuecomplete` event if all files finished uploading.
1291 this.on("complete", function (file) {
1292 if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) {
1293 // This needs to be deferred so that `queuecomplete` really triggers after `complete`
1294 return setTimeout(function () {
1295 return _this3.emit("queuecomplete");
1296 }, 0);
1297 }
1298 });
1299
1300 var noPropagation = function noPropagation(e) {
1301 e.stopPropagation();
1302 if (e.preventDefault) {
1303 return e.preventDefault();
1304 } else {
1305 return e.returnValue = false;
1306 }
1307 };
1308
1309 // Create the listeners
1310 this.listeners = [{
1311 element: this.element,
1312 events: {
1313 "dragstart": function dragstart(e) {
1314 return _this3.emit("dragstart", e);
1315 },
1316 "dragenter": function dragenter(e) {
1317 noPropagation(e);
1318 return _this3.emit("dragenter", e);
1319 },
1320 "dragover": function dragover(e) {
1321 // Makes it possible to drag files from chrome's download bar
1322 // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar
1323 // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception)
1324 var efct = void 0;
1325 try {
1326 efct = e.dataTransfer.effectAllowed;
1327 } catch (error) {}
1328 e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';
1329
1330 noPropagation(e);
1331 return _this3.emit("dragover", e);
1332 },
1333 "dragleave": function dragleave(e) {
1334 return _this3.emit("dragleave", e);
1335 },
1336 "drop": function drop(e) {
1337 noPropagation(e);
1338 return _this3.drop(e);
1339 },
1340 "dragend": function dragend(e) {
1341 return _this3.emit("dragend", e);
1342 }
1343
1344 // This is disabled right now, because the browsers don't implement it properly.
1345 // "paste": (e) =>
1346 // noPropagation e
1347 // @paste e
1348 } }];
1349
1350 this.clickableElements.forEach(function (clickableElement) {
1351 return _this3.listeners.push({
1352 element: clickableElement,
1353 events: {
1354 "click": function click(evt) {
1355 // Only the actual dropzone or the message element should trigger file selection
1356 if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) {
1357 _this3.hiddenFileInput.click(); // Forward the click
1358 }
1359 return true;
1360 }
1361 }
1362 });
1363 });
1364
1365 this.enable();
1366
1367 return this.options.init.call(this);
1368 }
1369
1370 // Not fully tested yet
1371
1372 }, {
1373 key: "destroy",
1374 value: function destroy() {
1375 this.disable();
1376 this.removeAllFiles(true);
1377 if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) {
1378 this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);
1379 this.hiddenFileInput = null;
1380 }
1381 delete this.element.dropzone;
1382 return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1);
1383 }
1384 }, {
1385 key: "updateTotalUploadProgress",
1386 value: function updateTotalUploadProgress() {
1387 var totalUploadProgress = void 0;
1388 var totalBytesSent = 0;
1389 var totalBytes = 0;
1390
1391 var activeFiles = this.getActiveFiles();
1392
1393 if (activeFiles.length) {
1394 for (var _iterator12 = this.getActiveFiles(), _isArray12 = true, _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) {
1395 var _ref11;
1396
1397 if (_isArray12) {
1398 if (_i12 >= _iterator12.length) break;
1399 _ref11 = _iterator12[_i12++];
1400 } else {
1401 _i12 = _iterator12.next();
1402 if (_i12.done) break;
1403 _ref11 = _i12.value;
1404 }
1405
1406 var file = _ref11;
1407
1408 totalBytesSent += file.upload.bytesSent;
1409 totalBytes += file.upload.total;
1410 }
1411 totalUploadProgress = 100 * totalBytesSent / totalBytes;
1412 } else {
1413 totalUploadProgress = 100;
1414 }
1415
1416 return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent);
1417 }
1418
1419 // @options.paramName can be a function taking one parameter rather than a string.
1420 // A parameter name for a file is obtained simply by calling this with an index number.
1421
1422 }, {
1423 key: "_getParamName",
1424 value: function _getParamName(n) {
1425 if (typeof this.options.paramName === "function") {
1426 return this.options.paramName(n);
1427 } else {
1428 return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : "");
1429 }
1430 }
1431
1432 // If @options.renameFile is a function,
1433 // the function will be used to rename the file.name before appending it to the formData
1434
1435 }, {
1436 key: "_renameFile",
1437 value: function _renameFile(file) {
1438 if (typeof this.options.renameFile !== "function") {
1439 return file.name;
1440 }
1441 return this.options.renameFile(file);
1442 }
1443
1444 // Returns a form that can be used as fallback if the browser does not support DragnDrop
1445 //
1446 // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided.
1447 // This code has to pass in IE7 :(
1448
1449 }, {
1450 key: "getFallbackForm",
1451 value: function getFallbackForm() {
1452 var existingFallback = void 0,
1453 form = void 0;
1454 if (existingFallback = this.getExistingFallback()) {
1455 return existingFallback;
1456 }
1457
1458 var fieldsString = "<div class=\"dz-fallback\">";
1459 if (this.options.dictFallbackText) {
1460 fieldsString += "<p>" + this.options.dictFallbackText + "</p>";
1461 }
1462 fieldsString += "<input type=\"file\" name=\"" + this._getParamName(0) + "\" " + (this.options.uploadMultiple ? 'multiple="multiple"' : undefined) + " /><input type=\"submit\" value=\"Upload!\"></div>";
1463
1464 var fields = Dropzone.createElement(fieldsString);
1465 if (this.element.tagName !== "FORM") {
1466 form = Dropzone.createElement("<form action=\"" + this.options.url + "\" enctype=\"multipart/form-data\" method=\"" + this.options.method + "\"></form>");
1467 form.appendChild(fields);
1468 } else {
1469 // Make sure that the enctype and method attributes are set properly
1470 this.element.setAttribute("enctype", "multipart/form-data");
1471 this.element.setAttribute("method", this.options.method);
1472 }
1473 return form != null ? form : fields;
1474 }
1475
1476 // Returns the fallback elements if they exist already
1477 //
1478 // This code has to pass in IE7 :(
1479
1480 }, {
1481 key: "getExistingFallback",
1482 value: function getExistingFallback() {
1483 var getFallback = function getFallback(elements) {
1484 for (var _iterator13 = elements, _isArray13 = true, _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) {
1485 var _ref12;
1486
1487 if (_isArray13) {
1488 if (_i13 >= _iterator13.length) break;
1489 _ref12 = _iterator13[_i13++];
1490 } else {
1491 _i13 = _iterator13.next();
1492 if (_i13.done) break;
1493 _ref12 = _i13.value;
1494 }
1495
1496 var el = _ref12;
1497
1498 if (/(^| )fallback($| )/.test(el.className)) {
1499 return el;
1500 }
1501 }
1502 };
1503
1504 var _arr = ["div", "form"];
1505 for (var _i14 = 0; _i14 < _arr.length; _i14++) {
1506 var tagName = _arr[_i14];
1507 var fallback;
1508 if (fallback = getFallback(this.element.getElementsByTagName(tagName))) {
1509 return fallback;
1510 }
1511 }
1512 }
1513
1514 // Activates all listeners stored in @listeners
1515
1516 }, {
1517 key: "setupEventListeners",
1518 value: function setupEventListeners() {
1519 return this.listeners.map(function (elementListeners) {
1520 return function () {
1521 var result = [];
1522 for (var event in elementListeners.events) {
1523 var listener = elementListeners.events[event];
1524 result.push(elementListeners.element.addEventListener(event, listener, false));
1525 }
1526 return result;
1527 }();
1528 });
1529 }
1530
1531 // Deactivates all listeners stored in @listeners
1532
1533 }, {
1534 key: "removeEventListeners",
1535 value: function removeEventListeners() {
1536 return this.listeners.map(function (elementListeners) {
1537 return function () {
1538 var result = [];
1539 for (var event in elementListeners.events) {
1540 var listener = elementListeners.events[event];
1541 result.push(elementListeners.element.removeEventListener(event, listener, false));
1542 }
1543 return result;
1544 }();
1545 });
1546 }
1547
1548 // Removes all event listeners and cancels all files in the queue or being processed.
1549
1550 }, {
1551 key: "disable",
1552 value: function disable() {
1553 var _this4 = this;
1554
1555 this.clickableElements.forEach(function (element) {
1556 return element.classList.remove("dz-clickable");
1557 });
1558 this.removeEventListeners();
1559 this.disabled = true;
1560
1561 return this.files.map(function (file) {
1562 return _this4.cancelUpload(file);
1563 });
1564 }
1565 }, {
1566 key: "enable",
1567 value: function enable() {
1568 delete this.disabled;
1569 this.clickableElements.forEach(function (element) {
1570 return element.classList.add("dz-clickable");
1571 });
1572 return this.setupEventListeners();
1573 }
1574
1575 // Returns a nicely formatted filesize
1576
1577 }, {
1578 key: "filesize",
1579 value: function filesize(size) {
1580 var selectedSize = 0;
1581 var selectedUnit = "b";
1582
1583 if (size > 0) {
1584 var units = ['tb', 'gb', 'mb', 'kb', 'b'];
1585
1586 for (var i = 0; i < units.length; i++) {
1587 var unit = units[i];
1588 var cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10;
1589
1590 if (size >= cutoff) {
1591 selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i);
1592 selectedUnit = unit;
1593 break;
1594 }
1595 }
1596
1597 selectedSize = Math.round(10 * selectedSize) / 10; // Cutting of digits
1598 }
1599
1600 return "<strong>" + selectedSize + "</strong> " + this.options.dictFileSizeUnits[selectedUnit];
1601 }
1602
1603 // Adds or removes the `dz-max-files-reached` class from the form.
1604
1605 }, {
1606 key: "_updateMaxFilesReachedClass",
1607 value: function _updateMaxFilesReachedClass() {
1608 if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) {
1609 if (this.getAcceptedFiles().length === this.options.maxFiles) {
1610 this.emit('maxfilesreached', this.files);
1611 }
1612 return this.element.classList.add("dz-max-files-reached");
1613 } else {
1614 return this.element.classList.remove("dz-max-files-reached");
1615 }
1616 }
1617 }, {
1618 key: "drop",
1619 value: function drop(e) {
1620 if (!e.dataTransfer) {
1621 return;
1622 }
1623 this.emit("drop", e);
1624
1625 // Convert the FileList to an Array
1626 // This is necessary for IE11
1627 var files = [];
1628 for (var i = 0; i < e.dataTransfer.files.length; i++) {
1629 files[i] = e.dataTransfer.files[i];
1630 }
1631
1632 this.emit("addedfiles", files);
1633
1634 // Even if it's a folder, files.length will contain the folders.
1635 if (files.length) {
1636 var items = e.dataTransfer.items;
1637
1638 if (items && items.length && items[0].webkitGetAsEntry != null) {
1639 // The browser supports dropping of folders, so handle items instead of files
1640 this._addFilesFromItems(items);
1641 } else {
1642 this.handleFiles(files);
1643 }
1644 }
1645 }
1646 }, {
1647 key: "paste",
1648 value: function paste(e) {
1649 if (__guard__(e != null ? e.clipboardData : undefined, function (x) {
1650 return x.items;
1651 }) == null) {
1652 return;
1653 }
1654
1655 this.emit("paste", e);
1656 var items = e.clipboardData.items;
1657
1658
1659 if (items.length) {
1660 return this._addFilesFromItems(items);
1661 }
1662 }
1663 }, {
1664 key: "handleFiles",
1665 value: function handleFiles(files) {
1666 for (var _iterator14 = files, _isArray14 = true, _i15 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) {
1667 var _ref13;
1668
1669 if (_isArray14) {
1670 if (_i15 >= _iterator14.length) break;
1671 _ref13 = _iterator14[_i15++];
1672 } else {
1673 _i15 = _iterator14.next();
1674 if (_i15.done) break;
1675 _ref13 = _i15.value;
1676 }
1677
1678 var file = _ref13;
1679
1680 this.addFile(file);
1681 }
1682 }
1683
1684 // When a folder is dropped (or files are pasted), items must be handled
1685 // instead of files.
1686
1687 }, {
1688 key: "_addFilesFromItems",
1689 value: function _addFilesFromItems(items) {
1690 var _this5 = this;
1691
1692 return function () {
1693 var result = [];
1694 for (var _iterator15 = items, _isArray15 = true, _i16 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) {
1695 var _ref14;
1696
1697 if (_isArray15) {
1698 if (_i16 >= _iterator15.length) break;
1699 _ref14 = _iterator15[_i16++];
1700 } else {
1701 _i16 = _iterator15.next();
1702 if (_i16.done) break;
1703 _ref14 = _i16.value;
1704 }
1705
1706 var item = _ref14;
1707
1708 var entry;
1709 if (item.webkitGetAsEntry != null && (entry = item.webkitGetAsEntry())) {
1710 if (entry.isFile) {
1711 result.push(_this5.addFile(item.getAsFile()));
1712 } else if (entry.isDirectory) {
1713 // Append all files from that directory to files
1714 result.push(_this5._addFilesFromDirectory(entry, entry.name));
1715 } else {
1716 result.push(undefined);
1717 }
1718 } else if (item.getAsFile != null) {
1719 if (item.kind == null || item.kind === "file") {
1720 result.push(_this5.addFile(item.getAsFile()));
1721 } else {
1722 result.push(undefined);
1723 }
1724 } else {
1725 result.push(undefined);
1726 }
1727 }
1728 return result;
1729 }();
1730 }
1731
1732 // Goes through the directory, and adds each file it finds recursively
1733
1734 }, {
1735 key: "_addFilesFromDirectory",
1736 value: function _addFilesFromDirectory(directory, path) {
1737 var _this6 = this;
1738
1739 var dirReader = directory.createReader();
1740
1741 var errorHandler = function errorHandler(error) {
1742 return __guardMethod__(console, 'log', function (o) {
1743 return o.log(error);
1744 });
1745 };
1746
1747 var readEntries = function readEntries() {
1748 return dirReader.readEntries(function (entries) {
1749 if (entries.length > 0) {
1750 for (var _iterator16 = entries, _isArray16 = true, _i17 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) {
1751 var _ref15;
1752
1753 if (_isArray16) {
1754 if (_i17 >= _iterator16.length) break;
1755 _ref15 = _iterator16[_i17++];
1756 } else {
1757 _i17 = _iterator16.next();
1758 if (_i17.done) break;
1759 _ref15 = _i17.value;
1760 }
1761
1762 var entry = _ref15;
1763
1764 if (entry.isFile) {
1765 entry.file(function (file) {
1766 if (_this6.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') {
1767 return;
1768 }
1769 file.fullPath = path + "/" + file.name;
1770 return _this6.addFile(file);
1771 });
1772 } else if (entry.isDirectory) {
1773 _this6._addFilesFromDirectory(entry, path + "/" + entry.name);
1774 }
1775 }
1776
1777 // Recursively call readEntries() again, since browser only handle
1778 // the first 100 entries.
1779 // See: https://developer.mozilla.org/en-US/docs/Web/API/DirectoryReader#readEntries
1780 readEntries();
1781 }
1782 return null;
1783 }, errorHandler);
1784 };
1785
1786 return readEntries();
1787 }
1788
1789 // If `done()` is called without argument the file is accepted
1790 // If you call it with an error message, the file is rejected
1791 // (This allows for asynchronous validation)
1792 //
1793 // This function checks the filesize, and if the file.type passes the
1794 // `acceptedFiles` check.
1795
1796 }, {
1797 key: "accept",
1798 value: function accept(file, done) {
1799 if (this.options.maxFilesize && file.size > this.options.maxFilesize * 1024 * 1024) {
1800 return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize));
1801 } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) {
1802 return done(this.options.dictInvalidFileType);
1803 } else if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) {
1804 done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles));
1805 return this.emit("maxfilesexceeded", file);
1806 } else {
1807 return this.options.accept.call(this, file, done);
1808 }
1809 }
1810 }, {
1811 key: "addFile",
1812 value: function addFile(file) {
1813 var _this7 = this;
1814
1815 file.upload = {
1816 uuid: Dropzone.uuidv4(),
1817 progress: 0,
1818 // Setting the total upload size to file.size for the beginning
1819 // It's actual different than the size to be transmitted.
1820 total: file.size,
1821 bytesSent: 0,
1822 filename: this._renameFile(file),
1823 chunked: this.options.chunking && (this.options.forceChunking || file.size > this.options.chunkSize),
1824 totalChunkCount: Math.ceil(file.size / this.options.chunkSize)
1825 };
1826 this.files.push(file);
1827
1828 file.status = Dropzone.ADDED;
1829
1830 this.emit("addedfile", file);
1831
1832 this._enqueueThumbnail(file);
1833
1834 return this.accept(file, function (error) {
1835 if (error) {
1836 file.accepted = false;
1837 _this7._errorProcessing([file], error); // Will set the file.status
1838 } else {
1839 file.accepted = true;
1840 if (_this7.options.autoQueue) {
1841 _this7.enqueueFile(file);
1842 } // Will set .accepted = true
1843 }
1844 return _this7._updateMaxFilesReachedClass();
1845 });
1846 }
1847
1848 // Wrapper for enqueueFile
1849
1850 }, {
1851 key: "enqueueFiles",
1852 value: function enqueueFiles(files) {
1853 for (var _iterator17 = files, _isArray17 = true, _i18 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator]();;) {
1854 var _ref16;
1855
1856 if (_isArray17) {
1857 if (_i18 >= _iterator17.length) break;
1858 _ref16 = _iterator17[_i18++];
1859 } else {
1860 _i18 = _iterator17.next();
1861 if (_i18.done) break;
1862 _ref16 = _i18.value;
1863 }
1864
1865 var file = _ref16;
1866
1867 this.enqueueFile(file);
1868 }
1869 return null;
1870 }
1871 }, {
1872 key: "enqueueFile",
1873 value: function enqueueFile(file) {
1874 var _this8 = this;
1875
1876 if (file.status === Dropzone.ADDED && file.accepted === true) {
1877 file.status = Dropzone.QUEUED;
1878 if (this.options.autoProcessQueue) {
1879 return setTimeout(function () {
1880 return _this8.processQueue();
1881 }, 0); // Deferring the call
1882 }
1883 } else {
1884 throw new Error("This file can't be queued because it has already been processed or was rejected.");
1885 }
1886 }
1887 }, {
1888 key: "_enqueueThumbnail",
1889 value: function _enqueueThumbnail(file) {
1890 var _this9 = this;
1891
1892 if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) {
1893 this._thumbnailQueue.push(file);
1894 return setTimeout(function () {
1895 return _this9._processThumbnailQueue();
1896 }, 0); // Deferring the call
1897 }
1898 }
1899 }, {
1900 key: "_processThumbnailQueue",
1901 value: function _processThumbnailQueue() {
1902 var _this10 = this;
1903
1904 if (this._processingThumbnail || this._thumbnailQueue.length === 0) {
1905 return;
1906 }
1907
1908 this._processingThumbnail = true;
1909 var file = this._thumbnailQueue.shift();
1910 return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, function (dataUrl) {
1911 _this10.emit("thumbnail", file, dataUrl);
1912 _this10._processingThumbnail = false;
1913 return _this10._processThumbnailQueue();
1914 });
1915 }
1916
1917 // Can be called by the user to remove a file
1918
1919 }, {
1920 key: "removeFile",
1921 value: function removeFile(file) {
1922 if (file.status === Dropzone.UPLOADING) {
1923 this.cancelUpload(file);
1924 }
1925 this.files = without(this.files, file);
1926
1927 this.emit("removedfile", file);
1928 if (this.files.length === 0) {
1929 return this.emit("reset");
1930 }
1931 }
1932
1933 // Removes all files that aren't currently processed from the list
1934
1935 }, {
1936 key: "removeAllFiles",
1937 value: function removeAllFiles(cancelIfNecessary) {
1938 // Create a copy of files since removeFile() changes the @files array.
1939 if (cancelIfNecessary == null) {
1940 cancelIfNecessary = false;
1941 }
1942 for (var _iterator18 = this.files.slice(), _isArray18 = true, _i19 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator]();;) {
1943 var _ref17;
1944
1945 if (_isArray18) {
1946 if (_i19 >= _iterator18.length) break;
1947 _ref17 = _iterator18[_i19++];
1948 } else {
1949 _i19 = _iterator18.next();
1950 if (_i19.done) break;
1951 _ref17 = _i19.value;
1952 }
1953
1954 var file = _ref17;
1955
1956 if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) {
1957 this.removeFile(file);
1958 }
1959 }
1960 return null;
1961 }
1962
1963 // Resizes an image before it gets sent to the server. This function is the default behavior of
1964 // `options.transformFile` if `resizeWidth` or `resizeHeight` are set. The callback is invoked with
1965 // the resized blob.
1966
1967 }, {
1968 key: "resizeImage",
1969 value: function resizeImage(file, width, height, resizeMethod, callback) {
1970 var _this11 = this;
1971
1972 return this.createThumbnail(file, width, height, resizeMethod, true, function (dataUrl, canvas) {
1973 if (canvas == null) {
1974 // The image has not been resized
1975 return callback(file);
1976 } else {
1977 var resizeMimeType = _this11.options.resizeMimeType;
1978
1979 if (resizeMimeType == null) {
1980 resizeMimeType = file.type;
1981 }
1982 var resizedDataURL = canvas.toDataURL(resizeMimeType, _this11.options.resizeQuality);
1983 if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') {
1984 // Now add the original EXIF information
1985 resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL);
1986 }
1987 return callback(Dropzone.dataURItoBlob(resizedDataURL));
1988 }
1989 });
1990 }
1991 }, {
1992 key: "createThumbnail",
1993 value: function createThumbnail(file, width, height, resizeMethod, fixOrientation, callback) {
1994 var _this12 = this;
1995
1996 var fileReader = new FileReader();
1997
1998 fileReader.onload = function () {
1999
2000 file.dataURL = fileReader.result;
2001
2002 // Don't bother creating a thumbnail for SVG images since they're vector
2003 if (file.type === "image/svg+xml") {
2004 if (callback != null) {
2005 callback(fileReader.result);
2006 }
2007 return;
2008 }
2009
2010 return _this12.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback);
2011 };
2012
2013 return fileReader.readAsDataURL(file);
2014 }
2015 }, {
2016 key: "createThumbnailFromUrl",
2017 value: function createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) {
2018 var _this13 = this;
2019
2020 // Not using `new Image` here because of a bug in latest Chrome versions.
2021 // See https://github.com/enyo/dropzone/pull/226
2022 var img = document.createElement("img");
2023
2024 if (crossOrigin) {
2025 img.crossOrigin = crossOrigin;
2026 }
2027
2028 img.onload = function () {
2029 var loadExif = function loadExif(callback) {
2030 return callback(1);
2031 };
2032 if (typeof EXIF !== 'undefined' && EXIF !== null && fixOrientation) {
2033 loadExif = function loadExif(callback) {
2034 return EXIF.getData(img, function () {
2035 return callback(EXIF.getTag(this, 'Orientation'));
2036 });
2037 };
2038 }
2039
2040 return loadExif(function (orientation) {
2041 file.width = img.width;
2042 file.height = img.height;
2043
2044 var resizeInfo = _this13.options.resize.call(_this13, file, width, height, resizeMethod);
2045
2046 var canvas = document.createElement("canvas");
2047 var ctx = canvas.getContext("2d");
2048
2049 canvas.width = resizeInfo.trgWidth;
2050 canvas.height = resizeInfo.trgHeight;
2051
2052 if (orientation > 4) {
2053 canvas.width = resizeInfo.trgHeight;
2054 canvas.height = resizeInfo.trgWidth;
2055 }
2056
2057 switch (orientation) {
2058 case 2:
2059 // horizontal flip
2060 ctx.translate(canvas.width, 0);
2061 ctx.scale(-1, 1);
2062 break;
2063 case 3:
2064 // 180° rotate left
2065 ctx.translate(canvas.width, canvas.height);
2066 ctx.rotate(Math.PI);
2067 break;
2068 case 4:
2069 // vertical flip
2070 ctx.translate(0, canvas.height);
2071 ctx.scale(1, -1);
2072 break;
2073 case 5:
2074 // vertical flip + 90 rotate right
2075 ctx.rotate(0.5 * Math.PI);
2076 ctx.scale(1, -1);
2077 break;
2078 case 6:
2079 // 90° rotate right
2080 ctx.rotate(0.5 * Math.PI);
2081 ctx.translate(0, -canvas.width);
2082 break;
2083 case 7:
2084 // horizontal flip + 90 rotate right
2085 ctx.rotate(0.5 * Math.PI);
2086 ctx.translate(canvas.height, -canvas.width);
2087 ctx.scale(-1, 1);
2088 break;
2089 case 8:
2090 // 90° rotate left
2091 ctx.rotate(-0.5 * Math.PI);
2092 ctx.translate(-canvas.height, 0);
2093 break;
2094 }
2095
2096 // This is a bugfix for iOS' scaling bug.
2097 drawImageIOSFix(ctx, img, resizeInfo.srcX != null ? resizeInfo.srcX : 0, resizeInfo.srcY != null ? resizeInfo.srcY : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, resizeInfo.trgX != null ? resizeInfo.trgX : 0, resizeInfo.trgY != null ? resizeInfo.trgY : 0, resizeInfo.trgWidth, resizeInfo.trgHeight);
2098
2099 var thumbnail = canvas.toDataURL("image/png");
2100
2101 if (callback != null) {
2102 return callback(thumbnail, canvas);
2103 }
2104 });
2105 };
2106
2107 if (callback != null) {
2108 img.onerror = callback;
2109 }
2110
2111 return img.src = file.dataURL;
2112 }
2113
2114 // Goes through the queue and processes files if there aren't too many already.
2115
2116 }, {
2117 key: "processQueue",
2118 value: function processQueue() {
2119 var parallelUploads = this.options.parallelUploads;
2120
2121 var processingLength = this.getUploadingFiles().length;
2122 var i = processingLength;
2123
2124 // There are already at least as many files uploading than should be
2125 if (processingLength >= parallelUploads) {
2126 return;
2127 }
2128
2129 var queuedFiles = this.getQueuedFiles();
2130
2131 if (!(queuedFiles.length > 0)) {
2132 return;
2133 }
2134
2135 if (this.options.uploadMultiple) {
2136 // The files should be uploaded in one request
2137 return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength));
2138 } else {
2139 while (i < parallelUploads) {
2140 if (!queuedFiles.length) {
2141 return;
2142 } // Nothing left to process
2143 this.processFile(queuedFiles.shift());
2144 i++;
2145 }
2146 }
2147 }
2148
2149 // Wrapper for `processFiles`
2150
2151 }, {
2152 key: "processFile",
2153 value: function processFile(file) {
2154 return this.processFiles([file]);
2155 }
2156
2157 // Loads the file, then calls finishedLoading()
2158
2159 }, {
2160 key: "processFiles",
2161 value: function processFiles(files) {
2162 for (var _iterator19 = files, _isArray19 = true, _i20 = 0, _iterator19 = _isArray19 ? _iterator19 : _iterator19[Symbol.iterator]();;) {
2163 var _ref18;
2164
2165 if (_isArray19) {
2166 if (_i20 >= _iterator19.length) break;
2167 _ref18 = _iterator19[_i20++];
2168 } else {
2169 _i20 = _iterator19.next();
2170 if (_i20.done) break;
2171 _ref18 = _i20.value;
2172 }
2173
2174 var file = _ref18;
2175
2176 file.processing = true; // Backwards compatibility
2177 file.status = Dropzone.UPLOADING;
2178
2179 this.emit("processing", file);
2180 }
2181
2182 if (this.options.uploadMultiple) {
2183 this.emit("processingmultiple", files);
2184 }
2185
2186 return this.uploadFiles(files);
2187 }
2188 }, {
2189 key: "_getFilesWithXhr",
2190 value: function _getFilesWithXhr(xhr) {
2191 var files = void 0;
2192 return files = this.files.filter(function (file) {
2193 return file.xhr === xhr;
2194 }).map(function (file) {
2195 return file;
2196 });
2197 }
2198
2199 // Cancels the file upload and sets the status to CANCELED
2200 // **if** the file is actually being uploaded.
2201 // If it's still in the queue, the file is being removed from it and the status
2202 // set to CANCELED.
2203
2204 }, {
2205 key: "cancelUpload",
2206 value: function cancelUpload(file) {
2207 if (file.status === Dropzone.UPLOADING) {
2208 var groupedFiles = this._getFilesWithXhr(file.xhr);
2209 for (var _iterator20 = groupedFiles, _isArray20 = true, _i21 = 0, _iterator20 = _isArray20 ? _iterator20 : _iterator20[Symbol.iterator]();;) {
2210 var _ref19;
2211
2212 if (_isArray20) {
2213 if (_i21 >= _iterator20.length) break;
2214 _ref19 = _iterator20[_i21++];
2215 } else {
2216 _i21 = _iterator20.next();
2217 if (_i21.done) break;
2218 _ref19 = _i21.value;
2219 }
2220
2221 var groupedFile = _ref19;
2222
2223 groupedFile.status = Dropzone.CANCELED;
2224 }
2225 if (typeof file.xhr !== 'undefined') {
2226 file.xhr.abort();
2227 }
2228 for (var _iterator21 = groupedFiles, _isArray21 = true, _i22 = 0, _iterator21 = _isArray21 ? _iterator21 : _iterator21[Symbol.iterator]();;) {
2229 var _ref20;
2230
2231 if (_isArray21) {
2232 if (_i22 >= _iterator21.length) break;
2233 _ref20 = _iterator21[_i22++];
2234 } else {
2235 _i22 = _iterator21.next();
2236 if (_i22.done) break;
2237 _ref20 = _i22.value;
2238 }
2239
2240 var _groupedFile = _ref20;
2241
2242 this.emit("canceled", _groupedFile);
2243 }
2244 if (this.options.uploadMultiple) {
2245 this.emit("canceledmultiple", groupedFiles);
2246 }
2247 } else if (file.status === Dropzone.ADDED || file.status === Dropzone.QUEUED) {
2248 file.status = Dropzone.CANCELED;
2249 this.emit("canceled", file);
2250 if (this.options.uploadMultiple) {
2251 this.emit("canceledmultiple", [file]);
2252 }
2253 }
2254
2255 if (this.options.autoProcessQueue) {
2256 return this.processQueue();
2257 }
2258 }
2259 }, {
2260 key: "resolveOption",
2261 value: function resolveOption(option) {
2262 if (typeof option === 'function') {
2263 for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
2264 args[_key3 - 1] = arguments[_key3];
2265 }
2266
2267 return option.apply(this, args);
2268 }
2269 return option;
2270 }
2271 }, {
2272 key: "uploadFile",
2273 value: function uploadFile(file) {
2274 return this.uploadFiles([file]);
2275 }
2276 }, {
2277 key: "uploadFiles",
2278 value: function uploadFiles(files) {
2279 var _this14 = this;
2280
2281 this._transformFiles(files, function (transformedFiles) {
2282 if (files[0].upload.chunked) {
2283 // This file should be sent in chunks!
2284
2285 // If the chunking option is set, we **know** that there can only be **one** file, since
2286 // uploadMultiple is not allowed with this option.
2287 var file = files[0];
2288 var transformedFile = transformedFiles[0];
2289 var startedChunkCount = 0;
2290
2291 file.upload.chunks = [];
2292
2293 var handleNextChunk = function handleNextChunk() {
2294 var chunkIndex = 0;
2295
2296 // Find the next item in file.upload.chunks that is not defined yet.
2297 while (file.upload.chunks[chunkIndex] !== undefined) {
2298 chunkIndex++;
2299 }
2300
2301 // This means, that all chunks have already been started.
2302 if (chunkIndex >= file.upload.totalChunkCount) return;
2303
2304 startedChunkCount++;
2305
2306 var start = chunkIndex * _this14.options.chunkSize;
2307 var end = Math.min(start + _this14.options.chunkSize, file.size);
2308
2309 var dataBlock = {
2310 name: _this14._getParamName(0),
2311 data: transformedFile.webkitSlice ? transformedFile.webkitSlice(start, end) : transformedFile.slice(start, end),
2312 filename: file.upload.filename,
2313 chunkIndex: chunkIndex
2314 };
2315
2316 file.upload.chunks[chunkIndex] = {
2317 file: file,
2318 index: chunkIndex,
2319 dataBlock: dataBlock, // In case we want to retry.
2320 status: Dropzone.UPLOADING,
2321 progress: 0,
2322 retries: 0 // The number of times this block has been retried.
2323 };
2324
2325 _this14._uploadData(files, [dataBlock]);
2326 };
2327
2328 file.upload.finishedChunkUpload = function (chunk) {
2329 var allFinished = true;
2330 chunk.status = Dropzone.SUCCESS;
2331
2332 // Clear the data from the chunk
2333 chunk.dataBlock = null;
2334 // Leaving this reference to xhr intact here will cause memory leaks in some browsers
2335 chunk.xhr = null;
2336
2337 for (var i = 0; i < file.upload.totalChunkCount; i++) {
2338 if (file.upload.chunks[i] === undefined) {
2339 return handleNextChunk();
2340 }
2341 if (file.upload.chunks[i].status !== Dropzone.SUCCESS) {
2342 allFinished = false;
2343 }
2344 }
2345
2346 if (allFinished) {
2347 _this14.options.chunksUploaded(file, function () {
2348 _this14._finished(files, '', null);
2349 });
2350 }
2351 };
2352
2353 if (_this14.options.parallelChunkUploads) {
2354 for (var i = 0; i < file.upload.totalChunkCount; i++) {
2355 handleNextChunk();
2356 }
2357 } else {
2358 handleNextChunk();
2359 }
2360 } else {
2361 var dataBlocks = [];
2362 for (var _i23 = 0; _i23 < files.length; _i23++) {
2363 dataBlocks[_i23] = {
2364 name: _this14._getParamName(_i23),
2365 data: transformedFiles[_i23],
2366 filename: files[_i23].upload.filename
2367 };
2368 }
2369 _this14._uploadData(files, dataBlocks);
2370 }
2371 });
2372 }
2373
2374 /// Returns the right chunk for given file and xhr
2375
2376 }, {
2377 key: "_getChunk",
2378 value: function _getChunk(file, xhr) {
2379 for (var i = 0; i < file.upload.totalChunkCount; i++) {
2380 if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].xhr === xhr) {
2381 return file.upload.chunks[i];
2382 }
2383 }
2384 }
2385
2386 // This function actually uploads the file(s) to the server.
2387 // If dataBlocks contains the actual data to upload (meaning, that this could either be transformed
2388 // files, or individual chunks for chunked upload).
2389
2390 }, {
2391 key: "_uploadData",
2392 value: function _uploadData(files, dataBlocks) {
2393 var _this15 = this;
2394
2395 var xhr = new XMLHttpRequest();
2396
2397 // Put the xhr object in the file objects to be able to reference it later.
2398 for (var _iterator22 = files, _isArray22 = true, _i24 = 0, _iterator22 = _isArray22 ? _iterator22 : _iterator22[Symbol.iterator]();;) {
2399 var _ref21;
2400
2401 if (_isArray22) {
2402 if (_i24 >= _iterator22.length) break;
2403 _ref21 = _iterator22[_i24++];
2404 } else {
2405 _i24 = _iterator22.next();
2406 if (_i24.done) break;
2407 _ref21 = _i24.value;
2408 }
2409
2410 var file = _ref21;
2411
2412 file.xhr = xhr;
2413 }
2414 if (files[0].upload.chunked) {
2415 // Put the xhr object in the right chunk object, so it can be associated later, and found with _getChunk
2416 files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr = xhr;
2417 }
2418
2419 var method = this.resolveOption(this.options.method, files);
2420 var url = this.resolveOption(this.options.url, files);
2421 xhr.open(method, url, true);
2422
2423 // Setting the timeout after open because of IE11 issue: https://gitlab.com/meno/dropzone/issues/8
2424 xhr.timeout = this.resolveOption(this.options.timeout, files);
2425
2426 // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179
2427 xhr.withCredentials = !!this.options.withCredentials;
2428
2429 xhr.onload = function (e) {
2430 _this15._finishedUploading(files, xhr, e);
2431 };
2432
2433 xhr.onerror = function () {
2434 _this15._handleUploadError(files, xhr);
2435 };
2436
2437 // Some browsers do not have the .upload property
2438 var progressObj = xhr.upload != null ? xhr.upload : xhr;
2439 progressObj.onprogress = function (e) {
2440 return _this15._updateFilesUploadProgress(files, xhr, e);
2441 };
2442
2443 var headers = {
2444 "Accept": "application/json",
2445 "Cache-Control": "no-cache",
2446 "X-Requested-With": "XMLHttpRequest"
2447 };
2448
2449 if (this.options.headers) {
2450 Dropzone.extend(headers, this.options.headers);
2451 }
2452
2453 for (var headerName in headers) {
2454 var headerValue = headers[headerName];
2455 if (headerValue) {
2456 xhr.setRequestHeader(headerName, headerValue);
2457 }
2458 }
2459
2460 var formData = new FormData();
2461
2462 // Adding all @options parameters
2463 if (this.options.params) {
2464 var additionalParams = this.options.params;
2465 if (typeof additionalParams === 'function') {
2466 additionalParams = additionalParams.call(this, files, xhr, files[0].upload.chunked ? this._getChunk(files[0], xhr) : null);
2467 }
2468
2469 for (var key in additionalParams) {
2470 var value = additionalParams[key];
2471 formData.append(key, value);
2472 }
2473 }
2474
2475 // Let the user add additional data if necessary
2476 for (var _iterator23 = files, _isArray23 = true, _i25 = 0, _iterator23 = _isArray23 ? _iterator23 : _iterator23[Symbol.iterator]();;) {
2477 var _ref22;
2478
2479 if (_isArray23) {
2480 if (_i25 >= _iterator23.length) break;
2481 _ref22 = _iterator23[_i25++];
2482 } else {
2483 _i25 = _iterator23.next();
2484 if (_i25.done) break;
2485 _ref22 = _i25.value;
2486 }
2487
2488 var _file = _ref22;
2489
2490 this.emit("sending", _file, xhr, formData);
2491 }
2492 if (this.options.uploadMultiple) {
2493 this.emit("sendingmultiple", files, xhr, formData);
2494 }
2495
2496 this._addFormElementData(formData);
2497
2498 // Finally add the files
2499 // Has to be last because some servers (eg: S3) expect the file to be the last parameter
2500 for (var i = 0; i < dataBlocks.length; i++) {
2501 var dataBlock = dataBlocks[i];
2502 formData.append(dataBlock.name, dataBlock.data, dataBlock.filename);
2503 }
2504
2505 this.submitRequest(xhr, formData, files);
2506 }
2507
2508 // Transforms all files with this.options.transformFile and invokes done with the transformed files when done.
2509
2510 }, {
2511 key: "_transformFiles",
2512 value: function _transformFiles(files, done) {
2513 var _this16 = this;
2514
2515 var transformedFiles = [];
2516 // Clumsy way of handling asynchronous calls, until I get to add a proper Future library.
2517 var doneCounter = 0;
2518
2519 var _loop = function _loop(i) {
2520 _this16.options.transformFile.call(_this16, files[i], function (transformedFile) {
2521 transformedFiles[i] = transformedFile;
2522 if (++doneCounter === files.length) {
2523 done(transformedFiles);
2524 }
2525 });
2526 };
2527
2528 for (var i = 0; i < files.length; i++) {
2529 _loop(i);
2530 }
2531 }
2532
2533 // Takes care of adding other input elements of the form to the AJAX request
2534
2535 }, {
2536 key: "_addFormElementData",
2537 value: function _addFormElementData(formData) {
2538 // Take care of other input elements
2539 if (this.element.tagName === "FORM") {
2540 for (var _iterator24 = this.element.querySelectorAll("input, textarea, select, button"), _isArray24 = true, _i26 = 0, _iterator24 = _isArray24 ? _iterator24 : _iterator24[Symbol.iterator]();;) {
2541 var _ref23;
2542
2543 if (_isArray24) {
2544 if (_i26 >= _iterator24.length) break;
2545 _ref23 = _iterator24[_i26++];
2546 } else {
2547 _i26 = _iterator24.next();
2548 if (_i26.done) break;
2549 _ref23 = _i26.value;
2550 }
2551
2552 var input = _ref23;
2553
2554 var inputName = input.getAttribute("name");
2555 var inputType = input.getAttribute("type");
2556 if (inputType) inputType = inputType.toLowerCase();
2557
2558 // If the input doesn't have a name, we can't use it.
2559 if (typeof inputName === 'undefined' || inputName === null) continue;
2560
2561 if (input.tagName === "SELECT" && input.hasAttribute("multiple")) {
2562 // Possibly multiple values
2563 for (var _iterator25 = input.options, _isArray25 = true, _i27 = 0, _iterator25 = _isArray25 ? _iterator25 : _iterator25[Symbol.iterator]();;) {
2564 var _ref24;
2565
2566 if (_isArray25) {
2567 if (_i27 >= _iterator25.length) break;
2568 _ref24 = _iterator25[_i27++];
2569 } else {
2570 _i27 = _iterator25.next();
2571 if (_i27.done) break;
2572 _ref24 = _i27.value;
2573 }
2574
2575 var option = _ref24;
2576
2577 if (option.selected) {
2578 formData.append(inputName, option.value);
2579 }
2580 }
2581 } else if (!inputType || inputType !== "checkbox" && inputType !== "radio" || input.checked) {
2582 formData.append(inputName, input.value);
2583 }
2584 }
2585 }
2586 }
2587
2588 // Invoked when there is new progress information about given files.
2589 // If e is not provided, it is assumed that the upload is finished.
2590
2591 }, {
2592 key: "_updateFilesUploadProgress",
2593 value: function _updateFilesUploadProgress(files, xhr, e) {
2594 var progress = void 0;
2595 if (typeof e !== 'undefined') {
2596 progress = 100 * e.loaded / e.total;
2597
2598 if (files[0].upload.chunked) {
2599 var file = files[0];
2600 // Since this is a chunked upload, we need to update the appropriate chunk progress.
2601 var chunk = this._getChunk(file, xhr);
2602 chunk.progress = progress;
2603 chunk.total = e.total;
2604 chunk.bytesSent = e.loaded;
2605 var fileProgress = 0,
2606 fileTotal = void 0,
2607 fileBytesSent = void 0;
2608 file.upload.progress = 0;
2609 file.upload.total = 0;
2610 file.upload.bytesSent = 0;
2611 for (var i = 0; i < file.upload.totalChunkCount; i++) {
2612 if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].progress !== undefined) {
2613 file.upload.progress += file.upload.chunks[i].progress;
2614 file.upload.total += file.upload.chunks[i].total;
2615 file.upload.bytesSent += file.upload.chunks[i].bytesSent;
2616 }
2617 }
2618 file.upload.progress = file.upload.progress / file.upload.totalChunkCount;
2619 } else {
2620 for (var _iterator26 = files, _isArray26 = true, _i28 = 0, _iterator26 = _isArray26 ? _iterator26 : _iterator26[Symbol.iterator]();;) {
2621 var _ref25;
2622
2623 if (_isArray26) {
2624 if (_i28 >= _iterator26.length) break;
2625 _ref25 = _iterator26[_i28++];
2626 } else {
2627 _i28 = _iterator26.next();
2628 if (_i28.done) break;
2629 _ref25 = _i28.value;
2630 }
2631
2632 var _file2 = _ref25;
2633
2634 _file2.upload.progress = progress;
2635 _file2.upload.total = e.total;
2636 _file2.upload.bytesSent = e.loaded;
2637 }
2638 }
2639 for (var _iterator27 = files, _isArray27 = true, _i29 = 0, _iterator27 = _isArray27 ? _iterator27 : _iterator27[Symbol.iterator]();;) {
2640 var _ref26;
2641
2642 if (_isArray27) {
2643 if (_i29 >= _iterator27.length) break;
2644 _ref26 = _iterator27[_i29++];
2645 } else {
2646 _i29 = _iterator27.next();
2647 if (_i29.done) break;
2648 _ref26 = _i29.value;
2649 }
2650
2651 var _file3 = _ref26;
2652
2653 this.emit("uploadprogress", _file3, _file3.upload.progress, _file3.upload.bytesSent);
2654 }
2655 } else {
2656 // Called when the file finished uploading
2657
2658 var allFilesFinished = true;
2659
2660 progress = 100;
2661
2662 for (var _iterator28 = files, _isArray28 = true, _i30 = 0, _iterator28 = _isArray28 ? _iterator28 : _iterator28[Symbol.iterator]();;) {
2663 var _ref27;
2664
2665 if (_isArray28) {
2666 if (_i30 >= _iterator28.length) break;
2667 _ref27 = _iterator28[_i30++];
2668 } else {
2669 _i30 = _iterator28.next();
2670 if (_i30.done) break;
2671 _ref27 = _i30.value;
2672 }
2673
2674 var _file4 = _ref27;
2675
2676 if (_file4.upload.progress !== 100 || _file4.upload.bytesSent !== _file4.upload.total) {
2677 allFilesFinished = false;
2678 }
2679 _file4.upload.progress = progress;
2680 _file4.upload.bytesSent = _file4.upload.total;
2681 }
2682
2683 // Nothing to do, all files already at 100%
2684 if (allFilesFinished) {
2685 return;
2686 }
2687
2688 for (var _iterator29 = files, _isArray29 = true, _i31 = 0, _iterator29 = _isArray29 ? _iterator29 : _iterator29[Symbol.iterator]();;) {
2689 var _ref28;
2690
2691 if (_isArray29) {
2692 if (_i31 >= _iterator29.length) break;
2693 _ref28 = _iterator29[_i31++];
2694 } else {
2695 _i31 = _iterator29.next();
2696 if (_i31.done) break;
2697 _ref28 = _i31.value;
2698 }
2699
2700 var _file5 = _ref28;
2701
2702 this.emit("uploadprogress", _file5, progress, _file5.upload.bytesSent);
2703 }
2704 }
2705 }
2706 }, {
2707 key: "_finishedUploading",
2708 value: function _finishedUploading(files, xhr, e) {
2709 var response = void 0;
2710
2711 if (files[0].status === Dropzone.CANCELED) {
2712 return;
2713 }
2714
2715 if (xhr.readyState !== 4) {
2716 return;
2717 }
2718
2719 if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') {
2720 response = xhr.responseText;
2721
2722 if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) {
2723 try {
2724 response = JSON.parse(response);
2725 } catch (error) {
2726 e = error;
2727 response = "Invalid JSON response from server.";
2728 }
2729 }
2730 }
2731
2732 this._updateFilesUploadProgress(files);
2733
2734 if (!(200 <= xhr.status && xhr.status < 300)) {
2735 this._handleUploadError(files, xhr, response);
2736 } else {
2737 if (files[0].upload.chunked) {
2738 files[0].upload.finishedChunkUpload(this._getChunk(files[0], xhr));
2739 } else {
2740 this._finished(files, response, e);
2741 }
2742 }
2743 }
2744 }, {
2745 key: "_handleUploadError",
2746 value: function _handleUploadError(files, xhr, response) {
2747 if (files[0].status === Dropzone.CANCELED) {
2748 return;
2749 }
2750
2751 if (files[0].upload.chunked && this.options.retryChunks) {
2752 var chunk = this._getChunk(files[0], xhr);
2753 if (chunk.retries++ < this.options.retryChunksLimit) {
2754 this._uploadData(files, [chunk.dataBlock]);
2755 return;
2756 } else {
2757 console.warn('Retried this chunk too often. Giving up.');
2758 }
2759 }
2760
2761 for (var _iterator30 = files, _isArray30 = true, _i32 = 0, _iterator30 = _isArray30 ? _iterator30 : _iterator30[Symbol.iterator]();;) {
2762 var _ref29;
2763
2764 if (_isArray30) {
2765 if (_i32 >= _iterator30.length) break;
2766 _ref29 = _iterator30[_i32++];
2767 } else {
2768 _i32 = _iterator30.next();
2769 if (_i32.done) break;
2770 _ref29 = _i32.value;
2771 }
2772
2773 var file = _ref29;
2774
2775 this._errorProcessing(files, response || this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr);
2776 }
2777 }
2778 }, {
2779 key: "submitRequest",
2780 value: function submitRequest(xhr, formData, files) {
2781 xhr.send(formData);
2782 }
2783
2784 // Called internally when processing is finished.
2785 // Individual callbacks have to be called in the appropriate sections.
2786
2787 }, {
2788 key: "_finished",
2789 value: function _finished(files, responseText, e) {
2790 for (var _iterator31 = files, _isArray31 = true, _i33 = 0, _iterator31 = _isArray31 ? _iterator31 : _iterator31[Symbol.iterator]();;) {
2791 var _ref30;
2792
2793 if (_isArray31) {
2794 if (_i33 >= _iterator31.length) break;
2795 _ref30 = _iterator31[_i33++];
2796 } else {
2797 _i33 = _iterator31.next();
2798 if (_i33.done) break;
2799 _ref30 = _i33.value;
2800 }
2801
2802 var file = _ref30;
2803
2804 file.status = Dropzone.SUCCESS;
2805 this.emit("success", file, responseText, e);
2806 this.emit("complete", file);
2807 }
2808 if (this.options.uploadMultiple) {
2809 this.emit("successmultiple", files, responseText, e);
2810 this.emit("completemultiple", files);
2811 }
2812
2813 if (this.options.autoProcessQueue) {
2814 return this.processQueue();
2815 }
2816 }
2817
2818 // Called internally when processing is finished.
2819 // Individual callbacks have to be called in the appropriate sections.
2820
2821 }, {
2822 key: "_errorProcessing",
2823 value: function _errorProcessing(files, message, xhr) {
2824 for (var _iterator32 = files, _isArray32 = true, _i34 = 0, _iterator32 = _isArray32 ? _iterator32 : _iterator32[Symbol.iterator]();;) {
2825 var _ref31;
2826
2827 if (_isArray32) {
2828 if (_i34 >= _iterator32.length) break;
2829 _ref31 = _iterator32[_i34++];
2830 } else {
2831 _i34 = _iterator32.next();
2832 if (_i34.done) break;
2833 _ref31 = _i34.value;
2834 }
2835
2836 var file = _ref31;
2837
2838 file.status = Dropzone.ERROR;
2839 this.emit("error", file, message, xhr);
2840 this.emit("complete", file);
2841 }
2842 if (this.options.uploadMultiple) {
2843 this.emit("errormultiple", files, message, xhr);
2844 this.emit("completemultiple", files);
2845 }
2846
2847 if (this.options.autoProcessQueue) {
2848 return this.processQueue();
2849 }
2850 }
2851 }], [{
2852 key: "uuidv4",
2853 value: function uuidv4() {
2854 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
2855 var r = Math.random() * 16 | 0,
2856 v = c === 'x' ? r : r & 0x3 | 0x8;
2857 return v.toString(16);
2858 });
2859 }
2860 }]);
2861
2862 return Dropzone;
2863}(Emitter);
2864
2865Dropzone.initClass();
2866
2867Dropzone.version = "5.5.0";
2868
2869// This is a map of options for your different dropzones. Add configurations
2870// to this object for your different dropzone elemens.
2871//
2872// Example:
2873//
2874// Dropzone.options.myDropzoneElementId = { maxFilesize: 1 };
2875//
2876// To disable autoDiscover for a specific element, you can set `false` as an option:
2877//
2878// Dropzone.options.myDisabledElementId = false;
2879//
2880// And in html:
2881//
2882// <form action="/upload" id="my-dropzone-element-id" class="dropzone"></form>
2883Dropzone.options = {};
2884
2885// Returns the options for an element or undefined if none available.
2886Dropzone.optionsForElement = function (element) {
2887 // Get the `Dropzone.options.elementId` for this element if it exists
2888 if (element.getAttribute("id")) {
2889 return Dropzone.options[camelize(element.getAttribute("id"))];
2890 } else {
2891 return undefined;
2892 }
2893};
2894
2895// Holds a list of all dropzone instances
2896Dropzone.instances = [];
2897
2898// Returns the dropzone for given element if any
2899Dropzone.forElement = function (element) {
2900 if (typeof element === "string") {
2901 element = document.querySelector(element);
2902 }
2903 if ((element != null ? element.dropzone : undefined) == null) {
2904 throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");
2905 }
2906 return element.dropzone;
2907};
2908
2909// Set to false if you don't want Dropzone to automatically find and attach to .dropzone elements.
2910Dropzone.autoDiscover = false;
2911
2912// Looks for all .dropzone elements and creates a dropzone for them
2913Dropzone.discover = function () {
2914 var dropzones = void 0;
2915 if (document.querySelectorAll) {
2916 dropzones = document.querySelectorAll(".dropzone");
2917 } else {
2918 dropzones = [];
2919 // IE :(
2920 var checkElements = function checkElements(elements) {
2921 return function () {
2922 var result = [];
2923 for (var _iterator33 = elements, _isArray33 = true, _i35 = 0, _iterator33 = _isArray33 ? _iterator33 : _iterator33[Symbol.iterator]();;) {
2924 var _ref32;
2925
2926 if (_isArray33) {
2927 if (_i35 >= _iterator33.length) break;
2928 _ref32 = _iterator33[_i35++];
2929 } else {
2930 _i35 = _iterator33.next();
2931 if (_i35.done) break;
2932 _ref32 = _i35.value;
2933 }
2934
2935 var el = _ref32;
2936
2937 if (/(^| )dropzone($| )/.test(el.className)) {
2938 result.push(dropzones.push(el));
2939 } else {
2940 result.push(undefined);
2941 }
2942 }
2943 return result;
2944 }();
2945 };
2946 checkElements(document.getElementsByTagName("div"));
2947 checkElements(document.getElementsByTagName("form"));
2948 }
2949
2950 return function () {
2951 var result = [];
2952 for (var _iterator34 = dropzones, _isArray34 = true, _i36 = 0, _iterator34 = _isArray34 ? _iterator34 : _iterator34[Symbol.iterator]();;) {
2953 var _ref33;
2954
2955 if (_isArray34) {
2956 if (_i36 >= _iterator34.length) break;
2957 _ref33 = _iterator34[_i36++];
2958 } else {
2959 _i36 = _iterator34.next();
2960 if (_i36.done) break;
2961 _ref33 = _i36.value;
2962 }
2963
2964 var dropzone = _ref33;
2965
2966 // Create a dropzone unless auto discover has been disabled for specific element
2967 if (Dropzone.optionsForElement(dropzone) !== false) {
2968 result.push(new Dropzone(dropzone));
2969 } else {
2970 result.push(undefined);
2971 }
2972 }
2973 return result;
2974 }();
2975};
2976
2977// Since the whole Drag'n'Drop API is pretty new, some browsers implement it,
2978// but not correctly.
2979// So I created a blacklist of userAgents. Yes, yes. Browser sniffing, I know.
2980// But what to do when browsers *theoretically* support an API, but crash
2981// when using it.
2982//
2983// This is a list of regular expressions tested against navigator.userAgent
2984//
2985// ** It should only be used on browser that *do* support the API, but
2986// incorrectly **
2987//
2988Dropzone.blacklistedBrowsers = [
2989// The mac os and windows phone version of opera 12 seems to have a problem with the File drag'n'drop API.
2990 /opera.*(Macintosh|Windows Phone).*version\/12/i];
2991
2992// Checks if the browser is supported
2993Dropzone.isBrowserSupported = function () {
2994 var capableBrowser = true;
2995
2996 if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) {
2997 if (!("classList" in document.createElement("a"))) {
2998 capableBrowser = false;
2999 } else {
3000 // The browser supports the API, but may be blacklisted.
3001 for (var _iterator35 = Dropzone.blacklistedBrowsers, _isArray35 = true, _i37 = 0, _iterator35 = _isArray35 ? _iterator35 : _iterator35[Symbol.iterator]();;) {
3002 var _ref34;
3003
3004 if (_isArray35) {
3005 if (_i37 >= _iterator35.length) break;
3006 _ref34 = _iterator35[_i37++];
3007 } else {
3008 _i37 = _iterator35.next();
3009 if (_i37.done) break;
3010 _ref34 = _i37.value;
3011 }
3012
3013 var regex = _ref34;
3014
3015 if (regex.test(navigator.userAgent)) {
3016 capableBrowser = false;
3017 continue;
3018 }
3019 }
3020 }
3021 } else {
3022 capableBrowser = false;
3023 }
3024
3025 return capableBrowser;
3026};
3027
3028Dropzone.dataURItoBlob = function (dataURI) {
3029 // convert base64 to raw binary data held in a string
3030 // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
3031 var byteString = atob(dataURI.split(',')[1]);
3032
3033 // separate out the mime component
3034 var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
3035
3036 // write the bytes of the string to an ArrayBuffer
3037 var ab = new ArrayBuffer(byteString.length);
3038 var ia = new Uint8Array(ab);
3039 for (var i = 0, end = byteString.length, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) {
3040 ia[i] = byteString.charCodeAt(i);
3041 }
3042
3043 // write the ArrayBuffer to a blob
3044 return new Blob([ab], { type: mimeString });
3045};
3046
3047// Returns an array without the rejected item
3048var without = function without(list, rejectedItem) {
3049 return list.filter(function (item) {
3050 return item !== rejectedItem;
3051 }).map(function (item) {
3052 return item;
3053 });
3054};
3055
3056// abc-def_ghi -> abcDefGhi
3057var camelize = function camelize(str) {
3058 return str.replace(/[\-_](\w)/g, function (match) {
3059 return match.charAt(1).toUpperCase();
3060 });
3061};
3062
3063// Creates an element from string
3064Dropzone.createElement = function (string) {
3065 var div = document.createElement("div");
3066 div.innerHTML = string;
3067 return div.childNodes[0];
3068};
3069
3070// Tests if given element is inside (or simply is) the container
3071Dropzone.elementInside = function (element, container) {
3072 if (element === container) {
3073 return true;
3074 } // Coffeescript doesn't support do/while loops
3075 while (element = element.parentNode) {
3076 if (element === container) {
3077 return true;
3078 }
3079 }
3080 return false;
3081};
3082
3083Dropzone.getElement = function (el, name) {
3084 var element = void 0;
3085 if (typeof el === "string") {
3086 element = document.querySelector(el);
3087 } else if (el.nodeType != null) {
3088 element = el;
3089 }
3090 if (element == null) {
3091 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element.");
3092 }
3093 return element;
3094};
3095
3096Dropzone.getElements = function (els, name) {
3097 var el = void 0,
3098 elements = void 0;
3099 if (els instanceof Array) {
3100 elements = [];
3101 try {
3102 for (var _iterator36 = els, _isArray36 = true, _i38 = 0, _iterator36 = _isArray36 ? _iterator36 : _iterator36[Symbol.iterator]();;) {
3103 if (_isArray36) {
3104 if (_i38 >= _iterator36.length) break;
3105 el = _iterator36[_i38++];
3106 } else {
3107 _i38 = _iterator36.next();
3108 if (_i38.done) break;
3109 el = _i38.value;
3110 }
3111
3112 elements.push(this.getElement(el, name));
3113 }
3114 } catch (e) {
3115 elements = null;
3116 }
3117 } else if (typeof els === "string") {
3118 elements = [];
3119 for (var _iterator37 = document.querySelectorAll(els), _isArray37 = true, _i39 = 0, _iterator37 = _isArray37 ? _iterator37 : _iterator37[Symbol.iterator]();;) {
3120 if (_isArray37) {
3121 if (_i39 >= _iterator37.length) break;
3122 el = _iterator37[_i39++];
3123 } else {
3124 _i39 = _iterator37.next();
3125 if (_i39.done) break;
3126 el = _i39.value;
3127 }
3128
3129 elements.push(el);
3130 }
3131 } else if (els.nodeType != null) {
3132 elements = [els];
3133 }
3134
3135 if (elements == null || !elements.length) {
3136 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");
3137 }
3138
3139 return elements;
3140};
3141
3142// Asks the user the question and calls accepted or rejected accordingly
3143//
3144// The default implementation just uses `window.confirm` and then calls the
3145// appropriate callback.
3146Dropzone.confirm = function (question, accepted, rejected) {
3147 if (window.confirm(question)) {
3148 return accepted();
3149 } else if (rejected != null) {
3150 return rejected();
3151 }
3152};
3153
3154// Validates the mime type like this:
3155//
3156// https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept
3157Dropzone.isValidFile = function (file, acceptedFiles) {
3158 if (!acceptedFiles) {
3159 return true;
3160 } // If there are no accepted mime types, it's OK
3161 acceptedFiles = acceptedFiles.split(",");
3162
3163 var mimeType = file.type;
3164 var baseMimeType = mimeType.replace(/\/.*$/, "");
3165
3166 for (var _iterator38 = acceptedFiles, _isArray38 = true, _i40 = 0, _iterator38 = _isArray38 ? _iterator38 : _iterator38[Symbol.iterator]();;) {
3167 var _ref35;
3168
3169 if (_isArray38) {
3170 if (_i40 >= _iterator38.length) break;
3171 _ref35 = _iterator38[_i40++];
3172 } else {
3173 _i40 = _iterator38.next();
3174 if (_i40.done) break;
3175 _ref35 = _i40.value;
3176 }
3177
3178 var validType = _ref35;
3179
3180 validType = validType.trim();
3181 if (validType.charAt(0) === ".") {
3182 if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) {
3183 return true;
3184 }
3185 } else if (/\/\*$/.test(validType)) {
3186 // This is something like a image/* mime type
3187 if (baseMimeType === validType.replace(/\/.*$/, "")) {
3188 return true;
3189 }
3190 } else {
3191 if (mimeType === validType) {
3192 return true;
3193 }
3194 }
3195 }
3196
3197 return false;
3198};
3199
3200// Augment jQuery
3201if (typeof jQuery !== 'undefined' && jQuery !== null) {
3202 jQuery.fn.dropzone = function (options) {
3203 return this.each(function () {
3204 return new Dropzone(this, options);
3205 });
3206 };
3207}
3208
3209if (typeof module !== 'undefined' && module !== null) {
3210 module.exports = Dropzone;
3211} else {
3212 window.Dropzone = Dropzone;
3213}
3214
3215// Dropzone file status codes
3216Dropzone.ADDED = "added";
3217
3218Dropzone.QUEUED = "queued";
3219// For backwards compatibility. Now, if a file is accepted, it's either queued
3220// or uploading.
3221Dropzone.ACCEPTED = Dropzone.QUEUED;
3222
3223Dropzone.UPLOADING = "uploading";
3224Dropzone.PROCESSING = Dropzone.UPLOADING; // alias
3225
3226Dropzone.CANCELED = "canceled";
3227Dropzone.ERROR = "error";
3228Dropzone.SUCCESS = "success";
3229
3230/*
3231
3232 Bugfix for iOS 6 and 7
3233 Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios
3234 based on the work of https://github.com/stomita/ios-imagefile-megapixel
3235
3236 */
3237
3238// Detecting vertical squash in loaded image.
3239// Fixes a bug which squash image vertically while drawing into canvas for some images.
3240// This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel
3241var detectVerticalSquash = function detectVerticalSquash(img) {
3242 var iw = img.naturalWidth;
3243 var ih = img.naturalHeight;
3244 var canvas = document.createElement("canvas");
3245 canvas.width = 1;
3246 canvas.height = ih;
3247 var ctx = canvas.getContext("2d");
3248 ctx.drawImage(img, 0, 0);
3249
3250 var _ctx$getImageData = ctx.getImageData(1, 0, 1, ih),
3251 data = _ctx$getImageData.data;
3252
3253 // search image edge pixel position in case it is squashed vertically.
3254
3255
3256 var sy = 0;
3257 var ey = ih;
3258 var py = ih;
3259 while (py > sy) {
3260 var alpha = data[(py - 1) * 4 + 3];
3261
3262 if (alpha === 0) {
3263 ey = py;
3264 } else {
3265 sy = py;
3266 }
3267
3268 py = ey + sy >> 1;
3269 }
3270 var ratio = py / ih;
3271
3272 if (ratio === 0) {
3273 return 1;
3274 } else {
3275 return ratio;
3276 }
3277};
3278
3279// A replacement for context.drawImage
3280// (args are for source and destination).
3281var drawImageIOSFix = function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {
3282 var vertSquashRatio = detectVerticalSquash(img);
3283 return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
3284};
3285
3286// Based on MinifyJpeg
3287// Source: http://www.perry.cz/files/ExifRestorer.js
3288// http://elicon.blog57.fc2.com/blog-entry-206.html
3289
3290var ExifRestore = function () {
3291 function ExifRestore() {
3292 _classCallCheck(this, ExifRestore);
3293 }
3294
3295 _createClass(ExifRestore, null, [{
3296 key: "initClass",
3297 value: function initClass() {
3298 this.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
3299 }
3300 }, {
3301 key: "encode64",
3302 value: function encode64(input) {
3303 var output = '';
3304 var chr1 = undefined;
3305 var chr2 = undefined;
3306 var chr3 = '';
3307 var enc1 = undefined;
3308 var enc2 = undefined;
3309 var enc3 = undefined;
3310 var enc4 = '';
3311 var i = 0;
3312 while (true) {
3313 chr1 = input[i++];
3314 chr2 = input[i++];
3315 chr3 = input[i++];
3316 enc1 = chr1 >> 2;
3317 enc2 = (chr1 & 3) << 4 | chr2 >> 4;
3318 enc3 = (chr2 & 15) << 2 | chr3 >> 6;
3319 enc4 = chr3 & 63;
3320 if (isNaN(chr2)) {
3321 enc3 = enc4 = 64;
3322 } else if (isNaN(chr3)) {
3323 enc4 = 64;
3324 }
3325 output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4);
3326 chr1 = chr2 = chr3 = '';
3327 enc1 = enc2 = enc3 = enc4 = '';
3328 if (!(i < input.length)) {
3329 break;
3330 }
3331 }
3332 return output;
3333 }
3334 }, {
3335 key: "restore",
3336 value: function restore(origFileBase64, resizedFileBase64) {
3337 if (!origFileBase64.match('data:image/jpeg;base64,')) {
3338 return resizedFileBase64;
3339 }
3340 var rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', ''));
3341 var segments = this.slice2Segments(rawImage);
3342 var image = this.exifManipulation(resizedFileBase64, segments);
3343 return "data:image/jpeg;base64," + this.encode64(image);
3344 }
3345 }, {
3346 key: "exifManipulation",
3347 value: function exifManipulation(resizedFileBase64, segments) {
3348 var exifArray = this.getExifArray(segments);
3349 var newImageArray = this.insertExif(resizedFileBase64, exifArray);
3350 var aBuffer = new Uint8Array(newImageArray);
3351 return aBuffer;
3352 }
3353 }, {
3354 key: "getExifArray",
3355 value: function getExifArray(segments) {
3356 var seg = undefined;
3357 var x = 0;
3358 while (x < segments.length) {
3359 seg = segments[x];
3360 if (seg[0] === 255 & seg[1] === 225) {
3361 return seg;
3362 }
3363 x++;
3364 }
3365 return [];
3366 }
3367 }, {
3368 key: "insertExif",
3369 value: function insertExif(resizedFileBase64, exifArray) {
3370 var imageData = resizedFileBase64.replace('data:image/jpeg;base64,', '');
3371 var buf = this.decode64(imageData);
3372 var separatePoint = buf.indexOf(255, 3);
3373 var mae = buf.slice(0, separatePoint);
3374 var ato = buf.slice(separatePoint);
3375 var array = mae;
3376 array = array.concat(exifArray);
3377 array = array.concat(ato);
3378 return array;
3379 }
3380 }, {
3381 key: "slice2Segments",
3382 value: function slice2Segments(rawImageArray) {
3383 var head = 0;
3384 var segments = [];
3385 while (true) {
3386 var length;
3387 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) {
3388 break;
3389 }
3390 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) {
3391 head += 2;
3392 } else {
3393 length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3];
3394 var endPoint = head + length + 2;
3395 var seg = rawImageArray.slice(head, endPoint);
3396 segments.push(seg);
3397 head = endPoint;
3398 }
3399 if (head > rawImageArray.length) {
3400 break;
3401 }
3402 }
3403 return segments;
3404 }
3405 }, {
3406 key: "decode64",
3407 value: function decode64(input) {
3408 var output = '';
3409 var chr1 = undefined;
3410 var chr2 = undefined;
3411 var chr3 = '';
3412 var enc1 = undefined;
3413 var enc2 = undefined;
3414 var enc3 = undefined;
3415 var enc4 = '';
3416 var i = 0;
3417 var buf = [];
3418 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
3419 var base64test = /[^A-Za-z0-9\+\/\=]/g;
3420 if (base64test.exec(input)) {
3421 console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.');
3422 }
3423 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
3424 while (true) {
3425 enc1 = this.KEY_STR.indexOf(input.charAt(i++));
3426 enc2 = this.KEY_STR.indexOf(input.charAt(i++));
3427 enc3 = this.KEY_STR.indexOf(input.charAt(i++));
3428 enc4 = this.KEY_STR.indexOf(input.charAt(i++));
3429 chr1 = enc1 << 2 | enc2 >> 4;
3430 chr2 = (enc2 & 15) << 4 | enc3 >> 2;
3431 chr3 = (enc3 & 3) << 6 | enc4;
3432 buf.push(chr1);
3433 if (enc3 !== 64) {
3434 buf.push(chr2);
3435 }
3436 if (enc4 !== 64) {
3437 buf.push(chr3);
3438 }
3439 chr1 = chr2 = chr3 = '';
3440 enc1 = enc2 = enc3 = enc4 = '';
3441 if (!(i < input.length)) {
3442 break;
3443 }
3444 }
3445 return buf;
3446 }
3447 }]);
3448
3449 return ExifRestore;
3450}();
3451
3452ExifRestore.initClass();
3453
3454/*
3455 * contentloaded.js
3456 *
3457 * Author: Diego Perini (diego.perini at gmail.com)
3458 * Summary: cross-browser wrapper for DOMContentLoaded
3459 * Updated: 20101020
3460 * License: MIT
3461 * Version: 1.2
3462 *
3463 * URL:
3464 * http://javascript.nwbox.com/ContentLoaded/
3465 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
3466 */
3467
3468// @win window reference
3469// @fn function reference
3470var contentLoaded = function contentLoaded(win, fn) {
3471 var done = false;
3472 var top = true;
3473 var doc = win.document;
3474 var root = doc.documentElement;
3475 var add = doc.addEventListener ? "addEventListener" : "attachEvent";
3476 var rem = doc.addEventListener ? "removeEventListener" : "detachEvent";
3477 var pre = doc.addEventListener ? "" : "on";
3478 var init = function init(e) {
3479 if (e.type === "readystatechange" && doc.readyState !== "complete") {
3480 return;
3481 }
3482 (e.type === "load" ? win : doc)[rem](pre + e.type, init, false);
3483 if (!done && (done = true)) {
3484 return fn.call(win, e.type || e);
3485 }
3486 };
3487
3488 var poll = function poll() {
3489 try {
3490 root.doScroll("left");
3491 } catch (e) {
3492 setTimeout(poll, 50);
3493 return;
3494 }
3495 return init("poll");
3496 };
3497
3498 if (doc.readyState !== "complete") {
3499 if (doc.createEventObject && root.doScroll) {
3500 try {
3501 top = !win.frameElement;
3502 } catch (error) {}
3503 if (top) {
3504 poll();
3505 }
3506 }
3507 doc[add](pre + "DOMContentLoaded", init, false);
3508 doc[add](pre + "readystatechange", init, false);
3509 return win[add](pre + "load", init, false);
3510 }
3511};
3512
3513// As a single function to be able to write tests.
3514Dropzone._autoDiscoverFunction = function () {
3515 if (Dropzone.autoDiscover) {
3516 return Dropzone.discover();
3517 }
3518};
3519contentLoaded(window, Dropzone._autoDiscoverFunction);
3520
3521function __guard__(value, transform) {
3522 return typeof value !== 'undefined' && value !== null ? transform(value) : undefined;
3523}
3524function __guardMethod__(obj, methodName, transform) {
3525 if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') {
3526 return transform(obj, methodName);
3527 } else {
3528 return undefined;
3529 }
3530}