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_checkAll_js
|
||||||
-- addScript $ StaticR js_utils_httpClient_js
|
-- addScript $ StaticR js_utils_httpClient_js
|
||||||
-- addScript $ StaticR js_utils_form_js
|
-- addScript $ StaticR js_utils_form_js
|
||||||
-- addScript $ StaticR js_utils_inputs_js
|
|
||||||
-- JavaScript utils
|
-- JavaScript utils
|
||||||
|
addScript $ StaticR js_utils_inputs_js
|
||||||
addScript $ StaticR js_utils_modal_js
|
addScript $ StaticR js_utils_modal_js
|
||||||
addScript $ StaticR js_utils_poc_js
|
addScript $ StaticR js_utils_poc_js
|
||||||
addScript $ StaticR js_utils_showHide_js
|
addScript $ StaticR js_utils_showHide_js
|
||||||
|
|||||||
@ -196,7 +196,11 @@ option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CUSTOM FILE INPUT */
|
/* FILE INPUT */
|
||||||
|
.file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.file-input__label {
|
.file-input__label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -206,6 +210,15 @@ option {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-input__input--hidden {
|
.file-input__multi-info {
|
||||||
display: none;
|
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() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.utils = window.utils || {};
|
|
||||||
|
|
||||||
var JS_INITIALIZED_CLASS = 'js-inputs-initialized';
|
var JS_INITIALIZED_CLASS = 'js-inputs-initialized';
|
||||||
|
|
||||||
window.utils.inputs = function(wrapper, options) {
|
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
|
* FileUpload Utility
|
||||||
// example: "Dateien ausgewählt" (will be prepended by number of selected files)
|
*
|
||||||
// »selectFile«: label of single-upload button before selection
|
* Attribute: uw-file-upload
|
||||||
// example: "Datei auswählen"
|
* (element must be an input of type='file')
|
||||||
// »selectFiles«: label of multi-upload button before selection
|
*
|
||||||
// example: "Datei(en) auswählen"
|
* 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_UTIL_NAME = 'fileUpload';
|
||||||
var FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS = 'file-input__unpack';
|
var FILE_UPLOAD_UTIL_SELECTOR = 'input[type="file"][uw-file-upload]';
|
||||||
var FILE_UPLOAD_INPUT_LABEL_CLASS = 'file-input__label';
|
|
||||||
var FILE_UPLOAD_INPUT_HIDDEN_CLASS = 'file-input__input--hidden';
|
|
||||||
|
|
||||||
window.utils.fileUpload = function(input, options) {
|
var FILE_UPLOAD_CLASS = 'file-input';
|
||||||
var isMulti = input.hasAttribute('multiple');
|
var FILE_UPLOAD_INITIALIZED_CLASS = 'file-input--initialized';
|
||||||
var fileList = isMulti ? addFileList() : null;
|
var FILE_UPLOAD_LIST_CLASS = 'file-input__list';
|
||||||
var label = addFileLabel();
|
var FILE_UPLOAD_UNPACK_CHECKBOX_CLASS = 'file-input__unpack';
|
||||||
var i18n = options.i18n;
|
var FILE_UPLOAD_LABEL_CLASS = 'file-input__label';
|
||||||
|
|
||||||
if (!i18n) {
|
var fileUploadUtil = function(element) {
|
||||||
throw new Error('window.utils.fileUpload(input, options) needs to be passed i18n object via options');
|
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 = '';
|
fileList.innerHTML = '';
|
||||||
Array.from(files).forEach(function(file, index) {
|
Array.from(files).forEach(function(file) {
|
||||||
var fileDisplayEl = document.createElement('li');
|
var fileDisplayEl = document.createElement('li');
|
||||||
fileDisplayEl.innerHTML = file.name;
|
fileDisplayEl.innerHTML = file.name;
|
||||||
fileList.appendChild(fileDisplayEl);
|
fileList.appendChild(fileDisplayEl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLabel(files) {
|
function createFileList() {
|
||||||
if (files.length) {
|
|
||||||
if (isMulti) {
|
|
||||||
label.innerText = files.length + ' ' + i18n.filesSelected;
|
|
||||||
} else {
|
|
||||||
label.innerHTML = files[0].name;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resetFileLabel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addFileList() {
|
|
||||||
var list = document.createElement('ol');
|
var list = document.createElement('ol');
|
||||||
list.classList.add(FILE_UPLOAD_INPUT_LIST_CLASS);
|
list.classList.add(FILE_UPLOAD_LIST_CLASS);
|
||||||
var unpackEl = input.parentElement.querySelector('.' + FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS);
|
var unpackEl = element.parentElement.querySelector('.' + FILE_UPLOAD_UNPACK_CHECKBOX_CLASS);
|
||||||
if (unpackEl) {
|
if (unpackEl) {
|
||||||
input.parentElement.insertBefore(list, unpackEl);
|
element.parentElement.insertBefore(list, unpackEl);
|
||||||
} else {
|
} else {
|
||||||
input.parentElement.appendChild(list);
|
element.parentElement.appendChild(list);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFileLabel() {
|
function createFileLabel() {
|
||||||
var label = document.createElement('label');
|
var label = document.createElement('label');
|
||||||
label.classList.add(FILE_UPLOAD_INPUT_LABEL_CLASS);
|
label.classList.add(FILE_UPLOAD_LABEL_CLASS);
|
||||||
label.setAttribute('for', input.id);
|
label.setAttribute('for', element.id);
|
||||||
input.parentElement.insertBefore(label, input);
|
element.parentElement.insertBefore(label, element);
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetFileLabel() {
|
function updateLabel() {
|
||||||
if (isMulti) {
|
var files = element.files;
|
||||||
label.innerText = i18n.selectFiles;
|
if (files && files.length) {
|
||||||
|
label.innerText = isMultiFileUpload ? files.length + ' ' + I18n.get('filesSelected') : files[0].name;
|
||||||
} else {
|
} else {
|
||||||
label.innerText = i18n.selectFile;
|
label.innerText = isMultiFileUpload ? I18n.get('selectFiles') : I18n.get('selectFile');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial setup
|
return init();
|
||||||
resetFileLabel();
|
}
|
||||||
input.classList.add(FILE_UPLOAD_INPUT_HIDDEN_CLASS);
|
|
||||||
input.addEventListener('change', function() {
|
|
||||||
input.dispatchEvent(new Event('input'));
|
|
||||||
if (isMulti) {
|
|
||||||
renderFileList(input.files);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// to remove previously uploaded files
|
||||||
@ -158,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
function setup() {
|
function init() {
|
||||||
var cont = input.parentNode;
|
var cont = input.parentNode;
|
||||||
while (cont !== document.body) {
|
while (cont !== document.body) {
|
||||||
if (cont.matches('.' + FILE_UPLOAD_CONTAINER_CLASS)) {
|
if (cont.matches('.' + FILE_UPLOAD_CONTAINER_CLASS)) {
|
||||||
@ -169,12 +199,7 @@
|
|||||||
addListener(cont);
|
addListener(cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup();
|
return init();
|
||||||
|
|
||||||
return {
|
|
||||||
scope: input,
|
|
||||||
destroy: function() {},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// turns native checkboxes into custom ones
|
// turns native checkboxes into custom ones
|
||||||
|
|||||||
@ -7,7 +7,7 @@ $forall FileUploadInfo{..} <- fileInfos
|
|||||||
<label for=#{fuiHtmlId}>
|
<label for=#{fuiHtmlId}>
|
||||||
|
|
||||||
$# new files
|
$# 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>
|
<div .file-input__multi-info>
|
||||||
_{MsgMultiFileUploadInfo}
|
_{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 {
|
.file-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user