4 * More info at [www.dropzonejs.com](http://www.dropzonejs.com)
6 * Copyright (c) 2012, Matias Meno
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 var Dropzone, Emitter, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without,
31 __hasProp = {}.hasOwnProperty,
32 __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
36 Emitter = (function() {
39 Emitter.prototype.addEventListener = Emitter.prototype.on;
41 Emitter.prototype.on = function(event, fn) {
42 this._callbacks = this._callbacks || {};
43 if (!this._callbacks[event]) {
44 this._callbacks[event] = [];
46 this._callbacks[event].push(fn);
50 Emitter.prototype.emit = function() {
51 var args, callback, callbacks, event, _i, _len;
52 event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
53 this._callbacks = this._callbacks || {};
54 callbacks = this._callbacks[event];
56 for (_i = 0, _len = callbacks.length; _i < _len; _i++) {
57 callback = callbacks[_i];
58 callback.apply(this, args);
64 Emitter.prototype.removeListener = Emitter.prototype.off;
66 Emitter.prototype.removeAllListeners = Emitter.prototype.off;
68 Emitter.prototype.removeEventListener = Emitter.prototype.off;
70 Emitter.prototype.off = function(event, fn) {
71 var callback, callbacks, i, _i, _len;
72 if (!this._callbacks || arguments.length === 0) {
76 callbacks = this._callbacks[event];
80 if (arguments.length === 1) {
81 delete this._callbacks[event];
84 for (i = _i = 0, _len = callbacks.length; _i < _len; i = ++_i) {
85 callback = callbacks[i];
86 if (callback === fn) {
87 callbacks.splice(i, 1);
98 Dropzone = (function(_super) {
99 var extend, resolveOption;
101 __extends(Dropzone, _super);
103 Dropzone.prototype.Emitter = Emitter;
107 This is a list of all available events you can register on a dropzone object.
109 You can register an event handler like this:
111 dropzone.on("dragEnter", function() { });
114 Dropzone.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"];
116 Dropzone.prototype.defaultOptions = {
119 withCredentials: false,
121 uploadMultiple: false,
124 createImageThumbnails: true,
125 maxThumbnailFilesize: 10,
127 thumbnailHeight: 120,
132 ignoreHiddenFiles: true,
134 acceptedMimeTypes: null,
135 autoProcessQueue: true,
137 addRemoveLinks: false,
138 previewsContainer: null,
139 hiddenInputContainer: "body",
141 renameFilename: null,
142 dictDefaultMessage: "Drop files here to upload",
143 dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
144 dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
145 dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
146 dictInvalidFileType: "You can't upload files of this type.",
147 dictResponseError: "Server responded with {{statusCode}} code.",
148 dictCancelUpload: "Cancel upload",
149 dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
150 dictRemoveFile: "Remove file",
151 dictRemoveFileConfirmation: null,
152 dictMaxFilesExceeded: "You can not upload any more files.",
153 accept: function(file, done) {
159 forceFallback: false,
160 fallback: function() {
161 var child, messageElement, span, _i, _len, _ref;
162 this.element.className = "" + this.element.className + " dz-browser-not-supported";
163 _ref = this.element.getElementsByTagName("div");
164 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
166 if (/(^| )dz-message($| )/.test(child.className)) {
167 messageElement = child;
168 child.className = "dz-message";
172 if (!messageElement) {
173 messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>");
174 this.element.appendChild(messageElement);
176 span = messageElement.getElementsByTagName("span")[0];
178 if (span.textContent != null) {
179 span.textContent = this.options.dictFallbackMessage;
180 } else if (span.innerText != null) {
181 span.innerText = this.options.dictFallbackMessage;
184 return this.element.appendChild(this.getFallbackForm());
186 resize: function(file) {
187 var info, srcRatio, trgRatio;
191 srcWidth: file.width,
192 srcHeight: file.height
194 srcRatio = file.width / file.height;
195 info.optWidth = this.options.thumbnailWidth;
196 info.optHeight = this.options.thumbnailHeight;
197 if ((info.optWidth == null) && (info.optHeight == null)) {
198 info.optWidth = info.srcWidth;
199 info.optHeight = info.srcHeight;
200 } else if (info.optWidth == null) {
201 info.optWidth = srcRatio * info.optHeight;
202 } else if (info.optHeight == null) {
203 info.optHeight = (1 / srcRatio) * info.optWidth;
205 trgRatio = info.optWidth / info.optHeight;
206 if (file.height < info.optHeight || file.width < info.optWidth) {
207 info.trgHeight = info.srcHeight;
208 info.trgWidth = info.srcWidth;
210 if (srcRatio > trgRatio) {
211 info.srcHeight = file.height;
212 info.srcWidth = info.srcHeight * trgRatio;
214 info.srcWidth = file.width;
215 info.srcHeight = info.srcWidth / trgRatio;
218 info.srcX = (file.width - info.srcWidth) / 2;
219 info.srcY = (file.height - info.srcHeight) / 2;
224 Those functions register themselves to the events on init and handle all
225 the user interface specific stuff. Overwriting them won't break the upload
226 but can break the way it's displayed.
227 You can overwrite them if you don't like the default behavior. If you just
228 want to add an additional event handler, register it on the dropzone object
229 and don't overwrite those options.
232 return this.element.classList.remove("dz-drag-hover");
235 dragend: function(e) {
236 return this.element.classList.remove("dz-drag-hover");
238 dragenter: function(e) {
239 return this.element.classList.add("dz-drag-hover");
241 dragover: function(e) {
242 return this.element.classList.add("dz-drag-hover");
244 dragleave: function(e) {
245 return this.element.classList.remove("dz-drag-hover");
249 return this.element.classList.remove("dz-started");
251 addedfile: function(file) {
252 var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
253 if (this.element === this.previewsContainer) {
254 this.element.classList.add("dz-started");
256 if (this.previewsContainer) {
257 file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());
258 file.previewTemplate = file.previewElement;
259 this.previewsContainer.appendChild(file.previewElement);
260 _ref = file.previewElement.querySelectorAll("[data-dz-name]");
261 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
263 node.textContent = this._renameFilename(file.name);
265 _ref1 = file.previewElement.querySelectorAll("[data-dz-size]");
266 for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
268 node.innerHTML = this.filesize(file.size);
270 if (this.options.addRemoveLinks) {
271 file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>" + this.options.dictRemoveFile + "</a>");
272 file.previewElement.appendChild(file._removeLink);
274 removeFileEvent = (function(_this) {
278 if (file.status === Dropzone.UPLOADING) {
279 return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() {
280 return _this.removeFile(file);
283 if (_this.options.dictRemoveFileConfirmation) {
284 return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() {
285 return _this.removeFile(file);
288 return _this.removeFile(file);
293 _ref2 = file.previewElement.querySelectorAll("[data-dz-remove]");
295 for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
296 removeLink = _ref2[_k];
297 _results.push(removeLink.addEventListener("click", removeFileEvent));
302 removedfile: function(file) {
304 if (file.previewElement) {
305 if ((_ref = file.previewElement) != null) {
306 _ref.parentNode.removeChild(file.previewElement);
309 return this._updateMaxFilesReachedClass();
311 thumbnail: function(file, dataUrl) {
312 var thumbnailElement, _i, _len, _ref;
313 if (file.previewElement) {
314 file.previewElement.classList.remove("dz-file-preview");
315 _ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]");
316 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
317 thumbnailElement = _ref[_i];
318 thumbnailElement.alt = file.name;
319 thumbnailElement.src = dataUrl;
321 return setTimeout(((function(_this) {
323 return file.previewElement.classList.add("dz-image-preview");
328 error: function(file, message) {
329 var node, _i, _len, _ref, _results;
330 if (file.previewElement) {
331 file.previewElement.classList.add("dz-error");
332 if (typeof message !== "String" && message.error) {
333 message = message.error;
335 _ref = file.previewElement.querySelectorAll("[data-dz-errormessage]");
337 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
339 _results.push(node.textContent = message);
345 processing: function(file) {
346 if (file.previewElement) {
347 file.previewElement.classList.add("dz-processing");
348 if (file._removeLink) {
349 return file._removeLink.textContent = this.options.dictCancelUpload;
353 processingmultiple: noop,
354 uploadprogress: function(file, progress, bytesSent) {
355 var node, _i, _len, _ref, _results;
356 if (file.previewElement) {
357 _ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]");
359 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
361 if (node.nodeName === 'PROGRESS') {
362 _results.push(node.value = progress);
364 _results.push(node.style.width = "" + progress + "%");
370 totaluploadprogress: noop,
372 sendingmultiple: noop,
373 success: function(file) {
374 if (file.previewElement) {
375 return file.previewElement.classList.add("dz-success");
378 successmultiple: noop,
379 canceled: function(file) {
380 return this.emit("error", file, "Upload canceled.");
382 canceledmultiple: noop,
383 complete: function(file) {
384 if (file._removeLink) {
385 file._removeLink.textContent = this.options.dictRemoveFile;
387 if (file.previewElement) {
388 return file.previewElement.classList.add("dz-complete");
391 completemultiple: noop,
392 maxfilesexceeded: noop,
393 maxfilesreached: noop,
396 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>"
399 extend = function() {
400 var key, object, objects, target, val, _i, _len;
401 target = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
402 for (_i = 0, _len = objects.length; _i < _len; _i++) {
403 object = objects[_i];
404 for (key in object) {
412 function Dropzone(element, options) {
413 var elementOptions, fallback, _ref;
414 this.element = element;
415 this.version = Dropzone.version;
416 this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, "");
417 this.clickableElements = [];
420 if (typeof this.element === "string") {
421 this.element = document.querySelector(this.element);
423 if (!(this.element && (this.element.nodeType != null))) {
424 throw new Error("Invalid dropzone element.");
426 if (this.element.dropzone) {
427 throw new Error("Dropzone already attached.");
429 Dropzone.instances.push(this);
430 this.element.dropzone = this;
431 elementOptions = (_ref = Dropzone.optionsForElement(this.element)) != null ? _ref : {};
432 this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {});
433 if (this.options.forceFallback || !Dropzone.isBrowserSupported()) {
434 return this.options.fallback.call(this);
436 if (this.options.url == null) {
437 this.options.url = this.element.getAttribute("action");
439 if (!this.options.url) {
440 throw new Error("No URL provided.");
442 if (this.options.acceptedFiles && this.options.acceptedMimeTypes) {
443 throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");
445 if (this.options.acceptedMimeTypes) {
446 this.options.acceptedFiles = this.options.acceptedMimeTypes;
447 delete this.options.acceptedMimeTypes;
449 this.options.method = this.options.method.toUpperCase();
450 if ((fallback = this.getExistingFallback()) && fallback.parentNode) {
451 fallback.parentNode.removeChild(fallback);
453 if (this.options.previewsContainer !== false) {
454 if (this.options.previewsContainer) {
455 this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer");
457 this.previewsContainer = this.element;
460 if (this.options.clickable) {
461 if (this.options.clickable === true) {
462 this.clickableElements = [this.element];
464 this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable");
470 Dropzone.prototype.getAcceptedFiles = function() {
471 var file, _i, _len, _ref, _results;
474 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
483 Dropzone.prototype.getRejectedFiles = function() {
484 var file, _i, _len, _ref, _results;
487 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
489 if (!file.accepted) {
496 Dropzone.prototype.getFilesWithStatus = function(status) {
497 var file, _i, _len, _ref, _results;
500 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
502 if (file.status === status) {
509 Dropzone.prototype.getQueuedFiles = function() {
510 return this.getFilesWithStatus(Dropzone.QUEUED);
513 Dropzone.prototype.getUploadingFiles = function() {
514 return this.getFilesWithStatus(Dropzone.UPLOADING);
517 Dropzone.prototype.getAddedFiles = function() {
518 return this.getFilesWithStatus(Dropzone.ADDED);
521 Dropzone.prototype.getActiveFiles = function() {
522 var file, _i, _len, _ref, _results;
525 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
527 if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) {
534 Dropzone.prototype.init = function() {
535 var eventName, noPropagation, setupHiddenFileInput, _i, _len, _ref, _ref1;
536 if (this.element.tagName === "form") {
537 this.element.setAttribute("enctype", "multipart/form-data");
539 if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) {
540 this.element.appendChild(Dropzone.createElement("<div class=\"dz-default dz-message\"><span>" + this.options.dictDefaultMessage + "</span></div>"));
542 if (this.clickableElements.length) {
543 setupHiddenFileInput = (function(_this) {
545 if (_this.hiddenFileInput) {
546 _this.hiddenFileInput.parentNode.removeChild(_this.hiddenFileInput);
548 _this.hiddenFileInput = document.createElement("input");
549 _this.hiddenFileInput.setAttribute("type", "file");
550 if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) {
551 _this.hiddenFileInput.setAttribute("multiple", "multiple");
553 _this.hiddenFileInput.className = "dz-hidden-input";
554 if (_this.options.acceptedFiles != null) {
555 _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles);
557 if (_this.options.capture != null) {
558 _this.hiddenFileInput.setAttribute("capture", _this.options.capture);
560 _this.hiddenFileInput.style.visibility = "hidden";
561 _this.hiddenFileInput.style.position = "absolute";
562 _this.hiddenFileInput.style.top = "0";
563 _this.hiddenFileInput.style.left = "0";
564 _this.hiddenFileInput.style.height = "0";
565 _this.hiddenFileInput.style.width = "0";
566 document.querySelector(_this.options.hiddenInputContainer).appendChild(_this.hiddenFileInput);
567 return _this.hiddenFileInput.addEventListener("change", function() {
568 var file, files, _i, _len;
569 files = _this.hiddenFileInput.files;
571 for (_i = 0, _len = files.length; _i < _len; _i++) {
576 _this.emit("addedfiles", files);
577 return setupHiddenFileInput();
581 setupHiddenFileInput();
583 this.URL = (_ref = window.URL) != null ? _ref : window.webkitURL;
585 for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
586 eventName = _ref1[_i];
587 this.on(eventName, this.options[eventName]);
589 this.on("uploadprogress", (function(_this) {
591 return _this.updateTotalUploadProgress();
594 this.on("removedfile", (function(_this) {
596 return _this.updateTotalUploadProgress();
599 this.on("canceled", (function(_this) {
600 return function(file) {
601 return _this.emit("complete", file);
604 this.on("complete", (function(_this) {
605 return function(file) {
606 if (_this.getAddedFiles().length === 0 && _this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) {
607 return setTimeout((function() {
608 return _this.emit("queuecomplete");
613 noPropagation = function(e) {
615 if (e.preventDefault) {
616 return e.preventDefault();
618 return e.returnValue = false;
623 element: this.element,
625 "dragstart": (function(_this) {
627 return _this.emit("dragstart", e);
630 "dragenter": (function(_this) {
633 return _this.emit("dragenter", e);
636 "dragover": (function(_this) {
640 efct = e.dataTransfer.effectAllowed;
642 e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';
644 return _this.emit("dragover", e);
647 "dragleave": (function(_this) {
649 return _this.emit("dragleave", e);
652 "drop": (function(_this) {
655 return _this.drop(e);
658 "dragend": (function(_this) {
660 return _this.emit("dragend", e);
666 this.clickableElements.forEach((function(_this) {
667 return function(clickableElement) {
668 return _this.listeners.push({
669 element: clickableElement,
671 "click": function(evt) {
672 if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) {
673 _this.hiddenFileInput.click();
682 return this.options.init.call(this);
685 Dropzone.prototype.destroy = function() {
688 this.removeAllFiles(true);
689 if ((_ref = this.hiddenFileInput) != null ? _ref.parentNode : void 0) {
690 this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);
691 this.hiddenFileInput = null;
693 delete this.element.dropzone;
694 return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1);
697 Dropzone.prototype.updateTotalUploadProgress = function() {
698 var activeFiles, file, totalBytes, totalBytesSent, totalUploadProgress, _i, _len, _ref;
701 activeFiles = this.getActiveFiles();
702 if (activeFiles.length) {
703 _ref = this.getActiveFiles();
704 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
706 totalBytesSent += file.upload.bytesSent;
707 totalBytes += file.upload.total;
709 totalUploadProgress = 100 * totalBytesSent / totalBytes;
711 totalUploadProgress = 100;
713 return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent);
716 Dropzone.prototype._getParamName = function(n) {
717 if (typeof this.options.paramName === "function") {
718 return this.options.paramName(n);
720 return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : "");
724 Dropzone.prototype._renameFilename = function(name) {
725 if (typeof this.options.renameFilename !== "function") {
728 return this.options.renameFilename(name);
731 Dropzone.prototype.getFallbackForm = function() {
732 var existingFallback, fields, fieldsString, form;
733 if (existingFallback = this.getExistingFallback()) {
734 return existingFallback;
736 fieldsString = "<div class=\"dz-fallback\">";
737 if (this.options.dictFallbackText) {
738 fieldsString += "<p>" + this.options.dictFallbackText + "</p>";
740 fieldsString += "<input type=\"file\" name=\"" + (this._getParamName(0)) + "\" " + (this.options.uploadMultiple ? 'multiple="multiple"' : void 0) + " /><input type=\"submit\" value=\"Upload!\"></div>";
741 fields = Dropzone.createElement(fieldsString);
742 if (this.element.tagName !== "FORM") {
743 form = Dropzone.createElement("<form action=\"" + this.options.url + "\" enctype=\"multipart/form-data\" method=\"" + this.options.method + "\"></form>");
744 form.appendChild(fields);
746 this.element.setAttribute("enctype", "multipart/form-data");
747 this.element.setAttribute("method", this.options.method);
749 return form != null ? form : fields;
752 Dropzone.prototype.getExistingFallback = function() {
753 var fallback, getFallback, tagName, _i, _len, _ref;
754 getFallback = function(elements) {
756 for (_i = 0, _len = elements.length; _i < _len; _i++) {
758 if (/(^| )fallback($| )/.test(el.className)) {
763 _ref = ["div", "form"];
764 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
766 if (fallback = getFallback(this.element.getElementsByTagName(tagName))) {
772 Dropzone.prototype.setupEventListeners = function() {
773 var elementListeners, event, listener, _i, _len, _ref, _results;
774 _ref = this.listeners;
776 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
777 elementListeners = _ref[_i];
778 _results.push((function() {
779 var _ref1, _results1;
780 _ref1 = elementListeners.events;
782 for (event in _ref1) {
783 listener = _ref1[event];
784 _results1.push(elementListeners.element.addEventListener(event, listener, false));
792 Dropzone.prototype.removeEventListeners = function() {
793 var elementListeners, event, listener, _i, _len, _ref, _results;
794 _ref = this.listeners;
796 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
797 elementListeners = _ref[_i];
798 _results.push((function() {
799 var _ref1, _results1;
800 _ref1 = elementListeners.events;
802 for (event in _ref1) {
803 listener = _ref1[event];
804 _results1.push(elementListeners.element.removeEventListener(event, listener, false));
812 Dropzone.prototype.disable = function() {
813 var file, _i, _len, _ref, _results;
814 this.clickableElements.forEach(function(element) {
815 return element.classList.remove("dz-clickable");
817 this.removeEventListeners();
820 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
822 _results.push(this.cancelUpload(file));
827 Dropzone.prototype.enable = function() {
828 this.clickableElements.forEach(function(element) {
829 return element.classList.add("dz-clickable");
831 return this.setupEventListeners();
834 Dropzone.prototype.filesize = function(size) {
835 var cutoff, i, selectedSize, selectedUnit, unit, units, _i, _len;
839 units = ['TB', 'GB', 'MB', 'KB', 'b'];
840 for (i = _i = 0, _len = units.length; _i < _len; i = ++_i) {
842 cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10;
843 if (size >= cutoff) {
844 selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i);
849 selectedSize = Math.round(10 * selectedSize) / 10;
851 return "<strong>" + selectedSize + "</strong> " + selectedUnit;
854 Dropzone.prototype._updateMaxFilesReachedClass = function() {
855 if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) {
856 if (this.getAcceptedFiles().length === this.options.maxFiles) {
857 this.emit('maxfilesreached', this.files);
859 return this.element.classList.add("dz-max-files-reached");
861 return this.element.classList.remove("dz-max-files-reached");
865 Dropzone.prototype.drop = function(e) {
867 if (!e.dataTransfer) {
870 this.emit("drop", e);
871 files = e.dataTransfer.files;
872 this.emit("addedfiles", files);
874 items = e.dataTransfer.items;
875 if (items && items.length && (items[0].webkitGetAsEntry != null)) {
876 this._addFilesFromItems(items);
878 this.handleFiles(files);
883 Dropzone.prototype.paste = function(e) {
885 if ((e != null ? (_ref = e.clipboardData) != null ? _ref.items : void 0 : void 0) == null) {
888 this.emit("paste", e);
889 items = e.clipboardData.items;
891 return this._addFilesFromItems(items);
895 Dropzone.prototype.handleFiles = function(files) {
896 var file, _i, _len, _results;
898 for (_i = 0, _len = files.length; _i < _len; _i++) {
900 _results.push(this.addFile(file));
905 Dropzone.prototype._addFilesFromItems = function(items) {
906 var entry, item, _i, _len, _results;
908 for (_i = 0, _len = items.length; _i < _len; _i++) {
910 if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) {
912 _results.push(this.addFile(item.getAsFile()));
913 } else if (entry.isDirectory) {
914 _results.push(this._addFilesFromDirectory(entry, entry.name));
916 _results.push(void 0);
918 } else if (item.getAsFile != null) {
919 if ((item.kind == null) || item.kind === "file") {
920 _results.push(this.addFile(item.getAsFile()));
922 _results.push(void 0);
925 _results.push(void 0);
931 Dropzone.prototype._addFilesFromDirectory = function(directory, path) {
932 var dirReader, errorHandler, readEntries;
933 dirReader = directory.createReader();
934 errorHandler = function(error) {
935 return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(error) : void 0 : void 0;
937 readEntries = (function(_this) {
939 return dirReader.readEntries(function(entries) {
941 if (entries.length > 0) {
942 for (_i = 0, _len = entries.length; _i < _len; _i++) {
945 entry.file(function(file) {
946 if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') {
949 file.fullPath = "" + path + "/" + file.name;
950 return _this.addFile(file);
952 } else if (entry.isDirectory) {
953 _this._addFilesFromDirectory(entry, "" + path + "/" + entry.name);
962 return readEntries();
965 Dropzone.prototype.accept = function(file, done) {
966 if (file.size > this.options.maxFilesize * 1024 * 1024) {
967 return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize));
968 } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) {
969 return done(this.options.dictInvalidFileType);
970 } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) {
971 done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles));
972 return this.emit("maxfilesexceeded", file);
974 return this.options.accept.call(this, file, done);
978 Dropzone.prototype.addFile = function(file) {
984 this.files.push(file);
985 file.status = Dropzone.ADDED;
986 this.emit("addedfile", file);
987 this._enqueueThumbnail(file);
988 return this.accept(file, (function(_this) {
989 return function(error) {
991 file.accepted = false;
992 _this._errorProcessing([file], error);
994 file.accepted = true;
995 if (_this.options.autoQueue) {
996 _this.enqueueFile(file);
999 return _this._updateMaxFilesReachedClass();
1004 Dropzone.prototype.enqueueFiles = function(files) {
1006 for (_i = 0, _len = files.length; _i < _len; _i++) {
1008 this.enqueueFile(file);
1013 Dropzone.prototype.enqueueFile = function(file) {
1014 if (file.status === Dropzone.ADDED && file.accepted === true) {
1015 file.status = Dropzone.QUEUED;
1016 if (this.options.autoProcessQueue) {
1017 return setTimeout(((function(_this) {
1019 return _this.processQueue();
1024 throw new Error("This file can't be queued because it has already been processed or was rejected.");
1028 Dropzone.prototype._thumbnailQueue = [];
1030 Dropzone.prototype._processingThumbnail = false;
1032 Dropzone.prototype._enqueueThumbnail = function(file) {
1033 if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) {
1034 this._thumbnailQueue.push(file);
1035 return setTimeout(((function(_this) {
1037 return _this._processThumbnailQueue();
1043 Dropzone.prototype._processThumbnailQueue = function() {
1044 if (this._processingThumbnail || this._thumbnailQueue.length === 0) {
1047 this._processingThumbnail = true;
1048 return this.createThumbnail(this._thumbnailQueue.shift(), (function(_this) {
1050 _this._processingThumbnail = false;
1051 return _this._processThumbnailQueue();
1056 Dropzone.prototype.removeFile = function(file) {
1057 if (file.status === Dropzone.UPLOADING) {
1058 this.cancelUpload(file);
1060 this.files = without(this.files, file);
1061 this.emit("removedfile", file);
1062 if (this.files.length === 0) {
1063 return this.emit("reset");
1067 Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) {
1068 var file, _i, _len, _ref;
1069 if (cancelIfNecessary == null) {
1070 cancelIfNecessary = false;
1072 _ref = this.files.slice();
1073 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1075 if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) {
1076 this.removeFile(file);
1082 Dropzone.prototype.createThumbnail = function(file, callback) {
1084 fileReader = new FileReader;
1085 fileReader.onload = (function(_this) {
1087 if (file.type === "image/svg+xml") {
1088 _this.emit("thumbnail", file, fileReader.result);
1089 if (callback != null) {
1094 return _this.createThumbnailFromUrl(file, fileReader.result, callback);
1097 return fileReader.readAsDataURL(file);
1100 Dropzone.prototype.createThumbnailFromUrl = function(file, imageUrl, callback, crossOrigin) {
1102 img = document.createElement("img");
1104 img.crossOrigin = crossOrigin;
1106 img.onload = (function(_this) {
1108 var canvas, ctx, resizeInfo, thumbnail, _ref, _ref1, _ref2, _ref3;
1109 file.width = img.width;
1110 file.height = img.height;
1111 resizeInfo = _this.options.resize.call(_this, file);
1112 if (resizeInfo.trgWidth == null) {
1113 resizeInfo.trgWidth = resizeInfo.optWidth;
1115 if (resizeInfo.trgHeight == null) {
1116 resizeInfo.trgHeight = resizeInfo.optHeight;
1118 canvas = document.createElement("canvas");
1119 ctx = canvas.getContext("2d");
1120 canvas.width = resizeInfo.trgWidth;
1121 canvas.height = resizeInfo.trgHeight;
1122 drawImageIOSFix(ctx, img, (_ref = resizeInfo.srcX) != null ? _ref : 0, (_ref1 = resizeInfo.srcY) != null ? _ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (_ref2 = resizeInfo.trgX) != null ? _ref2 : 0, (_ref3 = resizeInfo.trgY) != null ? _ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight);
1123 thumbnail = canvas.toDataURL("image/png");
1124 _this.emit("thumbnail", file, thumbnail);
1125 if (callback != null) {
1130 if (callback != null) {
1131 img.onerror = callback;
1133 return img.src = imageUrl;
1136 Dropzone.prototype.processQueue = function() {
1137 var i, parallelUploads, processingLength, queuedFiles;
1138 parallelUploads = this.options.parallelUploads;
1139 processingLength = this.getUploadingFiles().length;
1140 i = processingLength;
1141 if (processingLength >= parallelUploads) {
1144 queuedFiles = this.getQueuedFiles();
1145 if (!(queuedFiles.length > 0)) {
1148 if (this.options.uploadMultiple) {
1149 return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength));
1151 while (i < parallelUploads) {
1152 if (!queuedFiles.length) {
1155 this.processFile(queuedFiles.shift());
1161 Dropzone.prototype.processFile = function(file) {
1162 return this.processFiles([file]);
1165 Dropzone.prototype.processFiles = function(files) {
1167 for (_i = 0, _len = files.length; _i < _len; _i++) {
1169 file.processing = true;
1170 file.status = Dropzone.UPLOADING;
1171 this.emit("processing", file);
1173 if (this.options.uploadMultiple) {
1174 this.emit("processingmultiple", files);
1176 return this.uploadFiles(files);
1179 Dropzone.prototype._getFilesWithXhr = function(xhr) {
1181 return files = (function() {
1182 var _i, _len, _ref, _results;
1185 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1187 if (file.xhr === xhr) {
1188 _results.push(file);
1195 Dropzone.prototype.cancelUpload = function(file) {
1196 var groupedFile, groupedFiles, _i, _j, _len, _len1, _ref;
1197 if (file.status === Dropzone.UPLOADING) {
1198 groupedFiles = this._getFilesWithXhr(file.xhr);
1199 for (_i = 0, _len = groupedFiles.length; _i < _len; _i++) {
1200 groupedFile = groupedFiles[_i];
1201 groupedFile.status = Dropzone.CANCELED;
1204 for (_j = 0, _len1 = groupedFiles.length; _j < _len1; _j++) {
1205 groupedFile = groupedFiles[_j];
1206 this.emit("canceled", groupedFile);
1208 if (this.options.uploadMultiple) {
1209 this.emit("canceledmultiple", groupedFiles);
1211 } else if ((_ref = file.status) === Dropzone.ADDED || _ref === Dropzone.QUEUED) {
1212 file.status = Dropzone.CANCELED;
1213 this.emit("canceled", file);
1214 if (this.options.uploadMultiple) {
1215 this.emit("canceledmultiple", [file]);
1218 if (this.options.autoProcessQueue) {
1219 return this.processQueue();
1223 resolveOption = function() {
1225 option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
1226 if (typeof option === 'function') {
1227 return option.apply(this, args);
1232 Dropzone.prototype.uploadFile = function(file) {
1233 return this.uploadFiles([file]);
1236 Dropzone.prototype.uploadFiles = function(files) {
1237 var file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, key, method, option, progressObj, response, updateProgress, url, value, xhr, _i, _j, _k, _l, _len, _len1, _len2, _len3, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
1238 xhr = new XMLHttpRequest();
1239 for (_i = 0, _len = files.length; _i < _len; _i++) {
1243 method = resolveOption(this.options.method, files);
1244 url = resolveOption(this.options.url, files);
1245 xhr.open(method, url, true);
1246 xhr.withCredentials = !!this.options.withCredentials;
1248 handleError = (function(_this) {
1250 var _j, _len1, _results;
1252 for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
1254 _results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr));
1259 updateProgress = (function(_this) {
1260 return function(e) {
1261 var allFilesFinished, progress, _j, _k, _l, _len1, _len2, _len3, _results;
1263 progress = 100 * e.loaded / e.total;
1264 for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
1273 allFilesFinished = true;
1275 for (_k = 0, _len2 = files.length; _k < _len2; _k++) {
1277 if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) {
1278 allFilesFinished = false;
1280 file.upload.progress = progress;
1281 file.upload.bytesSent = file.upload.total;
1283 if (allFilesFinished) {
1288 for (_l = 0, _len3 = files.length; _l < _len3; _l++) {
1290 _results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent));
1295 xhr.onload = (function(_this) {
1296 return function(e) {
1298 if (files[0].status === Dropzone.CANCELED) {
1301 if (xhr.readyState !== 4) {
1304 response = xhr.responseText;
1305 if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) {
1307 response = JSON.parse(response);
1310 response = "Invalid JSON response from server.";
1314 if (!((200 <= (_ref = xhr.status) && _ref < 300))) {
1315 return handleError();
1317 return _this._finished(files, response, e);
1321 xhr.onerror = (function(_this) {
1323 if (files[0].status === Dropzone.CANCELED) {
1326 return handleError();
1329 progressObj = (_ref = xhr.upload) != null ? _ref : xhr;
1330 progressObj.onprogress = updateProgress;
1332 "Accept": "application/json",
1333 "Cache-Control": "no-cache",
1334 "X-Requested-With": "XMLHttpRequest"
1336 if (this.options.headers) {
1337 extend(headers, this.options.headers);
1339 for (headerName in headers) {
1340 headerValue = headers[headerName];
1342 xhr.setRequestHeader(headerName, headerValue);
1345 formData = new FormData();
1346 if (this.options.params) {
1347 _ref1 = this.options.params;
1348 for (key in _ref1) {
1350 formData.append(key, value);
1353 for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
1355 this.emit("sending", file, xhr, formData);
1357 if (this.options.uploadMultiple) {
1358 this.emit("sendingmultiple", files, xhr, formData);
1360 if (this.element.tagName === "FORM") {
1361 _ref2 = this.element.querySelectorAll("input, textarea, select, button");
1362 for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
1364 inputName = input.getAttribute("name");
1365 inputType = input.getAttribute("type");
1366 if (input.tagName === "SELECT" && input.hasAttribute("multiple")) {
1367 _ref3 = input.options;
1368 for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
1370 if (option.selected) {
1371 formData.append(inputName, option.value);
1374 } else if (!inputType || ((_ref4 = inputType.toLowerCase()) !== "checkbox" && _ref4 !== "radio") || input.checked) {
1375 formData.append(inputName, input.value);
1379 for (i = _m = 0, _ref5 = files.length - 1; 0 <= _ref5 ? _m <= _ref5 : _m >= _ref5; i = 0 <= _ref5 ? ++_m : --_m) {
1380 formData.append(this._getParamName(i), files[i], this._renameFilename(files[i].name));
1382 return this.submitRequest(xhr, formData, files);
1385 Dropzone.prototype.submitRequest = function(xhr, formData, files) {
1386 return xhr.send(formData);
1389 Dropzone.prototype._finished = function(files, responseText, e) {
1391 for (_i = 0, _len = files.length; _i < _len; _i++) {
1393 file.status = Dropzone.SUCCESS;
1394 this.emit("success", file, responseText, e);
1395 this.emit("complete", file);
1397 if (this.options.uploadMultiple) {
1398 this.emit("successmultiple", files, responseText, e);
1399 this.emit("completemultiple", files);
1401 if (this.options.autoProcessQueue) {
1402 return this.processQueue();
1406 Dropzone.prototype._errorProcessing = function(files, message, xhr) {
1408 for (_i = 0, _len = files.length; _i < _len; _i++) {
1410 file.status = Dropzone.ERROR;
1411 this.emit("error", file, message, xhr);
1412 this.emit("complete", file);
1414 if (this.options.uploadMultiple) {
1415 this.emit("errormultiple", files, message, xhr);
1416 this.emit("completemultiple", files);
1418 if (this.options.autoProcessQueue) {
1419 return this.processQueue();
1427 Dropzone.version = "4.3.0";
1429 Dropzone.options = {};
1431 Dropzone.optionsForElement = function(element) {
1432 if (element.getAttribute("id")) {
1433 return Dropzone.options[camelize(element.getAttribute("id"))];
1439 Dropzone.instances = [];
1441 Dropzone.forElement = function(element) {
1442 if (typeof element === "string") {
1443 element = document.querySelector(element);
1445 if ((element != null ? element.dropzone : void 0) == null) {
1446 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.");
1448 return element.dropzone;
1451 Dropzone.autoDiscover = true;
1453 Dropzone.discover = function() {
1454 var checkElements, dropzone, dropzones, _i, _len, _results;
1455 if (document.querySelectorAll) {
1456 dropzones = document.querySelectorAll(".dropzone");
1459 checkElements = function(elements) {
1460 var el, _i, _len, _results;
1462 for (_i = 0, _len = elements.length; _i < _len; _i++) {
1464 if (/(^| )dropzone($| )/.test(el.className)) {
1465 _results.push(dropzones.push(el));
1467 _results.push(void 0);
1472 checkElements(document.getElementsByTagName("div"));
1473 checkElements(document.getElementsByTagName("form"));
1476 for (_i = 0, _len = dropzones.length; _i < _len; _i++) {
1477 dropzone = dropzones[_i];
1478 if (Dropzone.optionsForElement(dropzone) !== false) {
1479 _results.push(new Dropzone(dropzone));
1481 _results.push(void 0);
1487 Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i];
1489 Dropzone.isBrowserSupported = function() {
1490 var capableBrowser, regex, _i, _len, _ref;
1491 capableBrowser = true;
1492 if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) {
1493 if (!("classList" in document.createElement("a"))) {
1494 capableBrowser = false;
1496 _ref = Dropzone.blacklistedBrowsers;
1497 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1499 if (regex.test(navigator.userAgent)) {
1500 capableBrowser = false;
1506 capableBrowser = false;
1508 return capableBrowser;
1511 without = function(list, rejectedItem) {
1512 var item, _i, _len, _results;
1514 for (_i = 0, _len = list.length; _i < _len; _i++) {
1516 if (item !== rejectedItem) {
1517 _results.push(item);
1523 camelize = function(str) {
1524 return str.replace(/[\-_](\w)/g, function(match) {
1525 return match.charAt(1).toUpperCase();
1529 Dropzone.createElement = function(string) {
1531 div = document.createElement("div");
1532 div.innerHTML = string;
1533 return div.childNodes[0];
1536 Dropzone.elementInside = function(element, container) {
1537 if (element === container) {
1540 while (element = element.parentNode) {
1541 if (element === container) {
1548 Dropzone.getElement = function(el, name) {
1550 if (typeof el === "string") {
1551 element = document.querySelector(el);
1552 } else if (el.nodeType != null) {
1555 if (element == null) {
1556 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element.");
1561 Dropzone.getElements = function(els, name) {
1562 var e, el, elements, _i, _j, _len, _len1, _ref;
1563 if (els instanceof Array) {
1566 for (_i = 0, _len = els.length; _i < _len; _i++) {
1568 elements.push(this.getElement(el, name));
1574 } else if (typeof els === "string") {
1576 _ref = document.querySelectorAll(els);
1577 for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
1581 } else if (els.nodeType != null) {
1584 if (!((elements != null) && elements.length)) {
1585 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");
1590 Dropzone.confirm = function(question, accepted, rejected) {
1591 if (window.confirm(question)) {
1593 } else if (rejected != null) {
1598 Dropzone.isValidFile = function(file, acceptedFiles) {
1599 var baseMimeType, mimeType, validType, _i, _len;
1600 if (!acceptedFiles) {
1603 acceptedFiles = acceptedFiles.split(",");
1604 mimeType = file.type;
1605 baseMimeType = mimeType.replace(/\/.*$/, "");
1606 for (_i = 0, _len = acceptedFiles.length; _i < _len; _i++) {
1607 validType = acceptedFiles[_i];
1608 validType = validType.trim();
1609 if (validType.charAt(0) === ".") {
1610 if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) {
1613 } else if (/\/\*$/.test(validType)) {
1614 if (baseMimeType === validType.replace(/\/.*$/, "")) {
1618 if (mimeType === validType) {
1626 if (typeof jQuery !== "undefined" && jQuery !== null) {
1627 jQuery.fn.dropzone = function(options) {
1628 return this.each(function() {
1629 return new Dropzone(this, options);
1634 if (typeof module !== "undefined" && module !== null) {
1635 module.exports = Dropzone;
1637 window.Dropzone = Dropzone;
1640 Dropzone.ADDED = "added";
1642 Dropzone.QUEUED = "queued";
1644 Dropzone.ACCEPTED = Dropzone.QUEUED;
1646 Dropzone.UPLOADING = "uploading";
1648 Dropzone.PROCESSING = Dropzone.UPLOADING;
1650 Dropzone.CANCELED = "canceled";
1652 Dropzone.ERROR = "error";
1654 Dropzone.SUCCESS = "success";
1659 Bugfix for iOS 6 and 7
1660 Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios
1661 based on the work of https://github.com/stomita/ios-imagefile-megapixel
1664 detectVerticalSquash = function(img) {
1665 var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy;
1666 iw = img.naturalWidth;
1667 ih = img.naturalHeight;
1668 canvas = document.createElement("canvas");
1671 ctx = canvas.getContext("2d");
1672 ctx.drawImage(img, 0, 0);
1673 data = ctx.getImageData(0, 0, 1, ih).data;
1678 alpha = data[(py - 1) * 4 + 3];
1684 py = (ey + sy) >> 1;
1694 drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {
1695 var vertSquashRatio;
1696 vertSquashRatio = detectVerticalSquash(img);
1697 return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
1704 * Author: Diego Perini (diego.perini at gmail.com)
1705 * Summary: cross-browser wrapper for DOMContentLoaded
1711 * http://javascript.nwbox.com/ContentLoaded/
1712 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
1715 contentLoaded = function(win, fn) {
1716 var add, doc, done, init, poll, pre, rem, root, top;
1720 root = doc.documentElement;
1721 add = (doc.addEventListener ? "addEventListener" : "attachEvent");
1722 rem = (doc.addEventListener ? "removeEventListener" : "detachEvent");
1723 pre = (doc.addEventListener ? "" : "on");
1724 init = function(e) {
1725 if (e.type === "readystatechange" && doc.readyState !== "complete") {
1728 (e.type === "load" ? win : doc)[rem](pre + e.type, init, false);
1729 if (!done && (done = true)) {
1730 return fn.call(win, e.type || e);
1736 root.doScroll("left");
1739 setTimeout(poll, 50);
1742 return init("poll");
1744 if (doc.readyState !== "complete") {
1745 if (doc.createEventObject && root.doScroll) {
1747 top = !win.frameElement;
1753 doc[add](pre + "DOMContentLoaded", init, false);
1754 doc[add](pre + "readystatechange", init, false);
1755 return win[add](pre + "load", init, false);
1759 Dropzone._autoDiscoverFunction = function() {
1760 if (Dropzone.autoDiscover) {
1761 return Dropzone.discover();
1765 contentLoaded(window, Dropzone._autoDiscoverFunction);