Merge remote-tracking branch 'origin/master' into feat/exercises
This commit is contained in:
commit
fa6b04663e
@ -83,7 +83,7 @@ makeSheetForm msId template = identForm FIDsheet $ \html -> do
|
|||||||
<*> aopt utcTimeField (fsb "Sichtbar ab") (sfVisibleFrom <$> template)
|
<*> aopt utcTimeField (fsb "Sichtbar ab") (sfVisibleFrom <$> template)
|
||||||
<*> areq utcTimeField (fsb "Abgabe ab") (sfActiveFrom <$> template)
|
<*> areq utcTimeField (fsb "Abgabe ab") (sfActiveFrom <$> template)
|
||||||
<*> areq utcTimeField (fsb "Abgabefrist") (sfActiveTo <$> template)
|
<*> areq utcTimeField (fsb "Abgabefrist") (sfActiveTo <$> template)
|
||||||
<*> aopt (multiFileField $ oldFileIds SheetExercise) (fsb "Aufgabenstellung") (sfSheetF <$> template)
|
<*> aopt (multiFileField Nothing $ oldFileIds SheetExercise) (fsb "Aufgabenstellung") (sfSheetF <$> template)
|
||||||
<*> aopt utcTimeField (fsb "Hinweis ab") (sfHintFrom <$> template)
|
<*> aopt utcTimeField (fsb "Hinweis ab") (sfHintFrom <$> template)
|
||||||
<*> fileAFormOpt (fsb "Hinweis")
|
<*> fileAFormOpt (fsb "Hinweis")
|
||||||
<*> aopt utcTimeField (fsb "Lösung ab") (sfSolutionFrom <$> template)
|
<*> aopt utcTimeField (fsb "Lösung ab") (sfSolutionFrom <$> template)
|
||||||
|
|||||||
@ -245,8 +245,10 @@ schoolEntField = selectField schools
|
|||||||
where
|
where
|
||||||
schools = optionsPersist [] [Asc SchoolName] schoolName
|
schools = optionsPersist [] [Asc SchoolName] schoolName
|
||||||
|
|
||||||
multiFileField :: Handler (Set FileId) -> Field Handler (Source Handler (Either FileId File))
|
multiFileField :: Maybe Bool -- ^ Override @unpackZips@-checkbox?
|
||||||
multiFileField permittedFiles' = Field{..}
|
-> Handler (Set FileId) -- ^ Existing files to allow keeping
|
||||||
|
-> Field Handler (Source Handler (Either FileId File))
|
||||||
|
multiFileField doUnpackOverride permittedFiles' = Field{..}
|
||||||
where
|
where
|
||||||
fieldEnctype = Multipart
|
fieldEnctype = Multipart
|
||||||
fieldParse vals files
|
fieldParse vals files
|
||||||
@ -270,7 +272,9 @@ multiFileField permittedFiles' = Field{..}
|
|||||||
| otherwise = yieldM . acceptFile
|
| otherwise = yieldM . acceptFile
|
||||||
mapM_ handleFile files .| C.map Right
|
mapM_ handleFile files .| C.map Right
|
||||||
where
|
where
|
||||||
doUnpack = unpackZips `elem` vals
|
doUnpack = case doUnpackOverride of
|
||||||
|
Nothing -> unpackZips `elem` vals
|
||||||
|
Just o -> o
|
||||||
fieldView fieldId fieldName attrs val req = do
|
fieldView fieldId fieldName attrs val req = do
|
||||||
pVals <- handlerToWidget permittedFiles'
|
pVals <- handlerToWidget permittedFiles'
|
||||||
sentVals <- for val $ \src -> handlerToWidget . sourceToList $ src .| takeLefts
|
sentVals <- for val $ \src -> handlerToWidget . sourceToList $ src .| takeLefts
|
||||||
|
|||||||
@ -1,17 +1,24 @@
|
|||||||
$newline never
|
$newline never
|
||||||
|
$forall FileUploadInfo{..} <- fileInfos
|
||||||
<input type=checkbox id=#{fieldId}_zip name=#{fieldName} value=#{unpackZips} :req:required>
|
<div .file-checkbox__container :fuiChecked:.file-checkbox__container--checked>
|
||||||
<label for=#{fieldId}_zip>
|
<label .file-checkbox__label.reactive-label.btn for=#{fuiHtmlId}>#{fuiTitle}
|
||||||
ZIPs entpacken
|
<div .checkbox>
|
||||||
|
<input .file-checkbox.js-file-checkbox id=#{fuiHtmlId} name=#{fieldName} :fuiChecked:checked value=#{toPathPiece fuiId} type="checkbox">
|
||||||
|
|
||||||
<ul>
|
|
||||||
$forall FileUploadInfo{..} <- fileInfos
|
|
||||||
<li>
|
|
||||||
<input type=checkbox name=#{fieldName} value=#{toPathPiece fuiId} id=#{fuiHtmlId} :fuiChecked:checked>
|
|
||||||
<span style="display:none">
|
|
||||||
#{fuiTitle}
|
|
||||||
<label for=#{fuiHtmlId}>
|
<label for=#{fuiHtmlId}>
|
||||||
#{fuiTitle}
|
|
||||||
<li>
|
|
||||||
<input type=file id=#{fieldId} name=#{fieldName} multiple>
|
<div .file-checkbox__container.file-checkbox__container--checked>
|
||||||
|
<label .file-checkbox__label.reactive-label.btn for=fi1>file1.txt
|
||||||
|
<div .checkbox>
|
||||||
|
<input .file-checkbox.js-file-checkbox id=fi1 name=file checked value="file1.txt" type="checkbox">
|
||||||
|
<label for=fi1>
|
||||||
|
|
||||||
|
$# new files
|
||||||
|
<input type="file" name=#{fieldName} multiple>
|
||||||
|
|
||||||
|
$case doUnpackOverride
|
||||||
|
$of Nothing
|
||||||
|
<div .file-input__unpack>
|
||||||
|
<label for=#{fieldId}_zip>ZIPs entpacken
|
||||||
|
<input type=checkbox id=#{fieldId}_zip name=#{fieldName} value=#{unpackZips} :req:required>
|
||||||
|
$of _
|
||||||
|
|||||||
@ -25,11 +25,12 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// allows for multiple file uploads with separate inputs
|
// allows for multiple file uploads with separate inputs
|
||||||
window.utils.reactiveFileUpload = function(input, parent) {
|
window.utils.reactiveFileUpload = function(input, formGroup) {
|
||||||
var currValidInputCount = 0;
|
var currValidInputCount = 0;
|
||||||
var addMore = false;
|
var addMore = false;
|
||||||
var inputName = input.getAttribute('name');
|
var inputName = input.getAttribute('name');
|
||||||
var isMulti = input.hasAttribute('multiple') ? true : false;
|
var isMulti = input.hasAttribute('multiple') ? true : false;
|
||||||
|
var wrapper = formGroup;
|
||||||
// FileInput PseudoClass
|
// FileInput PseudoClass
|
||||||
function FileInput(container, input, label, remover) {
|
function FileInput(container, input, label, remover) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
@ -49,26 +50,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function addNextInput() {
|
function addNextInput() {
|
||||||
var inputs = parent.querySelectorAll('.file-input__container');
|
var inputs = wrapper.querySelectorAll('.file-input__container');
|
||||||
if (inputs[inputs.length - 1].classList.contains('file-input__container--valid')) {
|
if (inputs[inputs.length - 1].classList.contains('file-input__container--valid')) {
|
||||||
makeInput(inputName).addTo(parent);
|
makeInput(inputName).addTo(wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// updates submitbutton and form-group-stripe
|
// updates submitbutton and form-group-stripe
|
||||||
function updateForm() {
|
function updateForm() {
|
||||||
var submitBtn = parent.parentElement.querySelector('[type=submit]');
|
var submitBtn = formGroup.parentElement.querySelector('[type=submit]');
|
||||||
parent.classList.remove('form-group--has-error');
|
formGroup.classList.remove('form-group--has-error');
|
||||||
if (currValidInputCount > 0) {
|
if (currValidInputCount > 0) {
|
||||||
if (parent.classList.contains('form-group')) {
|
if (formGroup.classList.contains('form-group')) {
|
||||||
parent.classList.add('form-group--valid')
|
formGroup.classList.add('form-group--valid')
|
||||||
}
|
}
|
||||||
submitBtn.removeAttribute('disabled');
|
submitBtn.removeAttribute('disabled');
|
||||||
if (isMulti) {
|
if (isMulti) {
|
||||||
addNextInput();
|
addNextInput();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (parent.classList.contains('form-group')) {
|
if (formGroup.classList.contains('form-group')) {
|
||||||
parent.classList.remove('form-group--valid')
|
formGroup.classList.remove('form-group--valid')
|
||||||
}
|
}
|
||||||
submitBtn.setAttribute('disabled', 'disabled');
|
submitBtn.setAttribute('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
@ -141,22 +142,27 @@
|
|||||||
// initial setup
|
// initial setup
|
||||||
function setup() {
|
function setup() {
|
||||||
var newInput = makeInput(inputName);
|
var newInput = makeInput(inputName);
|
||||||
|
if (isMulti) {
|
||||||
|
wrapper = document.createElement('div');
|
||||||
|
wrapper.classList.add('file-input__wrapper');
|
||||||
|
formGroup.insertBefore(wrapper, input);
|
||||||
|
}
|
||||||
input.remove();
|
input.remove();
|
||||||
newInput.addTo(parent);
|
newInput.addTo(wrapper);
|
||||||
updateForm();
|
updateForm();
|
||||||
}
|
}
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// to remove previously uploaded files
|
// to remove previously uploaded files
|
||||||
window.utils.reactiveFileCheckbox = function(input, label, parent) {
|
window.utils.reactiveFileCheckbox = function(input) {
|
||||||
// adds eventlistener(s)
|
// adds eventlistener(s)
|
||||||
function addListener(container) {
|
function addListener(container) {
|
||||||
container.addEventListener('click', function() {
|
container.addEventListener('click', function() {
|
||||||
input.click();
|
input.click();
|
||||||
});
|
});
|
||||||
input.addEventListener('change', function(event) {
|
input.addEventListener('change', function(event) {
|
||||||
container.classList.toggle('file-checkbox__container--valid', this.checked);
|
container.classList.toggle('file-checkbox__container--checked', this.checked);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,13 +213,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
var input = document.querySelector('#' + label.getAttribute('for'));
|
var input = document.querySelector('#' + label.getAttribute('for'));
|
||||||
if (!input) {
|
if (!input) {
|
||||||
console.error('No input found for ReactiveLabel! Targeted input: \'#%s\'', label.getAttribute('for'));
|
console.error('No input found for ReactiveLabel! Targeted input: \'#%s\'', label.getAttribute('for'));
|
||||||
|
label.classList.remove('reactive-label');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = label.parentElement;
|
var parent = label.parentElement;
|
||||||
var type = input.getAttribute('type');
|
var type = input.getAttribute('type');
|
||||||
var isFileUpload = /file/i.test(type);
|
|
||||||
var isFileCheckbox = input.classList.contains('file-checkbox');
|
|
||||||
var isListening = !RegExp(['date', 'checkbox', 'radio', 'hidden', 'file'].join('|')).test(type);
|
var isListening = !RegExp(['date', 'checkbox', 'radio', 'hidden', 'file'].join('|')).test(type);
|
||||||
var isInFormGroup = parent.classList.contains('form-group') && parent.classList.contains('form-group--required');
|
var isInFormGroup = parent.classList.contains('form-group') && parent.classList.contains('form-group--required');
|
||||||
|
|
||||||
@ -221,16 +226,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
if (isInFormGroup) {
|
if (isInFormGroup) {
|
||||||
window.utils.reactiveFormGroup(parent, input);
|
window.utils.reactiveFormGroup(parent, input);
|
||||||
}
|
}
|
||||||
if (isFileUpload) {
|
|
||||||
window.utils.reactiveFileUpload(input, parent);
|
|
||||||
}
|
|
||||||
if (isFileCheckbox) {
|
|
||||||
window.utils.reactiveFileCheckbox(input, label, parent);
|
|
||||||
}
|
|
||||||
if (isListening) {
|
if (isListening) {
|
||||||
window.utils.reactiveInputLabel(input, label);
|
window.utils.reactiveInputLabel(input, label);
|
||||||
} else {
|
} else {
|
||||||
label.classList.remove('reactive-label');
|
label.classList.remove('reactive-label');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// initialize file-upload-fields
|
||||||
|
Array.from(document.querySelectorAll('input[type="file"]')).map(function(inp) {
|
||||||
|
var formGroup = inp.parentNode;
|
||||||
|
while (!formGroup.classList.contains('form-group') && formGroup !== document.body) {
|
||||||
|
formGroup = formGroup.parentNode;
|
||||||
|
}
|
||||||
|
window.utils.reactiveFileUpload(inp, formGroup);
|
||||||
|
});
|
||||||
|
|
||||||
|
// initialize file-checkbox-fields
|
||||||
|
Array.from(document.querySelectorAll('.js-file-checkbox')).map(function(inp) {
|
||||||
|
window.utils.reactiveFileCheckbox(inp);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -263,11 +263,16 @@ input[type="file"].js-file-input {
|
|||||||
outline: 0;
|
outline: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
.file-input__wrapper {
|
||||||
|
grid-column-start: 2;
|
||||||
|
}
|
||||||
.file-input__container,
|
.file-input__container,
|
||||||
.file-checkbox__container {
|
.file-checkbox__container,
|
||||||
|
.file-input__unpack {
|
||||||
grid-column-start: 2;
|
grid-column-start: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
.file-input__label,
|
.file-input__label,
|
||||||
.file-input__remover,
|
.file-input__remover,
|
||||||
@ -336,12 +341,12 @@ input[type="file"].js-file-input {
|
|||||||
.file-input__container--valid > .file-input__label {
|
.file-input__container--valid > .file-input__label {
|
||||||
background-color: var(--lightbase);
|
background-color: var(--lightbase);
|
||||||
}
|
}
|
||||||
.file-checkbox__container--valid > .file-checkbox__label {
|
.file-checkbox__container--checked > .file-checkbox__label {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: var(--lighterbase);
|
background-color: var(--lighterbase);
|
||||||
|
|
||||||
&:hover {
|
&.btn:hover {
|
||||||
background-color: var(--greybase);
|
background-color: var(--lighterbase);
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,8 +358,10 @@ input[type="file"].js-file-input {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@media (max-width: 999px) {
|
@media (max-width: 999px) {
|
||||||
|
.file-input__wrapper,
|
||||||
.file-input__container,
|
.file-input__container,
|
||||||
.file-checkbox__container {
|
.file-checkbox__container,
|
||||||
|
.file-input__unpack {
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user