140 lines
4.3 KiB
JavaScript
140 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
const events = require('../events.js');
|
|
const views = require('../util/views.js');
|
|
|
|
const template = views.getTemplate('file-dropper');
|
|
|
|
const KEY_RETURN = 13;
|
|
|
|
class FileDropperControl extends events.EventTarget {
|
|
constructor(target, options) {
|
|
super();
|
|
|
|
this._options = options;
|
|
const source = template({
|
|
extraText: options.extraText,
|
|
allowMultiple: options.allowMultiple,
|
|
allowUrls: options.allowUrls,
|
|
lock: options.lock,
|
|
id: 'file-' + Math.random().toString(36).substring(7),
|
|
urlPlaceholder:
|
|
options.urlPlaceholder || 'Alternatively, paste an URL here.',
|
|
});
|
|
|
|
this._dropperNode = source.querySelector('.file-dropper');
|
|
this._urlInputNode = source.querySelector('input[type=text]');
|
|
this._urlConfirmButtonNode = source.querySelector('button');
|
|
this._fileInputNode = source.querySelector('input[type=file]');
|
|
this._fileInputNode.style.display = 'none';
|
|
this._fileInputNode.multiple = options.allowMultiple || false;
|
|
|
|
this._counter = 0;
|
|
this._dropperNode.addEventListener(
|
|
'dragenter', e => this._evtDragEnter(e));
|
|
this._dropperNode.addEventListener(
|
|
'dragleave', e => this._evtDragLeave(e));
|
|
this._dropperNode.addEventListener(
|
|
'dragover', e => this._evtDragOver(e));
|
|
this._dropperNode.addEventListener(
|
|
'drop', e => this._evtDrop(e));
|
|
this._fileInputNode.addEventListener(
|
|
'change', e => this._evtFileChange(e));
|
|
|
|
if (this._urlInputNode) {
|
|
this._urlInputNode.addEventListener(
|
|
'keydown', e => this._evtUrlInputKeyDown(e));
|
|
}
|
|
if (this._urlConfirmButtonNode) {
|
|
this._urlConfirmButtonNode.addEventListener(
|
|
'click', e => this._evtUrlConfirmButtonClick(e));
|
|
}
|
|
|
|
this._originalHtml = this._dropperNode.innerHTML;
|
|
views.replaceContent(target, source);
|
|
}
|
|
|
|
reset() {
|
|
this._dropperNode.innerHTML = this._originalHtml;
|
|
this.dispatchEvent(new CustomEvent('reset'));
|
|
}
|
|
|
|
_emitFiles(files) {
|
|
files = Array.from(files);
|
|
if (this._options.lock) {
|
|
this._dropperNode.innerText =
|
|
files.map(file => file.name).join(', ');
|
|
}
|
|
this.dispatchEvent(
|
|
new CustomEvent('fileadd', {detail: {files: files}}));
|
|
}
|
|
|
|
_emitUrls(urls) {
|
|
urls = Array.from(urls).map(url => url.trim());
|
|
if (this._options.lock) {
|
|
this._dropperNode.innerText =
|
|
urls.map(url => url.split(/\//).reverse()[0]).join(', ');
|
|
}
|
|
for (let url of urls) {
|
|
if (!url) {
|
|
return;
|
|
}
|
|
if (!url.match(/^https?:\/\/[^.]+\..+$/)) {
|
|
window.alert(`"${url}" does not look like a valid URL.`);
|
|
return;
|
|
}
|
|
}
|
|
this.dispatchEvent(new CustomEvent('urladd', {detail: {urls: urls}}));
|
|
}
|
|
|
|
_evtDragEnter(e) {
|
|
this._dropperNode.classList.add('active');
|
|
this._counter++;
|
|
}
|
|
|
|
_evtDragLeave(e) {
|
|
this._counter--;
|
|
if (this._counter === 0) {
|
|
this._dropperNode.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
_evtDragOver(e) {
|
|
e.preventDefault();
|
|
}
|
|
|
|
_evtFileChange(e) {
|
|
this._emitFiles(e.target.files);
|
|
}
|
|
|
|
_evtDrop(e) {
|
|
e.preventDefault();
|
|
this._dropperNode.classList.remove('active');
|
|
if (!e.dataTransfer.files.length) {
|
|
window.alert('Only files are supported.');
|
|
}
|
|
if (!this._options.allowMultiple && e.dataTransfer.files.length > 1) {
|
|
window.alert('Cannot select multiple files.');
|
|
}
|
|
this._emitFiles(e.dataTransfer.files);
|
|
}
|
|
|
|
_evtUrlInputKeyDown(e) {
|
|
if (e.which !== KEY_RETURN) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
this._dropperNode.classList.remove('active');
|
|
this._emitUrls(this._urlInputNode.value.split(/[\r\n]/));
|
|
this._urlInputNode.value = '';
|
|
}
|
|
|
|
_evtUrlConfirmButtonClick(e) {
|
|
e.preventDefault();
|
|
this._dropperNode.classList.remove('active');
|
|
this._emitUrls(this._urlInputNode.value.split(/[\r\n]/));
|
|
this._urlInputNode.value = '';
|
|
}
|
|
}
|
|
|
|
module.exports = FileDropperControl;
|