import {define, vlElement} from '/node_modules/vl-ui-core/dist/vl-core.js';
import {vlFormValidation, vlFormValidationElement} from '/node_modules/vl-ui-form-validation/dist/vl-form-validation-all.js';
import '/lib/upload.js';
Promise.all([
vlFormValidation.ready(),
]).then(() => define('vl-upload', VlUpload));
/**
* VlUpload
* @class
* @classdesc Gebruik de upload component om één of meerdere bestanden te selecteren of te slepen naar het upload veld. De gebruiker kan alternatief
* ook één of meerdere bestanden uploaden door op de link in het upload veld te klikken en de bestanden te selecteren in het Bestand menu.
*
* @extends HTMLElement
* @mixes vlElement
*
* @property {File[]} data-vl-accepted-files - Attribuut om te bepalen welke bestanden worden geaccepteerd door component (extensie en mimetype).
* @property {boolean} data-vl-autoprocess - Attribuut om te activeren of deactiveren dat het het gedropte bestand direct moet opgeladen worden.
* @property {boolean} data-vl-disabled - Attribuut om te voorkomen dat de gebruiker een bijlage kan opladen.
* @property {boolean} data-vl-disallow-duplicates - Attribuut om te voorkomen dat dezelfde bijlage meerdere keren kan opgeladen worden.
* @property {string} data-vl-error - Attribuut om aan te geven dat het upload element een fout bevat.
* @property {string} data-vl-error-message-accepted-files - Attribuut om de message te definiëren wanneer er niet-geaccepteerde bestanden zijn
* toegevoegd.
* @property {string} data-vl-error-message-filesize - Attribuut om de message te definiëren wanneer er te grote bestanden zijn toegevoegd.
* @property {string} data-vl-error-message-maxfiles - Attribuut om de message te definiëren wanneer er teveel bestanden zijn toegevoegd.
* @property {boolean} data-vl-full-body-drop - Attribuut om te activeren of deactiveren dat het de dropzone over het heel scherm is.
* @property {string} data-vl-input-name - Attribuut om de key te definiëren waarmee het bestand wordt opgeladen.
* @property {number} data-vl-max-files - Attribuut om het maximaal aantal bestanden dat opgeladen mag worden, aan te duiden.
* @property {number} data-vl-max-size - Attribuut om de maximum grootte van een bestand dat opgeladen kan worden (20000000 = 2MB), aan te duiden.
* @property {number} data-vl-sub-title - Attribuut om de subtitel te bepalen.
* @property {string} data-vl-success - Attribuut om aan te geven dat het upload element geen fout bevat.
* @property {number} data-vl-title - Attribuut om de titel te bepalen.
* @property {URL} data-vl-url - Attribuut om de url naar waar de component moet uploaden, te definiëren.
*
* @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-upload/releases/latest|Release notes}
* @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-upload/issues|Issues}
* @see {@link https://webcomponenten.omgeving.vlaanderen.be/demo/vl-upload.html|Demo}
*/
export class VlUpload extends vlFormValidationElement(vlElement(HTMLElement)) {
static get _observedAttributes() {
return vlFormValidation._observedAttributes().concat(['accepted-files', 'autoprocess', 'disabled', 'disallow-duplicates', 'error-message-accepted-files', 'error-message-filesize', 'error-message-maxfiles', 'full-body-drop', 'input-name', 'max-files', 'max-size', 'sub-title', 'title', 'url']);
}
static get _observedChildClassAttributes() {
return ['error', 'success'];
}
get _classPrefix() {
return 'vl-upload--';
}
constructor() {
super(`
<style>
@import '/src/style.css';
@import '/node_modules/vl-ui-link/dist/style.css';
</style>
<div class="vl-upload" data-vl-upload data-vl-upload-url="http://www.example.com"></div>
`);
}
connectedCallback() {
this._appendTemplates();
this.dress();
this._processSlots();
}
/**
* Geeft de bestanden die toegevoegd zijn.
* @return {File[]}
*/
get value() {
if (this.acceptedFiles && this.acceptedFiles.length > 0) {
return this.acceptedFiles;
}
}
/**
* Geeft het upload element.
* @return {HTMLElement}
*/
get uploadElement() {
return this.shadowRoot.querySelector('.vl-upload__element');
}
/**
* Haal de geaccepteerde bestanden (zonder error) op, die toegevoegd zijn.
* @return {File[]}
*/
get acceptedFiles() {
return this._dropzone.getAcceptedFiles();
}
/**
* Haal de niet-geaccepteerde bestanden (met error) op, die toegevoegd zijn.
* @return {File[]}
*/
get rejectedFiles() {
return this._dropzone.getRejectedFiles();
}
/**
* Haal alle bestanden op die toegevoegd zijn.
* @return {File[]}
*/
get files() {
return this._dropzone.files;
}
get _upload() {
return this._element;
}
get _dressed() {
return !!this.getAttribute('data-vl-upload-dressed');
}
get _dropzone() {
if (vl && vl.upload && vl.upload.dropzoneInstances) {
return vl.upload.dropzoneInstances.filter((dropzone) => dropzone.element === this._element)[0];
}
}
get _button() {
return this._shadow.querySelector('.vl-upload__element__button');
}
get _hasUploadTemplate() {
return document.body.querySelector('#uploadTemplate');
}
get _hasPreviewFilesWrapperTemplate() {
return document.body.querySelector('#previewFilesWrapper');
}
get _hasPreviewTemplate() {
return document.body.querySelector('#previewTemplate');
}
get _hasUploadOverlayTemplate() {
return document.body.querySelector('#uploadOverlay');
}
get _titleSlotElement() {
return this.querySelector('[slot="title"]');
}
get _subTitleSlotElement() {
return this.querySelector('[slot="sub-title"]');
}
get _titleElement() {
return this.uploadElement.querySelector('#title');
}
get _slottedTitleElement() {
return this.uploadElement.querySelector('#slotted-title');
}
get _subTitleElement() {
return this.uploadElement.querySelector('#sub-title');
}
get _slottedSubTitleElement() {
return this.uploadElement.querySelector('#slotted-sub-title');
}
get _uploadTemplate() {
return this._template(`
<template id="uploadTemplate">
<div class="vl-upload__element">
<div class="vl-upload__element__label">
<button type="button" class="vl-upload__element__button vl-link">
<i class="vl-vi vl-vi-paperclip" aria-hidden="true"></i>
<span class="vl-upload__element__button__container" id="title"></span>
<span class="vl-upload__element__button__container" id="slotted-title"><slot name="title"></slot></span>
</button>
<small id="sub-title"></small>
<small id="slotted-sub-title"><slot name="sub-title"></slot></small>
</div>
</div>
</template>
`);
}
get _previewFilesWrapperTemplate() {
return this._template(`
<template id="previewFilesWrapper">
<div class="vl-upload__files">
<div class="vl-upload__files__container"></div>
<div class="vl-upload__files__input__container"></div>
<button class="vl-upload__files__close vl-link vl-link--icon">
<span class="vl-link__icon vl-vi vl-vi-trash" aria-hidden="true"></span>
Verwijder alle bestanden
</button>
</div>
</template>
`);
}
get _previewTemplate() {
return this._template(`
<template id="previewTemplate">
<div class="vl-upload__file">
<p class="vl-upload__file__name">
<span class="vl-upload__file__name__icon vl-vi vl-vi-document" aria-hidden="true"></span>
<span data-dz-name></span>
<span class="vl-upload__file__size">
(<span data-dz-size></span>)
</span>
</p>
<div class="dz-error-message">
<span data-dz-errormessage></span>
</div>
<button type="button" class="vl-upload__file__close vl-link vl-link--icon" data-dz-remove>
<span class="vl-vi vl-vi-cross" aria-hidden="true"></span>
</button>
</div>
</template>
`);
}
get _uploadOverlayTemplate() {
return this._template(`
<template id="uploadOverlay">
<div class="vl-upload__overlay">
<p class="vl-upload__overlay__text">
<span class="vl-link__icon vl-vi vl-vi-paperclip" aria-hidden="true"></span>
</p>
</div>
</template>
`);
}
get _prefix() {
return 'data-vl-upload-';
}
/**
* Initialiseer de modal config.
* @return {void}
*/
dress() {
if (!this._dressed) {
vl.upload.dress(this._upload);
this._dressFormValidation();
this._dropzone.on('addedfile', () => setTimeout(() => this.dispatchEvent(new Event('change'))));
this._dropzone.on('removedfile', () => setTimeout(() => this.dispatchEvent(new Event('change'))));
this._dropzone.timeout = 0; // 0 value will disable the connection timeout
}
}
/**
* Handmatig de upload aanroepen. Indien een url gegeven is, laad op naar die url.
* @param {String} url
* @return {void}
*/
upload(url) {
if (url) {
this._dropzone.options.url = url;
}
this._dropzone.processQueue();
}
/**
* Verwijder alle files in de dropzone.
* @return {void}
*/
clear() {
this._dropzone.removeAllFiles();
}
/**
* Wrapper om alle events te kunnen catchen van de upload (zoals vl.upload.hook.fileChange alsook de events van
* [DropZoneJs]{@link https://www.dropzonejs.com/#event-list})
* @param {String} event
* @param {Function} callback
* @return {void}
*/
on(event, callback) {
this._element.addEventListener(event, callback);
this._dropzone.on(event, callback);
}
/**
* Handmatig bestand toevoegen aan de lijst van opgeladen bestanden zonder achterliggende upload
* @param {String} name
* @param {Number} size
* @param {Number} id
* @return {void}
*/
addFile({name, size, id}) {
const autoprocessActive = this.dataset.vlAutoprocess != undefined;
if (autoprocessActive) {
this._disableAutoProcessQueue();
}
const file = {name: name, size: size, id: id};
this._dropzone.addFile(file);
this._dropzone.emit('complete', file);
file.status = 'success';
if (autoprocessActive) {
this._enableAutoProcessQueue();
}
}
/**
* Geeft focus aan het link element.
*/
focus() {
this._button.focus();
}
/**
* Enable input element.
*/
enable() {
vl.upload.enable(this._element);
}
/**
* Disable input element.
*/
disable() {
vl.upload.disable(this._element);
}
_acceptedFilesChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'accepted-files', newValue);
this._element.setAttribute('accept', newValue);
}
_autoprocessChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'autoprocess', newValue);
}
_disabledChangedCallback(oldValue, newValue) {
if (newValue !== undefined) {
this.disable();
} else {
this.enable();
}
}
_disallowDuplicatesChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'disallow-duplicates', newValue);
}
_errorMessageAcceptedFilesChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'error-message-accepted-files', newValue);
}
_errorMessageFilesizeChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'error-message-filesize', newValue);
}
_errorMessageMaxfilesChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'error-message-maxfiles', newValue);
}
_fullBodyDropChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'full-body-drop', '');
}
_inputNameChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'input-name', newValue);
}
_maxFilesChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'max-files', newValue);
}
_maxSizeChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'max-size', newValue);
}
_titleChangedCallback(oldValue, newValue) {
this._changeTranslation('upload.add_files', newValue);
}
_subTitleChangedCallback(oldValue, newValue) {
this._changeTranslation('upload.add_files_subtitle', newValue);
}
_urlChangedCallback(oldValue, newValue) {
this._element.setAttribute(this._prefix + 'url', newValue);
if (this._dropzone && this._dropzone.options) {
this._dropzone.options.url = newValue;
}
}
_appendTemplates() {
if (!this._hasUploadTemplate) {
document.body.appendChild(this._uploadTemplate);
}
if (!this._hasPreviewFilesWrapperTemplate) {
document.body.appendChild(this._previewFilesWrapperTemplate);
}
if (!this._hasPreviewTemplate) {
document.body.appendChild(this._previewTemplate);
}
if (!this._hasUploadOverlayTemplate) {
document.body.appendChild(this._uploadOverlayTemplate);
}
}
_disableAutoProcessQueue() {
this._dropzone.options.autoProcessQueue = false;
}
_enableAutoProcessQueue() {
this._dropzone.options.autoProcessQueue = true;
}
_processSlots() {
if (this._titleSlotElement) {
this._titleElement.remove();
} else {
this._slottedTitleElement.remove();
}
if (this._subTitleSlotElement) {
this._subTitleElement.remove();
} else {
this._slottedSubTitleElement.remove();
}
}
}