diff --git a/src/Handler/Sheet.hs b/src/Handler/Sheet.hs index a7f672cc7..fdcc1c14b 100644 --- a/src/Handler/Sheet.hs +++ b/src/Handler/Sheet.hs @@ -83,7 +83,7 @@ makeSheetForm msId template = identForm FIDsheet $ \html -> do <*> aopt utcTimeField (fsb "Sichtbar ab") (sfVisibleFrom <$> template) <*> areq utcTimeField (fsb "Abgabe ab") (sfActiveFrom <$> 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) <*> fileAFormOpt (fsb "Hinweis") <*> aopt utcTimeField (fsb "Lösung ab") (sfSolutionFrom <$> template) diff --git a/src/Handler/Utils/Form.hs b/src/Handler/Utils/Form.hs index bbd547277..1c41fab33 100644 --- a/src/Handler/Utils/Form.hs +++ b/src/Handler/Utils/Form.hs @@ -245,8 +245,10 @@ schoolEntField = selectField schools where schools = optionsPersist [] [Asc SchoolName] schoolName -multiFileField :: Handler (Set FileId) -> Field Handler (Source Handler (Either FileId File)) -multiFileField permittedFiles' = Field{..} +multiFileField :: Maybe Bool -- ^ Override @unpackZips@-checkbox? + -> Handler (Set FileId) -- ^ Existing files to allow keeping + -> Field Handler (Source Handler (Either FileId File)) +multiFileField doUnpackOverride permittedFiles' = Field{..} where fieldEnctype = Multipart fieldParse vals files @@ -270,7 +272,9 @@ multiFileField permittedFiles' = Field{..} | otherwise = yieldM . acceptFile mapM_ handleFile files .| C.map Right where - doUnpack = unpackZips `elem` vals + doUnpack = case doUnpackOverride of + Nothing -> unpackZips `elem` vals + Just o -> o fieldView fieldId fieldName attrs val req = do pVals <- handlerToWidget permittedFiles' sentVals <- for val $ \src -> handlerToWidget . sourceToList $ src .| takeLefts diff --git a/templates/multiFileField.hamlet b/templates/multiFileField.hamlet index 9a9822c84..384408d49 100644 --- a/templates/multiFileField.hamlet +++ b/templates/multiFileField.hamlet @@ -1,17 +1,24 @@ $newline never - - - - ZIPs entpacken - - - - $forall FileUploadInfo{..} <- fileInfos - - - - #{fuiTitle} +$forall FileUploadInfo{..} <- fileInfos + + #{fuiTitle} + + - #{fuiTitle} - - + + + + file1.txt + + + + +$# new files + + +$case doUnpackOverride + $of Nothing + + ZIPs entpacken + + $of _ diff --git a/templates/standalone/inputs.julius b/templates/standalone/inputs.julius index 4744d8628..30c3ebad9 100644 --- a/templates/standalone/inputs.julius +++ b/templates/standalone/inputs.julius @@ -25,11 +25,12 @@ }; // allows for multiple file uploads with separate inputs - window.utils.reactiveFileUpload = function(input, parent) { + window.utils.reactiveFileUpload = function(input, formGroup) { var currValidInputCount = 0; var addMore = false; var inputName = input.getAttribute('name'); var isMulti = input.hasAttribute('multiple') ? true : false; + var wrapper = formGroup; // FileInput PseudoClass function FileInput(container, input, label, remover) { this.container = container; @@ -49,26 +50,26 @@ } } 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')) { - makeInput(inputName).addTo(parent); + makeInput(inputName).addTo(wrapper); } } // updates submitbutton and form-group-stripe function updateForm() { - var submitBtn = parent.parentElement.querySelector('[type=submit]'); - parent.classList.remove('form-group--has-error'); + var submitBtn = formGroup.parentElement.querySelector('[type=submit]'); + formGroup.classList.remove('form-group--has-error'); if (currValidInputCount > 0) { - if (parent.classList.contains('form-group')) { - parent.classList.add('form-group--valid') + if (formGroup.classList.contains('form-group')) { + formGroup.classList.add('form-group--valid') } submitBtn.removeAttribute('disabled'); if (isMulti) { addNextInput(); } } else { - if (parent.classList.contains('form-group')) { - parent.classList.remove('form-group--valid') + if (formGroup.classList.contains('form-group')) { + formGroup.classList.remove('form-group--valid') } submitBtn.setAttribute('disabled', 'disabled'); } @@ -141,22 +142,27 @@ // initial setup function setup() { var newInput = makeInput(inputName); + if (isMulti) { + wrapper = document.createElement('div'); + wrapper.classList.add('file-input__wrapper'); + formGroup.insertBefore(wrapper, input); + } input.remove(); - newInput.addTo(parent); + newInput.addTo(wrapper); updateForm(); } setup(); } // to remove previously uploaded files - window.utils.reactiveFileCheckbox = function(input, label, parent) { + window.utils.reactiveFileCheckbox = function(input) { // adds eventlistener(s) function addListener(container) { container.addEventListener('click', function() { input.click(); }); 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')); if (!input) { console.error('No input found for ReactiveLabel! Targeted input: \'#%s\'', label.getAttribute('for')); + label.classList.remove('reactive-label'); return false; } var parent = label.parentElement; 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 isInFormGroup = parent.classList.contains('form-group') && parent.classList.contains('form-group--required'); @@ -221,16 +226,24 @@ document.addEventListener('DOMContentLoaded', function() { if (isInFormGroup) { window.utils.reactiveFormGroup(parent, input); } - if (isFileUpload) { - window.utils.reactiveFileUpload(input, parent); - } - if (isFileCheckbox) { - window.utils.reactiveFileCheckbox(input, label, parent); - } if (isListening) { window.utils.reactiveInputLabel(input, label); } else { 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); + }); }); diff --git a/templates/standalone/inputs.lucius b/templates/standalone/inputs.lucius index c5514988a..e22350888 100644 --- a/templates/standalone/inputs.lucius +++ b/templates/standalone/inputs.lucius @@ -263,11 +263,16 @@ input[type="file"].js-file-input { outline: 0; border: 0; } +.file-input__wrapper { + grid-column-start: 2; +} .file-input__container, -.file-checkbox__container { +.file-checkbox__container, +.file-input__unpack { grid-column-start: 2; display: flex; justify-content: space-between; + margin: 4px 0; } .file-input__label, .file-input__remover, @@ -336,12 +341,12 @@ input[type="file"].js-file-input { .file-input__container--valid > .file-input__label { background-color: var(--lightbase); } -.file-checkbox__container--valid > .file-checkbox__label { +.file-checkbox__container--checked > .file-checkbox__label { text-decoration: none; background-color: var(--lighterbase); - &:hover { - background-color: var(--greybase); + &.btn:hover { + background-color: var(--lighterbase); text-decoration: line-through; } } @@ -353,8 +358,10 @@ input[type="file"].js-file-input { display: block; } @media (max-width: 999px) { + .file-input__wrapper, .file-input__container, - .file-checkbox__container { + .file-checkbox__container, + .file-input__unpack { grid-column-start: 1; } }