diff --git a/src/bundle/Resources/public/js/scripts/fieldType/base/base-file-field.js b/src/bundle/Resources/public/js/scripts/fieldType/base/base-file-field.js index 3e3687be9f..442a356a23 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/base/base-file-field.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/base/base-file-field.js @@ -16,6 +16,7 @@ const isRequired = input.required || this.fieldContainer.classList.contains('ibexa-field-edit--required'); const dataMaxSize = +input.dataset.maxFileSize; const maxFileSize = parseInt(dataMaxSize, 10); + const { allowedFileTypes } = input.dataset; const isEmpty = input.files && !input.files.length && dataContainer && !dataContainer.hasAttribute('hidden'); let result = { isError: false }; @@ -26,8 +27,14 @@ }; } - if (!isEmpty && maxFileSize > 0 && input.files[0] && input.files[0].size > maxFileSize) { - result = this.validateFileSize(event); + const file = input.files[0]; + + if (!isEmpty && maxFileSize > 0 && file && file.size > maxFileSize) { + result = this.validateFileSize(); + } + + if (!isEmpty && allowedFileTypes.length > 0 && file && !allowedFileTypes.includes(file.type)) { + result = this.showFileTypeError(); } return result; @@ -52,6 +59,16 @@ return result; } + + showFileTypeError() { + const label = this.fieldContainer.querySelector(SELECTOR_FIELD_LABEL).innerHTML; + const result = { + isError: true, + errorMessage: ibexa.errors.invalidFileType.replace('{fieldName}', label), + }; + + return result; + } } ibexa.addConfig('BaseFileFieldValidator', BaseFileFieldValidator); diff --git a/src/bundle/Resources/public/js/scripts/fieldType/base/base-preview-field.js b/src/bundle/Resources/public/js/scripts/fieldType/base/base-preview-field.js index 3a30a4369b..71410d2865 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/base/base-preview-field.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/base/base-preview-field.js @@ -87,6 +87,10 @@ return this.showFileSizeError(); } + if (this.allowedFileTypes.length > 0 && !this.allowedFileTypes.includes(file.type)) { + return this.showFileTypeError(); + } + const changeEvent = new Event('change'); this.inputField.files = event.dataTransfer.files; @@ -102,6 +106,10 @@ this.inputField.dispatchEvent(new CustomEvent('ibexa-invalid-file-size')); } + showFileTypeError() { + this.inputField.dispatchEvent(new CustomEvent('ibexa-invalid-file-type')); + } + /** * Checks whether a given file can be dropped onto a field * diff --git a/src/bundle/Resources/public/js/scripts/fieldType/ezbinaryfile.js b/src/bundle/Resources/public/js/scripts/fieldType/ezbinaryfile.js index 2fea06ca8d..d2c6139867 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/ezbinaryfile.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/ezbinaryfile.js @@ -41,6 +41,13 @@ callback: 'showFileSizeError', errorNodeSelectors: ['.ibexa-form-error'], }, + { + isValueValidator: false, + selector: `input[type="file"]`, + eventName: 'ibexa-invalid-file-type', + callback: 'showFileTypeError', + errorNodeSelectors: ['.ibexa-form-error'], + }, ], }); const previewField = new EzBinaryFilePreviewField({ diff --git a/src/bundle/Resources/public/js/scripts/fieldType/ezimage.js b/src/bundle/Resources/public/js/scripts/fieldType/ezimage.js index 87b803c22b..2ffc4e0001 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/ezimage.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/ezimage.js @@ -123,6 +123,13 @@ callback: 'showFileSizeError', errorNodeSelectors: ['.ibexa-form-error'], }, + { + isValueValidator: false, + selector: `${SELECTOR_INPUT_FILE}`, + eventName: 'ibexa-invalid-file-type', + callback: 'showFileTypeError', + errorNodeSelectors: ['.ibexa-form-error'], + }, { isValueValidator: false, selector: SELECTOR_INPUT_ALT, diff --git a/src/bundle/Resources/public/js/scripts/fieldType/ezimageasset.js b/src/bundle/Resources/public/js/scripts/fieldType/ezimageasset.js index 71b89a89c9..70527d536a 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/ezimageasset.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/ezimageasset.js @@ -187,7 +187,7 @@ */ handleInputChange(event) { const [file] = event.currentTarget.files; - const { languageCode } = event.currentTarget.dataset; + const { languageCode, allowedFileTypes } = event.currentTarget.dataset; const isFileSizeLimited = this.maxFileSize > 0; const maxFileSizeExceeded = isFileSizeLimited && file.size > this.maxFileSize; @@ -196,6 +196,11 @@ return; } + if (!allowedFileTypes.includes(file.type)) { + this.resetInputField(); + return; + } + this.fieldContainer.querySelector('.ibexa-field-edit__option--remove-media').checked = false; this.createAsset(file, languageCode); @@ -244,6 +249,13 @@ callback: 'showFileSizeError', errorNodeSelectors: ['.ibexa-form-error'], }, + { + isValueValidator: false, + selector: `${SELECTOR_INPUT_FILE}`, + eventName: 'ibexa-invalid-file-type', + callback: 'showFileTypeError', + errorNodeSelectors: ['.ibexa-form-error'], + }, ], }); diff --git a/src/bundle/Resources/public/js/scripts/fieldType/ezmedia.js b/src/bundle/Resources/public/js/scripts/fieldType/ezmedia.js index 4f63d0d9d1..394599d6d4 100644 --- a/src/bundle/Resources/public/js/scripts/fieldType/ezmedia.js +++ b/src/bundle/Resources/public/js/scripts/fieldType/ezmedia.js @@ -139,6 +139,13 @@ callback: 'showFileSizeError', errorNodeSelectors: ['.ibexa-field-edit--ezmedia .ibexa-form-error'], }, + { + isValueValidator: false, + selector: SELECTOR_INPUT_FILE, + eventName: 'ibexa-invalid-file-type', + callback: 'showFileTypeError', + errorNodeSelectors: ['.ibexa-field-edit--ezmedia .ibexa-form-error'], + }, { selector: '.ibexa-field-edit-preview__dimensions .form-control', eventName: 'blur', diff --git a/src/bundle/Resources/public/scss/fieldType/edit/_base-preview.scss b/src/bundle/Resources/public/scss/fieldType/edit/_base-preview.scss index a91b0b37ad..f6d07914e8 100644 --- a/src/bundle/Resources/public/scss/fieldType/edit/_base-preview.scss +++ b/src/bundle/Resources/public/scss/fieldType/edit/_base-preview.scss @@ -44,7 +44,7 @@ color: $ibexa-color-dark-300; } - &--mime-types, + &--image-extensions, &--filesize { color: $ibexa-color-dark-300; font-size: $ibexa-text-font-size-small; diff --git a/src/bundle/Resources/translations/ibexa_content_forms_content.en.xliff b/src/bundle/Resources/translations/ibexa_content_forms_content.en.xliff index dba58c5253..480c071ce7 100644 --- a/src/bundle/Resources/translations/ibexa_content_forms_content.en.xliff +++ b/src/bundle/Resources/translations/ibexa_content_forms_content.en.xliff @@ -161,16 +161,16 @@ or key: fieldtype.binary_base.drag_drop.or + + Allowed extensions: %extensions% + Allowed extensions: %extensions% + key: fieldtype.binary_base.image_extensions + Max file size: %size% Max file size: %size% key: fieldtype.binary_base.max_file_size - - Allowed mime types: %mime_types% - Allowed mime types: %mime_types% - key: fieldtype.binary_base.mime_types - Upload file Upload file diff --git a/src/bundle/Resources/translations/validators.en.xliff b/src/bundle/Resources/translations/validators.en.xliff index c1d09d5690..a05aacd696 100644 --- a/src/bundle/Resources/translations/validators.en.xliff +++ b/src/bundle/Resources/translations/validators.en.xliff @@ -96,6 +96,11 @@ {fieldName}: Cannot upload. File exceeds file size limit. key: js.error.invalid_file_size + + {fieldName}: Cannot upload. File has wrong type. + {fieldName}: Cannot upload. File has wrong type. + key: js.error.invalid_file_type + A valid URL is required A valid URL is required diff --git a/src/bundle/Resources/views/themes/admin/ui/field_type/edit/binary_base.html.twig b/src/bundle/Resources/views/themes/admin/ui/field_type/edit/binary_base.html.twig index d185576d9c..5a68006aca 100644 --- a/src/bundle/Resources/views/themes/admin/ui/field_type/edit/binary_base.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/field_type/edit/binary_base.html.twig @@ -53,9 +53,15 @@
{{ 'fieldtype.binary_base.max_file_size'|trans({'%size%': max_file_size|default(0)|ibexa_file_size(2)})|desc('Max file size: %size%') }}
{% endif %} - {% if mime_types is defined %} -
- {{ 'fieldtype.binary_base.mime_types'|trans({'%mime_types%': mime_types|join(', ')})|desc('Allowed mime types: %mime_types%') }} + {% if image_extensions is defined %} + {% set extensions = [] %} + + {% for mime_type in mime_types %} + {% set extensions = extensions|merge(image_extensions[mime_type]) %} + {% endfor %} + +
+ {{ 'fieldtype.binary_base.image_extensions'|trans({'%extensions%': extensions|join(', ')})|desc('Allowed extensions: %extensions%') }}
{% endif %} diff --git a/src/bundle/Resources/views/themes/admin/ui/field_type/edit/ezimageasset.html.twig b/src/bundle/Resources/views/themes/admin/ui/field_type/edit/ezimageasset.html.twig index a851c55c81..78356d9423 100644 --- a/src/bundle/Resources/views/themes/admin/ui/field_type/edit/ezimageasset.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/field_type/edit/ezimageasset.html.twig @@ -17,6 +17,10 @@ 'accept': 'image/*' }) %} + {% if mime_types is defined %} + {% set attr = attr|merge({'data-allowed-file-types': mime_types|join(',') }) %} + {% endif %} + {{ block('binary_base_row') }} {%- endblock -%} @@ -50,9 +54,15 @@
{% endif %} - {% if mime_types is defined %} -
- {{ 'fieldtype.binary_base.mime_types'|trans({'%mime_types%': mime_types|join(', ')})|desc('Allowed mime types: %mime_types%') }} + {% if image_extensions is defined %} + {% set extensions = [] %} + + {% for mime_type in mime_types %} + {% set extensions = extensions|merge(image_extensions[mime_type]) %} + {% endfor %} + +
+ {{ 'fieldtype.binary_base.image_extensions'|trans({'%extensions%': extensions|join(', ')})|desc('Allowed extensions: %extensions%') }}
{% endif %} diff --git a/src/bundle/Resources/views/themes/admin/ui/layout.html.twig b/src/bundle/Resources/views/themes/admin/ui/layout.html.twig index 335adec7b3..0c222d32af 100644 --- a/src/bundle/Resources/views/themes/admin/ui/layout.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/layout.html.twig @@ -72,6 +72,7 @@ isLess: '{{ 'js.error.is_less'|trans({}, 'validators')|desc('{fieldName} value must be greater than or equal to {minValue}') }}', isGreater: '{{ 'js.error.is_greater'|trans({}, 'validators')|desc('{fieldName} value must be less than or equal to {maxValue}') }}', invalidFileSize: '{{ 'js.error.invalid_file_size'|trans({}, 'validators')|desc('{fieldName}: Cannot upload. File exceeds file size limit.') }}', + invalidFileType: '{{ 'js.error.invalid_file_type'|trans({}, 'validators')|desc('{fieldName}: Cannot upload. File has wrong type.') }}', provideLatitudeValue: '{{ 'js.error.provide_latitude_value'|trans({}, 'validators')|desc('Provide latitude value in the Latitude field') }}', provideLongitudeValue: '{{ 'js.error.provide_longitude_value'|trans({}, 'validators')|desc('Provide longitude value in the Longitude field') }}', addressNotFound: '{{ 'js.error.address_not_found'|trans({}, 'validators')|desc('Provided address does not exist') }}',