PageSourceSearch

https://takismarakakis.com/catalog/view/javascript/codinginspect/dropzone/dist/dropzone.js?v=14218c54

js takismarakakis.com collected 2026-10-06 12:53:20 UTC 121,518 bytes, 3,530 lines download raw bytes

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 olde
436n 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            }
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. Get
936s 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 = true;
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
vendor: 6,814 bytes, lines 3298-3530
3298+/=';
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}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.