File uploads
Combination of fields and buttons to add documents or media to a form.
When to use
When there is a need to allow users to attach anything to a form (documents, pictures, videos, etc).
Implementation
In order to automatically attach event listeners on your file upload forms, add the following script to your page:
document.addEventListener('DOMContentLoaded', function() {
ECL.fileUploads();
});
{#
Parameters:
- "id" (string) (default: 'default-id'): the id of the file input
- "name" (string) (default: 'default-name'): the name of the file input
- "value" (string) (default: 'No file selected.'): the name of the file selected
- "label_browse" (string) (default: 'Browse'): the label of the Browse button
- "has_upload" (boolean) (default: true): define if form upload has a "upload" button
- "label_upload" (string) (default: 'Upload'): the label of the Upload button
- "is_disabled" (boolean) (default: false): define if form upload is disabled
- "is_multiple" (boolean) (default: false): define if form upload is multiple
- "has_error" (boolean) (default: false): define if form upload has error
- "extra_classes" (string) (default: '')
- "extra_attributes" (array) (default: []): format: [
{
"name" (string) (default: ''),
"value" (string) (default: '')
},
...
]
#}
{% include '@ecl/generic-component-form-file-upload' %}
/* Normal file upload */
{
"id": "example-input-id-1",
"name": "example-input-name-1"
}
/* Disabled file upload */
{
"id": "example-input-id-2",
"name": "example-input-name-2",
"is_disabled": true
}
/* Multiple file upload */
{
"id": "example-input-id-3",
"name": "example-input-name-3",
"is_multiple": true
}
/* File upload with error */
{
"id": "example-input-id-4",
"name": "example-input-name-4",
"has_error": true
}
<!-- Normal file upload -->
<div class="ecl-file-upload">
<div class="ecl-file-upload__value" tabindex="0">No file selected.</div>
<label for="example-input-id-1">
<span class="ecl-file-upload__browse" role="button" aria-controls="example-input-id-1" tabindex="0">Browse</span>
</label>
<button class="ecl-file-upload__upload" tabindex="0" type="submit">
Upload
</button>
<input class="ecl-file-upload__input" name="example-input-name-1" type="file" id="example-input-id-1">
</div>
<!-- Disabled file upload -->
<div class="ecl-file-upload ecl-file-upload--is-disabled">
<div class="ecl-file-upload__value" tabindex="0">No file selected.</div>
<label for="example-input-id-2">
<span class="ecl-file-upload__browse" role="button" aria-controls="example-input-id-2" tabindex="0">Browse</span>
</label>
<input class="ecl-file-upload__input" name="example-input-name-2" type="file" id="example-input-id-2" disabled>
</div>
<!-- Multiple file upload -->
<div class="ecl-file-upload">
<div class="ecl-file-upload__value" tabindex="0">No file selected.</div>
<label for="example-input-id-3">
<span class="ecl-file-upload__browse" role="button" aria-controls="example-input-id-3" tabindex="0">Browse</span>
</label>
<button class="ecl-file-upload__upload" tabindex="0" type="submit">
Upload
</button>
<input class="ecl-file-upload__input" name="example-input-name-3" type="file" id="example-input-id-3" multiple>
</div>
<!-- File upload with error -->
<div class="ecl-file-upload ecl-file-upload--has-error">
<div class="ecl-file-upload__value" tabindex="0">No file selected.</div>
<label for="example-input-id-4">
<span class="ecl-file-upload__browse" role="button" aria-controls="example-input-id-4" tabindex="0">Browse</span>
</label>
<button class="ecl-file-upload__upload" tabindex="0" type="submit">
Upload
</button>
<input class="ecl-file-upload__input" name="example-input-name-4" type="file" id="example-input-id-4">
</div>
-
Content:
/** * File uploads related behaviors. */ import { queryAll } from '@ecl/eu-base/helpers/dom'; /** * @param {object} options Object containing configuration overrides */ export const fileUploads = ({ selector: selector = '.ecl-file-upload', inputSelector: inputSelector = '.ecl-file-upload__input', valueSelector: valueSelector = '.ecl-file-upload__value', browseSelector: browseSelector = '.ecl-file-upload__browse', } = {}) => { // SUPPORTS if ( !('querySelector' in document) || !('addEventListener' in window) || !document.documentElement.classList ) return null; // SETUP // set file upload element NodeLists const fileUploadContainers = queryAll(selector); // ACTIONS function updateFileName(element, files) { if (files.length === 0) return; let filename = ''; for (let i = 0; i < files.length; i += 1) { const file = files[i]; if ('name' in file) { if (i > 0) { filename += ', '; } filename += file.name; } } // Show the selected filename in the field. const messageElement = element; messageElement.innerHTML = filename; } // EVENTS function eventValueChange(e) { if ('files' in e.target) { const fileUploadElements = queryAll(valueSelector, e.target.parentNode); fileUploadElements.forEach(fileUploadElement => { updateFileName(fileUploadElement, e.target.files); }); } } function eventBrowseKeydown(e) { // collect header targets, and their prev/next const isModifierKey = e.metaKey || e.altKey; const inputElements = queryAll(inputSelector, e.target.parentNode); inputElements.forEach(inputElement => { // don't catch key events when ⌘ or Alt modifier is present if (isModifierKey) return; // catch enter/space, left/right and up/down arrow key events // if new panel show it, if next/prev move focus switch (e.keyCode) { case 13: case 32: e.preventDefault(); inputElement.click(); break; default: break; } }); } // BIND EVENTS function bindFileUploadEvents(fileUploadContainer) { // bind all file upload change events const fileUploadInputs = queryAll(inputSelector, fileUploadContainer); fileUploadInputs.forEach(fileUploadInput => { fileUploadInput.addEventListener('change', eventValueChange); }); // bind all file upload keydown events const fileUploadBrowses = queryAll(browseSelector, fileUploadContainer); fileUploadBrowses.forEach(fileUploadBrowse => { fileUploadBrowse.addEventListener('keydown', eventBrowseKeydown); }); } // UNBIND EVENTS function unbindFileUploadEvents(fileUploadContainer) { const fileUploadInputs = queryAll(inputSelector, fileUploadContainer); // unbind all file upload change events fileUploadInputs.forEach(fileUploadInput => { fileUploadInput.removeEventListener('change', eventValueChange); }); const fileUploadBrowses = queryAll(browseSelector, fileUploadContainer); // bind all file upload keydown events fileUploadBrowses.forEach(fileUploadBrowse => { fileUploadBrowse.removeEventListener('keydown', eventBrowseKeydown); }); } // DESTROY function destroy() { fileUploadContainers.forEach(fileUploadContainer => { unbindFileUploadEvents(fileUploadContainer); }); } // INIT function init() { if (fileUploadContainers.length) { fileUploadContainers.forEach(fileUploadContainer => { bindFileUploadEvents(fileUploadContainer); }); } } init(); // REVEAL API return { init, destroy, }; }; // module exports export default fileUploads;
- URL: /components/raw/eu-component-form-file-upload/eu-component-form-file-upload.js
- Filesystem Path: ../../src/systems/eu/eu-component/eu-component-form/eu-component-form-file-upload/eu-component-form-file-upload.js
- Size: 3.8 KB
-
Content:
/* * File upload * @define file-upload */ // Import base and generic @import '@ecl/ec-base/ec-base'; @import '@ecl/generic-component-form-file-upload/generic-component-form-file-upload'; // Use generic mixin @include exports('ec-component-form-file-upload') { @include ecl-file-upload(); }
- URL: /components/raw/eu-component-form-file-upload/eu-component-form-file-upload.scss
- Filesystem Path: ../../src/systems/eu/eu-component/eu-component-form/eu-component-form-file-upload/eu-component-form-file-upload.scss
- Size: 297 Bytes
- Handle: @ecl/eu-component-form-file-upload
- Tags: atom
- Preview:
- Filesystem Path: ../../src/systems/eu/eu-component/eu-component-form/eu-component-form-file-upload/eu-component-form-file-upload.twig