diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java index bd012dd50a71e4f92f910de68f9329e941b9c833..1b20928c705cebe281b836ba4da4de9b9417691c 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/FileElementRenderer.java @@ -102,6 +102,9 @@ public class FileElementRenderer extends DefaultComponentRenderer { sb.append(id); // name for form labeling sb.append("\" id=\""); sb.append(id); // id to make dirty button work + if (fileElem.getMaxUploadSizeKB() != FileElement.UPLOAD_UNLIMITED) { + sb.append("\" data-max-size=\"").append(fileElem.getMaxUploadSizeKB() * 1024l); + } sb.append("\" class='form-control o_realchooser ").append(" o_chooser_with_delete", showDeleteButton).append("' "); // Add on* event handlers StringBuilder eventHandlers = FormJSHelper.getRawJSFor(fileElem.getRootForm(), id, fileElem.getAction()); diff --git a/src/main/webapp/static/js/functions.js b/src/main/webapp/static/js/functions.js index 66fa538d7121bf1378a576ed140971c41ef7acac..e977bf51b40a9f2dffa4063a3db5fa970860db6c 100644 --- a/src/main/webapp/static/js/functions.js +++ b/src/main/webapp/static/js/functions.js @@ -796,12 +796,32 @@ function o_openPopUp(url, windowname, width, height, menubar) { } function b_handleFileUploadFormChange(fileInputElement, fakeInputElement, saveButton) { + + fileInputElement.setCustomValidity(''); + + if (fileInputElement.hasAttribute('data-max-size')) { + // check if the file selected does satisfy the max-size constraint + var maxSize = fileInputElement.getAttribute('data-max-size'); + if (maxSize) { + var fileSize = formInputFileSize(fileInputElement); + if (fileSize > maxSize) { + // show a validation error message, reset the fileInputElement and stop processing + // to prevent unneeded uploads of potentially really big files + var trans = jQuery(document).ooTranslator().getTranslator(o_info.locale, 'org.olat.modules.forms.ui'); + var msgLimitExceeded = trans.translate('file.upload.error.limit.exeeded'); + var msgUploadLimit = trans.translate('file.upload.limit'); + fileInputElement.setCustomValidity(msgLimitExceeded + + " (" + msgUploadLimit + ": " + (maxSize / 1024 / 1024 / 1024).toFixed(1) + " GB)"); + } + } + } + // file upload forms are rendered transparent and have a fake input field that is rendered. // on change events of the real input field this method is triggered to display the file // path in the fake input field. See the code for more info on this var fileName = fileInputElement.value; // remove unix path - slashPos = fileName.lastIndexOf('/'); + var slashPos = fileName.lastIndexOf('/'); if (slashPos != -1) { fileName=fileName.substring(slashPos + 1); } @@ -825,6 +845,30 @@ function b_handleFileUploadFormChange(fileInputElement, fakeInputElement, saveBu } } +// Return the file size of the selected file in bytes. Returns -1 when API is not working or +// no file was selected. +function formInputFileSize(fileInputElement) { + try { + if (!window.FileReader) { + // file API is not supported do proceed as if the file satisfies the constraint + return -1; + } + if (!fileInputElement || !fileInputElement.files) { + // missing input element parameter or element is not a file input + return -1; + } + var file = fileInputElement.files[0]; + if (!file) { + // no file selected! + return -1; + } + return file.size; + } catch (e) { + o_logerr('form input file size check failed: ' + e); + } + return -1; +} + // goto node must be in global scope to support content that has been opened in a new window // with the clone controller - real implementation is moved to course run scope o_activateCourseNode() function gotonode(nodeid) { @@ -1166,13 +1210,29 @@ function o_ffEvent(formNam, dispIdField, dispId, eventIdField, eventInt){ eventIdEl.value=eventInt; // manually execute onsubmit method - calling submit itself does not trigger onsubmit event! var form = jQuery('#' + formNam); - var enctype = form.attr('enctype'); - if(enctype && enctype.indexOf("multipart") == 0) { - o_XHRSubmitMultipart(formNam); - } else if (document.forms[formNam].onsubmit()) { - document.forms[formNam].submit(); + var formValid = true; + jQuery('#' + formNam + ' input') + .filter(function(index, element) {return !element.checkValidity()}) + .each(function(index, element) { + var valErrorElementId = element.getAttribute('id') + "_validation_error"; + var valErrorElement = document.getElementById(valErrorElementId); + if (!valErrorElement) { + valErrorElement = document.createElement('div'); + valErrorElement.setAttribute('class','o_error'); + valErrorElement.setAttribute('id', valErrorElementId); + element.parentNode.parentNode.appendChild(valErrorElement); + } + valErrorElement.innerHTML = element.validationMessage; + formValid = false; + }); + if (formValid) { + var enctype = form.attr('enctype'); + if(enctype && enctype.indexOf("multipart") == 0) { + o_XHRSubmitMultipart(formNam); + } else if (document.forms[formNam].onsubmit()) { + document.forms[formNam].submit(); + } } - dispIdEl.value = defDispId; eventIdEl.value = defEventId; }