refactor file upload JS utility
This commit is contained in:
parent
c2d01e9489
commit
4973fd0b08
@ -1076,8 +1076,8 @@ siteLayout' headingOverride widget = do
|
||||
-- addScript $ StaticR js_utils_checkAll_js
|
||||
-- addScript $ StaticR js_utils_httpClient_js
|
||||
-- addScript $ StaticR js_utils_form_js
|
||||
-- addScript $ StaticR js_utils_inputs_js
|
||||
-- JavaScript utils
|
||||
addScript $ StaticR js_utils_inputs_js
|
||||
addScript $ StaticR js_utils_modal_js
|
||||
addScript $ StaticR js_utils_poc_js
|
||||
addScript $ StaticR js_utils_showHide_js
|
||||
|
||||
@ -196,7 +196,11 @@ option {
|
||||
}
|
||||
}
|
||||
|
||||
/* CUSTOM FILE INPUT */
|
||||
/* FILE INPUT */
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-input__label {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@ -206,6 +210,15 @@ option {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.file-input__input--hidden {
|
||||
display: none;
|
||||
.file-input__multi-info {
|
||||
font-size: .9rem;
|
||||
font-style: italic;
|
||||
margin-top: 10px;
|
||||
color: var(--color-fontsec);
|
||||
}
|
||||
|
||||
.file-input__list {
|
||||
margin-left: 15px;
|
||||
margin-top: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.utils = window.utils || {};
|
||||
|
||||
var JS_INITIALIZED_CLASS = 'js-inputs-initialized';
|
||||
|
||||
window.utils.inputs = function(wrapper, options) {
|
||||
@ -53,95 +51,127 @@
|
||||
};
|
||||
};
|
||||
|
||||
// (multiple) dynamic file uploads
|
||||
// expects i18n object with following strings:
|
||||
// »filesSelected«: label of multi-upload button after selection
|
||||
// example: "Dateien ausgewählt" (will be prepended by number of selected files)
|
||||
// »selectFile«: label of single-upload button before selection
|
||||
// example: "Datei auswählen"
|
||||
// »selectFiles«: label of multi-upload button before selection
|
||||
// example: "Datei(en) auswählen"
|
||||
/**
|
||||
*
|
||||
* FileUpload Utility
|
||||
*
|
||||
* Attribute: uw-file-upload
|
||||
* (element must be an input of type='file')
|
||||
*
|
||||
* Example usage:
|
||||
* <input type='file' uw-file-upload>
|
||||
*
|
||||
* Internationalization:
|
||||
* This utility expects the following translations to be available:
|
||||
* »filesSelected«: label of multi-upload button after selection
|
||||
* example: "Dateien ausgewählt" (will be prepended by number of selected files)
|
||||
* »selectFile«: label of single-upload button before selection
|
||||
* example: "Datei auswählen"
|
||||
* »selectFiles«: label of multi-upload button before selection
|
||||
* example: "Datei(en) auswählen"
|
||||
*
|
||||
*/
|
||||
|
||||
var FILE_UPLOAD_INPUT_LIST_CLASS = 'file-input__list';
|
||||
var FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS = 'file-input__unpack';
|
||||
var FILE_UPLOAD_INPUT_LABEL_CLASS = 'file-input__label';
|
||||
var FILE_UPLOAD_INPUT_HIDDEN_CLASS = 'file-input__input--hidden';
|
||||
var FILE_UPLOAD_UTIL_NAME = 'fileUpload';
|
||||
var FILE_UPLOAD_UTIL_SELECTOR = 'input[type="file"][uw-file-upload]';
|
||||
|
||||
window.utils.fileUpload = function(input, options) {
|
||||
var isMulti = input.hasAttribute('multiple');
|
||||
var fileList = isMulti ? addFileList() : null;
|
||||
var label = addFileLabel();
|
||||
var i18n = options.i18n;
|
||||
var FILE_UPLOAD_CLASS = 'file-input';
|
||||
var FILE_UPLOAD_INITIALIZED_CLASS = 'file-input--initialized';
|
||||
var FILE_UPLOAD_LIST_CLASS = 'file-input__list';
|
||||
var FILE_UPLOAD_UNPACK_CHECKBOX_CLASS = 'file-input__unpack';
|
||||
var FILE_UPLOAD_LABEL_CLASS = 'file-input__label';
|
||||
|
||||
if (!i18n) {
|
||||
throw new Error('window.utils.fileUpload(input, options) needs to be passed i18n object via options');
|
||||
var fileUploadUtil = function(element) {
|
||||
var isMultiFileUpload = false;
|
||||
var fileList;
|
||||
var label;
|
||||
|
||||
function init() {
|
||||
if (!element) {
|
||||
throw new Error('FileUpload utility cannot be setup without an element!');
|
||||
}
|
||||
|
||||
if (element.classList.contains(FILE_UPLOAD_INITIALIZED_CLASS)) {
|
||||
throw new Error('FileUpload utility already initialized!');
|
||||
}
|
||||
|
||||
// check if is multi-file upload
|
||||
isMultiFileUpload = element.hasAttribute('multiple');
|
||||
if (isMultiFileUpload) {
|
||||
fileList = createFileList();
|
||||
}
|
||||
|
||||
label = createFileLabel();
|
||||
updateLabel();
|
||||
|
||||
// add change listener
|
||||
element.addEventListener('change', function() {
|
||||
updateLabel();
|
||||
renderFileList();
|
||||
});
|
||||
|
||||
// add util class for styling and mark as initialized
|
||||
element.classList.add(FILE_UPLOAD_CLASS, FILE_UPLOAD_INITIALIZED_CLASS);
|
||||
|
||||
return {
|
||||
name: FILE_UPLOAD_UTIL_NAME,
|
||||
element: element,
|
||||
destroy: function() {},
|
||||
};
|
||||
}
|
||||
|
||||
function renderFileList(files) {
|
||||
function renderFileList() {
|
||||
if (!fileList) {
|
||||
return;
|
||||
}
|
||||
|
||||
var files = element.files;
|
||||
fileList.innerHTML = '';
|
||||
Array.from(files).forEach(function(file, index) {
|
||||
Array.from(files).forEach(function(file) {
|
||||
var fileDisplayEl = document.createElement('li');
|
||||
fileDisplayEl.innerHTML = file.name;
|
||||
fileList.appendChild(fileDisplayEl);
|
||||
});
|
||||
}
|
||||
|
||||
function updateLabel(files) {
|
||||
if (files.length) {
|
||||
if (isMulti) {
|
||||
label.innerText = files.length + ' ' + i18n.filesSelected;
|
||||
} else {
|
||||
label.innerHTML = files[0].name;
|
||||
}
|
||||
} else {
|
||||
resetFileLabel();
|
||||
}
|
||||
}
|
||||
|
||||
function addFileList() {
|
||||
function createFileList() {
|
||||
var list = document.createElement('ol');
|
||||
list.classList.add(FILE_UPLOAD_INPUT_LIST_CLASS);
|
||||
var unpackEl = input.parentElement.querySelector('.' + FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS);
|
||||
list.classList.add(FILE_UPLOAD_LIST_CLASS);
|
||||
var unpackEl = element.parentElement.querySelector('.' + FILE_UPLOAD_UNPACK_CHECKBOX_CLASS);
|
||||
if (unpackEl) {
|
||||
input.parentElement.insertBefore(list, unpackEl);
|
||||
element.parentElement.insertBefore(list, unpackEl);
|
||||
} else {
|
||||
input.parentElement.appendChild(list);
|
||||
element.parentElement.appendChild(list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function addFileLabel() {
|
||||
function createFileLabel() {
|
||||
var label = document.createElement('label');
|
||||
label.classList.add(FILE_UPLOAD_INPUT_LABEL_CLASS);
|
||||
label.setAttribute('for', input.id);
|
||||
input.parentElement.insertBefore(label, input);
|
||||
label.classList.add(FILE_UPLOAD_LABEL_CLASS);
|
||||
label.setAttribute('for', element.id);
|
||||
element.parentElement.insertBefore(label, element);
|
||||
return label;
|
||||
}
|
||||
|
||||
function resetFileLabel() {
|
||||
if (isMulti) {
|
||||
label.innerText = i18n.selectFiles;
|
||||
function updateLabel() {
|
||||
var files = element.files;
|
||||
if (files && files.length) {
|
||||
label.innerText = isMultiFileUpload ? files.length + ' ' + I18n.get('filesSelected') : files[0].name;
|
||||
} else {
|
||||
label.innerText = i18n.selectFile;
|
||||
label.innerText = isMultiFileUpload ? I18n.get('selectFiles') : I18n.get('selectFile');
|
||||
}
|
||||
}
|
||||
|
||||
// initial setup
|
||||
resetFileLabel();
|
||||
input.classList.add(FILE_UPLOAD_INPUT_HIDDEN_CLASS);
|
||||
input.addEventListener('change', function() {
|
||||
input.dispatchEvent(new Event('input'));
|
||||
if (isMulti) {
|
||||
renderFileList(input.files);
|
||||
}
|
||||
return init();
|
||||
}
|
||||
|
||||
updateLabel(input.files);
|
||||
if (UtilRegistry) {
|
||||
UtilRegistry.register({
|
||||
name: FILE_UPLOAD_UTIL_NAME,
|
||||
selector: FILE_UPLOAD_UTIL_SELECTOR,
|
||||
setup: fileUploadUtil,
|
||||
});
|
||||
|
||||
return {
|
||||
scope: input,
|
||||
destroy: function() {},
|
||||
};
|
||||
}
|
||||
|
||||
// to remove previously uploaded files
|
||||
@ -158,7 +188,7 @@
|
||||
}
|
||||
|
||||
// initial setup
|
||||
function setup() {
|
||||
function init() {
|
||||
var cont = input.parentNode;
|
||||
while (cont !== document.body) {
|
||||
if (cont.matches('.' + FILE_UPLOAD_CONTAINER_CLASS)) {
|
||||
@ -169,12 +199,7 @@
|
||||
addListener(cont);
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
return {
|
||||
scope: input,
|
||||
destroy: function() {},
|
||||
};
|
||||
return init();
|
||||
}
|
||||
|
||||
// turns native checkboxes into custom ones
|
||||
|
||||
@ -7,7 +7,7 @@ $forall FileUploadInfo{..} <- fileInfos
|
||||
<label for=#{fuiHtmlId}>
|
||||
|
||||
$# new files
|
||||
<input type="file" name=#{fieldName} id=#{fieldId} multiple :req:required="required">
|
||||
<input type="file" uw-file-upload name=#{fieldName} id=#{fieldId} multiple :req:required="required">
|
||||
|
||||
<div .file-input__multi-info>
|
||||
_{MsgMultiFileUploadInfo}
|
||||
|
||||
@ -10,19 +10,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.file-input__multi-info {
|
||||
font-size: .9rem;
|
||||
font-style: italic;
|
||||
margin-top: 10px;
|
||||
color: var(--color-fontsec);
|
||||
}
|
||||
|
||||
.file-input__list {
|
||||
margin-left: 15px;
|
||||
margin-top: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.file-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user