diff --git a/config/install/image_widget_crop.settings.yml b/config/install/image_widget_crop.settings.yml index cd1c6f3..af7486a 100644 --- a/config/install/image_widget_crop.settings.yml +++ b/config/install/image_widget_crop.settings.yml @@ -5,3 +5,4 @@ settings: crop_list: [] warn_multiple_usages: FALSE show_default_crop: TRUE + crop_required: FALSE diff --git a/config/schema/image_widget_crop.schema.yml b/config/schema/image_widget_crop.schema.yml index 3838b64..fc38273 100644 --- a/config/schema/image_widget_crop.schema.yml +++ b/config/schema/image_widget_crop.schema.yml @@ -27,6 +27,9 @@ field.widget.settings.image_widget_crop: show_default_crop: type: boolean label: 'Show default crop area' + crop_required: + type: boolean + label: 'Crops are required to validate file' image_widget_crop.settings: type: config_object @@ -58,3 +61,6 @@ image_widget_crop.settings: show_crop_area: type: boolean label: 'Always expand crop area' + crop_required: + type: boolean + label: 'Crops are required to validate file' diff --git a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.media.image.default.yml b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.media.image.default.yml index 5f40014..de758a3 100644 --- a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.media.image.default.yml +++ b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.media.image.default.yml @@ -31,6 +31,7 @@ content: progress_indicator: throbber show_crop_area: false warn_multiple_usages: false + crop_required: false third_party_settings: { } type: image_widget_crop region: content diff --git a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_file_imce_example.default.yml b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_file_imce_example.default.yml index ed53241..d4c4dbf 100644 --- a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_file_imce_example.default.yml +++ b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_file_imce_example.default.yml @@ -36,6 +36,7 @@ content: settings: show_default_crop: true warn_multiple_usages: true + crop_required: false preview_image_style: thumbnail crop_preview_image_style: crop_thumbnail crop_list: diff --git a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_responsive_example.default.yml b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_responsive_example.default.yml index dbbbb8e..fd5833c 100644 --- a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_responsive_example.default.yml +++ b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_responsive_example.default.yml @@ -37,6 +37,7 @@ content: settings: show_default_crop: true warn_multiple_usages: true + crop_required: false preview_image_style: thumbnail crop_preview_image_style: crop_thumbnail crop_list: diff --git a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_simple_example.default.yml b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_simple_example.default.yml index e033fcb..46ab396 100644 --- a/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_simple_example.default.yml +++ b/modules/image_widget_crop_examples/config/optional/core.entity_form_display.node.crop_simple_example.default.yml @@ -38,6 +38,7 @@ content: show_crop_area: true show_default_crop: true warn_multiple_usages: true + crop_required: false preview_image_style: thumbnail crop_preview_image_style: crop_thumbnail crop_list: diff --git a/modules/image_widget_crop_examples/image_widget_crop_examples.install b/modules/image_widget_crop_examples/image_widget_crop_examples.install index 70a79de..3135047 100644 --- a/modules/image_widget_crop_examples/image_widget_crop_examples.install +++ b/modules/image_widget_crop_examples/image_widget_crop_examples.install @@ -21,6 +21,7 @@ function image_widget_crop_examples_install() { ->set('settings.crop_preview_image_style', 'crop_thumbnail') ->set('settings.show_default_crop', TRUE) ->set('settings.warn_multiple_usages', FALSE) + ->set('settings.crop_required', FALSE) ->set('settings.crop_list', [ 'crop_16_9' => 'crop_16_9', 'crop_4_3' => 'crop_4_3', diff --git a/src/Element/ImageCrop.php b/src/Element/ImageCrop.php index 6615519..d1a1116 100644 --- a/src/Element/ImageCrop.php +++ b/src/Element/ImageCrop.php @@ -34,6 +34,7 @@ class ImageCrop extends FormElement { '#warn_multiple_usages' => FALSE, '#show_default_crop' => TRUE, '#show_crop_area' => FALSE, + '#crop_required' => FALSE, '#attached' => [ 'library' => 'image_widget_crop/cropper.integration', ], @@ -181,7 +182,10 @@ class ImageCrop extends FormElement { // Element to track whether cropping is applied or not. $element['crop_wrapper'][$type]['crop_container']['values']['crop_applied'] = [ '#type' => 'hidden', - '#attributes' => ['data-drupal-iwc-value' => 'applied'], + '#attributes' => [ + 'data-drupal-iwc-value' => 'applied', + 'data-drupal-iwc-id' => $type, + ], '#default_value' => 0, ]; $edit = FALSE; @@ -198,6 +202,15 @@ class ImageCrop extends FormElement { $properties = $form_state_properties; } + if ($element['#crop_required']) { + $element['crop_wrapper'][$type]['crop_container']['values']['crop_applied']['#element_validate'] = [ + [ + static::class, + 'cropRequired', + ], + ]; + } + /** @var \Drupal\crop\CropInterface $crop */ $crop = Crop::findCrop($file->getFileUri(), $type); if ($crop) { @@ -391,6 +404,34 @@ class ImageCrop extends FormElement { } /** + * Form element validation handler for crop widget elements. + * + * @param array $element + * All form elements without crop properties. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @see ImageCrop::getCropFormElement() + */ + public static function cropRequired(array $element, FormStateInterface $form_state) { + /** @var \Drupal\crop\Entity\CropType $crop_type */ + $crop_type = \Drupal::entityTypeManager() + ->getStorage('crop_type') + ->load($element['#attributes']['data-drupal-iwc-id']); + $crop_applied = $form_state->getValue($element['#parents']); + $action_button = $form_state->getTriggeringElement()['#value']; + $operation = ($action_button instanceof TranslatableMarkup) ? $action_button->getUntranslatedString() : $action_button; + + if ((int) $crop_applied === 0 && $operation !== 'Remove') { + $form_state->setError($element, t('Crop @crop_name is required.', + [ + '@crop_name' => $crop_type->label(), + ] + )); + } + } + + /** * Set All sizes properties of the crops. * * @return array diff --git a/src/Form/CropWidgetForm.php b/src/Form/CropWidgetForm.php index 70454fe..d163d44 100644 --- a/src/Form/CropWidgetForm.php +++ b/src/Form/CropWidgetForm.php @@ -157,6 +157,12 @@ class CropWidgetForm extends ConfigFormBase { '#default_value' => $this->settings->get('settings.show_default_crop'), ]; + $form['image_crop']['crop_required'] = [ + '#title' => $this->t('Crops are required to validate file'), + '#type' => 'checkbox', + '#default_value' => $this->settings->get('settings.crop_required'), + ]; + return parent::buildForm($form, $form_state); } @@ -221,7 +227,8 @@ class CropWidgetForm extends ConfigFormBase { ->set("settings.show_default_crop", $form_state->getValue('show_default_crop')) ->set("settings.show_crop_area", $form_state->getValue('show_crop_area')) ->set("settings.warn_multiple_usages", $form_state->getValue('warn_multiple_usages')) - ->set("settings.crop_list", $form_state->getValue('crop_list')); + ->set("settings.crop_list", $form_state->getValue('crop_list')) + ->set("settings.crop_required", $form_state->getValue('crop_required')); $this->settings->save(); } diff --git a/src/Plugin/Field/FieldWidget/ImageCropWidget.php b/src/Plugin/Field/FieldWidget/ImageCropWidget.php index 8dfa223..200d6d4 100644 --- a/src/Plugin/Field/FieldWidget/ImageCropWidget.php +++ b/src/Plugin/Field/FieldWidget/ImageCropWidget.php @@ -102,6 +102,7 @@ class ImageCropWidget extends ImageWidget { 'show_crop_area' => FALSE, 'show_default_crop' => TRUE, 'warn_multiple_usages' => TRUE, + 'crop_required' => FALSE, ] + parent::defaultSettings(); } @@ -126,6 +127,7 @@ class ImageCropWidget extends ImageWidget { '#show_default_crop' => $element['#show_default_crop'], '#show_crop_area' => $element['#show_crop_area'], '#warn_multiple_usages' => $element['#warn_multiple_usages'], + '#crop_required' => $element['#crop_required'], ]; } } @@ -210,6 +212,12 @@ class ImageCropWidget extends ImageWidget { '#default_value' => $this->getSetting('warn_multiple_usages'), ]; + $element['crop_required'] = [ + '#title' => $this->t('Crops are required to validate file.'), + '#type' => 'checkbox', + '#default_value' => $this->getSetting('crop_required'), + ]; + return $element; } @@ -234,10 +242,12 @@ class ImageCropWidget extends ImageWidget { $crop_show_button = $this->getSetting('show_crop_area'); $show_default_crop = $this->getSetting('show_default_crop'); $warn_multiple_usages = $this->getSetting('warn_multiple_usages'); + $crop_required = $this->getSetting('crop_required'); $preview[] = $this->t('Always expand crop area: @bool', ['@bool' => ($crop_show_button) ? 'Yes' : 'No']); $preview[] = $this->t('Show default crop area: @bool', ['@bool' => ($show_default_crop) ? 'Yes' : 'No']); $preview[] = $this->t('Warn the user if the crop is used more than once: @bool', ['@bool' => ($warn_multiple_usages) ? 'Yes' : 'No']); + $preview[] = $this->t('Crops are required to validate file: @bool', ['@bool' => ($crop_required) ? 'Yes' : 'No']); if (isset($image_styles[$image_style_setting])) { $preview[] = $this->t('Preview image style: @style', ['@style' => $image_style_setting]); @@ -270,6 +280,7 @@ class ImageCropWidget extends ImageWidget { $element['#show_crop_area'] = $this->getSetting('show_crop_area'); $element['#show_default_crop'] = $this->getSetting('show_default_crop'); $element['#warn_multiple_usages'] = $this->getSetting('warn_multiple_usages'); + $element['#crop_required'] = $this->getSetting('crop_required'); return parent::formElement($items, $delta, $element, $form, $form_state); }