1 import {Component} from './component';
2 import {Clipboard} from '../services/clipboard';
4 elem, getLoading, onSelect, removeLoading,
5 } from '../services/dom';
7 export class Dropzone extends Component {
10 this.container = this.$el;
11 this.statusArea = this.$refs.statusArea;
12 this.dropTarget = this.$refs.dropTarget;
13 this.selectButtons = this.$manyRefs.selectButton || [];
15 this.url = this.$opts.url;
16 this.successMessage = this.$opts.successMessage;
17 this.removeMessage = this.$opts.removeMessage;
18 this.uploadLimit = Number(this.$opts.uploadLimit); // TODO - Use
19 this.uploadLimitMessage = this.$opts.uploadLimitMessage; // TODO - Use
20 this.timeoutMessage = this.$opts.timeoutMessage; // TODO - Use
21 this.zoneText = this.$opts.zoneText;
22 // window.uploadTimeout // TODO - Use
24 this.setupListeners();
28 onSelect(this.selectButtons, this.manualSelectHandler.bind(this));
32 this.dropTarget.addEventListener('dragenter', event => {
33 event.preventDefault();
41 this.dropTarget.addEventListener('dragover', event => {
42 event.preventDefault();
50 this.dropTarget.addEventListener('dragend', event => {
54 this.dropTarget.addEventListener('dragleave', event => {
61 this.dropTarget.addEventListener('drop', event => {
62 event.preventDefault();
64 const clipboard = new Clipboard(event.dataTransfer);
65 const files = clipboard.getFiles();
66 for (const file of files) {
67 this.createUploadFromFile(file);
72 manualSelectHandler() {
73 const input = elem('input', {type: 'file', style: 'left: -400px; visibility: hidden; position: fixed;'});
74 this.container.append(input);
76 input.addEventListener('change', event => {
77 for (const file of input.files) {
78 this.createUploadFromFile(file);
85 const overlay = this.dropTarget.querySelector('.dropzone-overlay');
87 const zoneElem = elem('div', {class: 'dropzone-overlay'}, [this.zoneText]);
88 this.dropTarget.append(zoneElem);
93 const overlay = this.dropTarget.querySelector('.dropzone-overlay');
103 createUploadFromFile(file) {
104 const {dom, status, progress, dismiss} = this.createDomForFile(file);
105 this.statusArea.append(dom);
106 const component = this;
111 updateProgress(percentComplete) {
112 progress.textContent = `${percentComplete}%`;
113 progress.style.width = `${percentComplete}%`;
116 status.setAttribute('data-status', 'error');
117 status.textContent = message;
120 markSuccess(message) {
121 status.setAttribute('data-status', 'success');
122 status.textContent = message;
124 setTimeout(dismiss, 2400);
125 component.$emit('upload-success', {
131 this.startXhrForUpload(upload);
137 * @param {Upload} upload
139 startXhrForUpload(upload) {
140 const formData = new FormData();
141 formData.append('file', upload.file, upload.file.name);
143 const req = window.$http.createXMLHttpRequest('POST', this.url, {
145 upload.markError('Upload failed'); // TODO - Update text
148 if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
149 upload.markSuccess('Finished upload!');
150 } else if (this.readyState === XMLHttpRequest.DONE && this.status >= 400) {
151 const content = this.responseText;
152 const data = content.startsWith('{') ? JSON.parse(content) : {message: content};
153 const message = data?.message || content;
154 upload.markError(message);
159 req.upload.addEventListener('progress', evt => {
160 const percent = Math.min(Math.ceil((evt.loaded / evt.total) * 100), 100);
161 upload.updateProgress(percent);
164 req.setRequestHeader('Accept', 'application/json');
170 * @return {{image: Element, dom: Element, progress: Element, status: Element, dismiss: function}}
172 createDomForFile(file) {
173 const image = elem('img', {src: ''});
174 const status = elem('div', {class: 'dropzone-file-item-status'}, []);
175 const progress = elem('div', {class: 'dropzone-file-item-progress'});
176 const imageWrap = elem('div', {class: 'dropzone-file-item-image-wrap'}, [image]);
178 const dom = elem('div', {class: 'dropzone-file-item'}, [
180 elem('div', {class: 'dropzone-file-item-text-wrap'}, [
181 elem('div', {class: 'dropzone-file-item-label'}, [file.name]),
188 if (file.type.startsWith('image/')) {
189 image.src = URL.createObjectURL(file);
192 const dismiss = () => {
193 dom.classList.add('dismiss');
194 dom.addEventListener('animationend', event => {
199 dom.addEventListener('click', dismiss);
202 dom, progress, status, dismiss,
210 * @property {File} file
211 * @property {Element} dom
212 * @property {function(Number)} updateProgress
213 * @property {function(String)} markError
214 * @property {function(String)} markSuccess