diff --git a/composer.json b/composer.json index 7b9f890c76335f437957257a5916c72c012961e8..e23a58291fa25dae13e72034c41089f2b3e394b7 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,7 @@ "drupal/addtocalendar": "3.2", "drupal/admin_toolbar": "3.1.0", "drupal/administerusersbyrole": "3.0", - "drupal/allowed_formats": "1.3", + "drupal/allowed_formats": "1.5", "drupal/anchor_link": "1.9", "drupal/better_exposed_filters": "5.0", "drupal/block_field": "1.0.0-rc2", @@ -100,15 +100,16 @@ "drupal/cache_control_override": "^1.0@alpha", "drupal/ckeditor_indentblock": "1.0.0-beta2", "drupal/config_direct_save": "2.1", + "drupal/config_filter": "1.9", "drupal/config_ignore": "2.3", "drupal/config_update": "1.7", "drupal/console": "1.9.7", "drupal/content_access": "1.0-alpha3", "drupal/core-composer-scaffold": "^9.0", "drupal/core-recommended": "^9.0", - "drupal/crop": "2.1", + "drupal/crop": "2.2", "drupal/ctools": "3.7", - "drupal/dropzonejs": "2.5", + "drupal/dropzonejs": "2.6", "drupal/editor_advanced_link": "1.9", "drupal/embed": "1.4", "drupal/entity": "1.2", diff --git a/composer.lock b/composer.lock index de80c3e923052f635c4198be11aaddb12f9a5675..e7dc1110159d744b8f09569f1187c6f9134d3a07 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ddbb6bfcc5492e80908375b84ecb45bb", + "content-hash": "0db64872456ea6dcec72cfaea15b3fdf", "packages": [ { "name": "alchemy/zippy", @@ -1843,26 +1843,26 @@ }, { "name": "drupal/allowed_formats", - "version": "1.3.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/allowed_formats.git", - "reference": "8.x-1.3" + "reference": "8.x-1.5" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/allowed_formats-8.x-1.3.zip", - "reference": "8.x-1.3", - "shasum": "4c3c036d7b41428d6e22b61f1219de0ab012feec" + "url": "https://ftp.drupal.org/files/projects/allowed_formats-8.x-1.5.zip", + "reference": "8.x-1.5", + "shasum": "dbf61bee7aec87beaa2cf307c1d0d9d5b896328c" }, "require": { - "drupal/core": "^8.7.7 || ^9" + "drupal/core": "^8.8 || ^9" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.3", - "datestamp": "1592909219", + "version": "8.x-1.5", + "datestamp": "1648060331", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -1875,18 +1875,31 @@ ], "authors": [ { - "name": "floretan", - "homepage": "https://www.drupal.org/user/66163" + "name": "Northern Commerce (formerly Digital Echidna)", + "homepage": "https://www.drupal.org/northern-commerce-formerly-digital-echidna", + "role": "Supporting organization" }, { - "name": "nord102", - "homepage": "https://www.drupal.org/user/3471419" + "name": "Jordan Thompson (nord102)", + "homepage": "https://www.drupal.org/u/nord102", + "role": "Maintainer" + }, + { + "name": "Wunder", + "homepage": "https://www.drupal.org/wunder", + "role": "Supporting organization" + }, + { + "name": "Florian Loretan (floretan)", + "homepage": "https://www.drupal.org/u/floretan", + "role": "Maintainer" } ], "description": "Limit which text formats are available for each field instance.", "homepage": "https://www.drupal.org/project/allowed_formats", "support": { - "source": "https://git.drupalcode.org/project/allowed_formats" + "source": "http://cgit.drupalcode.org/allowed_formats", + "issues": "https://www.drupal.org/project/issues/allowed_formats" } }, { @@ -2446,17 +2459,17 @@ }, { "name": "drupal/config_filter", - "version": "1.8.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/config_filter.git", - "reference": "8.x-1.8" + "reference": "8.x-1.9" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/config_filter-8.x-1.8.zip", - "reference": "8.x-1.8", - "shasum": "5def5f97e79d6f5af6bb7007f012443475c90bfe" + "url": "https://ftp.drupal.org/files/projects/config_filter-8.x-1.9.zip", + "reference": "8.x-1.9", + "shasum": "cf6919fc5039771f8e6c2ed203f29ab0eca8d91f" }, "require": { "drupal/core": "^8 || ^9" @@ -2467,8 +2480,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.8", - "datestamp": "1603870062", + "version": "8.x-1.9", + "datestamp": "1649336052", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -3347,17 +3360,17 @@ }, { "name": "drupal/crop", - "version": "2.1.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/crop.git", - "reference": "8.x-2.1" + "reference": "8.x-2.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.1.zip", - "reference": "8.x-2.1", - "shasum": "c03541907d59874ca8a81f574258f6c0de8cbdc8" + "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.2.zip", + "reference": "8.x-2.2", + "shasum": "b5a84c6b85b9582e686ccf421295611d9dd52055" }, "require": { "drupal/core": "^8.8 || ^9" @@ -3365,8 +3378,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.1", - "datestamp": "1585251827", + "version": "8.x-2.2", + "datestamp": "1645187494", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -3497,23 +3510,23 @@ }, { "name": "drupal/dropzonejs", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/dropzonejs.git", - "reference": "8.x-2.5" + "reference": "8.x-2.6" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.5.zip", - "reference": "8.x-2.5", - "shasum": "9918bd8c3c62599ec701be3bbac986741e735859" + "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.6.zip", + "reference": "8.x-2.6", + "shasum": "3a14b26ade989e00bbbc9f6bbfa364fb5acb9367" }, "require": { "drupal/core": "^8.8 || ^9" }, "require-dev": { - "drupal/entity_browser": "*" + "drupal/entity_browser": "^2.5" }, "suggest": { "enyo/dropzone": "Required to use drupal/dropzonejs. DropzoneJS is an open source library that provides drag’n’drop file uploads with image previews." @@ -3521,8 +3534,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.5", - "datestamp": "1614606376", + "version": "8.x-2.6", + "datestamp": "1647857808", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -4810,6 +4823,10 @@ "name": "RobLoach", "homepage": "https://www.drupal.org/user/61114" }, + { + "name": "bnjmnm", + "homepage": "https://www.drupal.org/user/2369194" + }, { "name": "jjeff", "homepage": "https://www.drupal.org/user/17190" @@ -6919,6 +6936,10 @@ "name": "geekwisdom", "homepage": "https://www.drupal.org/user/1662" }, + { + "name": "japerry", + "homepage": "https://www.drupal.org/user/45640" + }, { "name": "snufkin", "homepage": "https://www.drupal.org/user/58645" @@ -8052,7 +8073,7 @@ "extra": { "drupal": { "version": "6.1.2", - "datestamp": "1638988073", + "datestamp": "1644940638", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 86c3899c9dbe35b57362b6d302d44c1b706ca8b3..83a97a7e7126690681f64d6bb20c98744387f72a 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1890,27 +1890,27 @@ }, { "name": "drupal/allowed_formats", - "version": "1.3.0", - "version_normalized": "1.3.0.0", + "version": "1.5.0", + "version_normalized": "1.5.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/allowed_formats.git", - "reference": "8.x-1.3" + "reference": "8.x-1.5" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/allowed_formats-8.x-1.3.zip", - "reference": "8.x-1.3", - "shasum": "4c3c036d7b41428d6e22b61f1219de0ab012feec" + "url": "https://ftp.drupal.org/files/projects/allowed_formats-8.x-1.5.zip", + "reference": "8.x-1.5", + "shasum": "dbf61bee7aec87beaa2cf307c1d0d9d5b896328c" }, "require": { - "drupal/core": "^8.7.7 || ^9" + "drupal/core": "^8.8 || ^9" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.3", - "datestamp": "1592909219", + "version": "8.x-1.5", + "datestamp": "1648060331", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -1924,14 +1924,31 @@ ], "authors": [ { - "name": "floretan", - "homepage": "https://www.drupal.org/user/66163" + "name": "Northern Commerce (formerly Digital Echidna)", + "homepage": "https://www.drupal.org/northern-commerce-formerly-digital-echidna", + "role": "Supporting organization" + }, + { + "name": "Jordan Thompson (nord102)", + "homepage": "https://www.drupal.org/u/nord102", + "role": "Maintainer" + }, + { + "name": "Wunder", + "homepage": "https://www.drupal.org/wunder", + "role": "Supporting organization" + }, + { + "name": "Florian Loretan (floretan)", + "homepage": "https://www.drupal.org/u/floretan", + "role": "Maintainer" } ], "description": "Limit which text formats are available for each field instance.", "homepage": "https://www.drupal.org/project/allowed_formats", "support": { - "source": "https://git.drupalcode.org/project/allowed_formats" + "source": "http://cgit.drupalcode.org/allowed_formats", + "issues": "https://www.drupal.org/project/issues/allowed_formats" }, "install-path": "../../web/modules/allowed_formats" }, @@ -2522,18 +2539,18 @@ }, { "name": "drupal/config_filter", - "version": "1.8.0", - "version_normalized": "1.8.0.0", + "version": "1.9.0", + "version_normalized": "1.9.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/config_filter.git", - "reference": "8.x-1.8" + "reference": "8.x-1.9" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/config_filter-8.x-1.8.zip", - "reference": "8.x-1.8", - "shasum": "5def5f97e79d6f5af6bb7007f012443475c90bfe" + "url": "https://ftp.drupal.org/files/projects/config_filter-8.x-1.9.zip", + "reference": "8.x-1.9", + "shasum": "cf6919fc5039771f8e6c2ed203f29ab0eca8d91f" }, "require": { "drupal/core": "^8 || ^9" @@ -2544,8 +2561,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.8", - "datestamp": "1603870062", + "version": "8.x-1.9", + "datestamp": "1649336052", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -3438,18 +3455,18 @@ }, { "name": "drupal/crop", - "version": "2.1.0", - "version_normalized": "2.1.0.0", + "version": "2.2.0", + "version_normalized": "2.2.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/crop.git", - "reference": "8.x-2.1" + "reference": "8.x-2.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.1.zip", - "reference": "8.x-2.1", - "shasum": "c03541907d59874ca8a81f574258f6c0de8cbdc8" + "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.2.zip", + "reference": "8.x-2.2", + "shasum": "b5a84c6b85b9582e686ccf421295611d9dd52055" }, "require": { "drupal/core": "^8.8 || ^9" @@ -3457,8 +3474,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.1", - "datestamp": "1585251827", + "version": "8.x-2.2", + "datestamp": "1645187494", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -3594,18 +3611,18 @@ }, { "name": "drupal/dropzonejs", - "version": "2.5.0", - "version_normalized": "2.5.0.0", + "version": "2.6.0", + "version_normalized": "2.6.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/dropzonejs.git", - "reference": "8.x-2.5" + "reference": "8.x-2.6" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.5.zip", - "reference": "8.x-2.5", - "shasum": "9918bd8c3c62599ec701be3bbac986741e735859" + "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.6.zip", + "reference": "8.x-2.6", + "shasum": "3a14b26ade989e00bbbc9f6bbfa364fb5acb9367" }, "require": { "drupal/core": "^8.8 || ^9" @@ -3619,8 +3636,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-2.5", - "datestamp": "1614606376", + "version": "8.x-2.6", + "datestamp": "1647857808", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 39a00312f7439965cd363323d2027b53b6a9b518..afded3349f1b79b4ab0c00fe85e6d10387dea6b9 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => 'e84dd64613669ee59f663ea0db62b53e321ee2c8', + 'reference' => 'ac0e30f29859b960ce5fce6752376c2d329ff838', 'name' => 'osu-asc-webservices/d8-upstream', 'dev' => true, ), @@ -308,12 +308,12 @@ ), ), 'drupal/allowed_formats' => array( - 'pretty_version' => '1.3.0', - 'version' => '1.3.0.0', + 'pretty_version' => '1.5.0', + 'version' => '1.5.0.0', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/allowed_formats', 'aliases' => array(), - 'reference' => '8.x-1.3', + 'reference' => '8.x-1.5', 'dev_requirement' => false, ), 'drupal/anchor_link' => array( @@ -503,12 +503,12 @@ 'dev_requirement' => false, ), 'drupal/config_filter' => array( - 'pretty_version' => '1.8.0', - 'version' => '1.8.0.0', + 'pretty_version' => '1.9.0', + 'version' => '1.9.0.0', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/config_filter', 'aliases' => array(), - 'reference' => '8.x-1.8', + 'reference' => '8.x-1.9', 'dev_requirement' => false, ), 'drupal/config_ignore' => array( @@ -782,12 +782,12 @@ ), ), 'drupal/crop' => array( - 'pretty_version' => '2.1.0', - 'version' => '2.1.0.0', + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/crop', 'aliases' => array(), - 'reference' => '8.x-2.1', + 'reference' => '8.x-2.2', 'dev_requirement' => false, ), 'drupal/ctools' => array( @@ -818,12 +818,12 @@ ), ), 'drupal/dropzonejs' => array( - 'pretty_version' => '2.5.0', - 'version' => '2.5.0.0', + 'pretty_version' => '2.6.0', + 'version' => '2.6.0.0', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/dropzonejs', 'aliases' => array(), - 'reference' => '8.x-2.5', + 'reference' => '8.x-2.6', 'dev_requirement' => false, ), 'drupal/dropzonejs_eb_widget' => array( @@ -2101,7 +2101,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => 'e84dd64613669ee59f663ea0db62b53e321ee2c8', + 'reference' => 'ac0e30f29859b960ce5fce6752376c2d329ff838', 'dev_requirement' => false, ), 'pantheon-systems/quicksilver-pushback' => array( diff --git a/web/modules/allowed_formats/allowed_formats.info.yml b/web/modules/allowed_formats/allowed_formats.info.yml index cef7368645c6b0a656835cac4f70bf0ae5e400b9..95135c550aa8e4f35a8e9efc4ff7e42a70804e49 100644 --- a/web/modules/allowed_formats/allowed_formats.info.yml +++ b/web/modules/allowed_formats/allowed_formats.info.yml @@ -1,12 +1,12 @@ name: Allowed Formats description: Limit which text formats are available for each field instance. type: module -core_version_requirement: ^8.7.7 || ^9 +core_version_requirement: ^8.8 || ^9 dependencies: - drupal:field - drupal:filter -# Information added by Drupal.org packaging script on 2020-06-23 -version: '8.x-1.3' +# Information added by Drupal.org packaging script on 2022-03-23 +version: '8.x-1.5' project: 'allowed_formats' -datestamp: 1592909221 +datestamp: 1648060332 diff --git a/web/modules/allowed_formats/allowed_formats.module b/web/modules/allowed_formats/allowed_formats.module index bc2a3a42f850a9ad436f75eaf29b532e5d50b9fd..dbab0cab125bf26071aec26377801538e0d3f1f6 100644 --- a/web/modules/allowed_formats/allowed_formats.module +++ b/web/modules/allowed_formats/allowed_formats.module @@ -26,16 +26,33 @@ function allowed_formats_form_field_config_edit_form_alter(array &$form, FormSta $options[$format->id()] = $format->label(); } - $form['third_party_settings']['allowed_formats'] = [ + $settings = $field->getThirdPartySettings('allowed_formats'); + $form['third_party_settings']['allowed_formats']['allowed_formats'] = [ '#type' => 'checkboxes', '#title' => t('Allowed formats'), '#options' => $options, - '#default_value' => $field->getThirdPartySettings('allowed_formats'), + '#default_value' => !empty($settings['allowed_formats']) ? $settings['allowed_formats'] : [], '#description' => t('Restrict which text formats are allowed, given the user has the required permissions. If no text formats are selected, then all the ones the user has access to will be available.'), ]; + + $form['#validate'][] = 'allowed_formats_form_field_config_edit_form_validate'; } } +/** + * Validation handler for field_config_edit_form. + */ +function allowed_formats_form_field_config_edit_form_validate(array &$form, FormStateInterface $form_state) { + // Restructure options to store the value as a sequence. + $form_parents = [ + 'third_party_settings', + 'allowed_formats', + 'allowed_formats', + ]; + $value = $form_state->getValue($form_parents); + $form_state->setValue($form_parents, array_keys(array_filter($value))); +} + /** * Implements hook_field_widget_third_party_settings_form(). */ @@ -72,7 +89,7 @@ function allowed_formats_field_widget_form_alter(&$element, FormStateInterface $ // Read configuration if available. This is possible for bundle fields or // base fields overridden using a BaseFieldOverride. $field_configuration = $field_definition->getConfig($field_definition->getTargetBundle()); - $allowed_formats_setting = $field_configuration->getThirdPartySettings('allowed_formats'); + $allowed_formats_setting = $field_configuration->getThirdPartySetting('allowed_formats', 'allowed_formats'); } else { // Base fields don't support third party settings so use an ordinary @@ -81,11 +98,8 @@ function allowed_formats_field_widget_form_alter(&$element, FormStateInterface $ $allowed_formats_setting = $field_definition->getSetting('allowed_formats'); } - if (isset($allowed_formats_setting) && is_array($allowed_formats_setting)) { - $allowed_formats = array_filter($allowed_formats_setting); - if (!empty($allowed_formats)) { - $element['#allowed_formats'] = $allowed_formats; - } + if (!empty($allowed_formats_setting) && is_array($allowed_formats_setting)) { + $element['#allowed_formats'] = $allowed_formats_setting; } /** @var \Drupal\Core\Field\WidgetInterface $widget */ diff --git a/web/modules/allowed_formats/allowed_formats.post_update.php b/web/modules/allowed_formats/allowed_formats.post_update.php new file mode 100644 index 0000000000000000000000000000000000000000..6a7a5c10b0d56831abeae046a106a9fbb826a1ce --- /dev/null +++ b/web/modules/allowed_formats/allowed_formats.post_update.php @@ -0,0 +1,34 @@ +<?php + +/** + * @file + * Post update functions for Allowed Formats module. + */ + +use Drupal\field\Entity\FieldConfig; + +/** + * Updates existing configuration to store allowed_formats as sequence. + */ +function allowed_formats_post_update_store_allowed_formats_as_sequence() { + foreach (FieldConfig::loadMultiple() as $field_config) { + /** @var \Drupal\field\Entity\FieldConfig $field_config */ + if (in_array($field_config->getType(), _allowed_formats_field_types(), TRUE)) { + $allowed_formats = $field_config->getThirdPartySettings('allowed_formats'); + if (!empty($allowed_formats)) { + // Don't do anything if the configuration is already a sequence. + if (isset($allowed_formats['allowed_formats']) && is_array($allowed_formats['allowed_formats'])) { + continue; + } + // Unset existing configuration. + foreach ($allowed_formats as $key => $value) { + $field_config->unsetThirdPartySetting('allowed_formats', $key); + } + $field_config->setThirdPartySetting('allowed_formats', 'allowed_formats', array_values(array_filter($allowed_formats))); + $field_config->save(); + } + } + } + + return t('Allowed formats in field configuration has been updated.'); +} diff --git a/web/modules/allowed_formats/composer.json b/web/modules/allowed_formats/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..42b0ecaaeee7118c59735a474c1c418bab478f1f --- /dev/null +++ b/web/modules/allowed_formats/composer.json @@ -0,0 +1,37 @@ +{ + "name": "drupal/allowed_formats", + "description": "Limit which text formats are available for each field instance.", + "type": "drupal-module", + "homepage": "https://www.drupal.org/project/allowed_formats", + "license": "GPL-2.0-or-later", + "minimum-stability": "dev", + "authors": [ + { + "name": "Northern Commerce (formerly Digital Echidna)", + "homepage": "https://www.drupal.org/northern-commerce-formerly-digital-echidna", + "role": "Supporting organization" + }, + { + "name": "Jordan Thompson (nord102)", + "homepage": "https://www.drupal.org/u/nord102", + "role": "Maintainer" + }, + { + "name": "Wunder", + "homepage": "https://www.drupal.org/wunder", + "role": "Supporting organization" + }, + { + "name": "Florian Loretan (floretan)", + "homepage": "https://www.drupal.org/u/floretan", + "role": "Maintainer" + } + ], + "support": { + "issues": "https://www.drupal.org/project/issues/allowed_formats", + "source": "http://cgit.drupalcode.org/allowed_formats" + }, + "require": { + "drupal/core": "^8.8 || ^9" + } +} diff --git a/web/modules/allowed_formats/config/schema/allowed_formats.schema.yml b/web/modules/allowed_formats/config/schema/allowed_formats.schema.yml index 56a61824abf38a36a4ed558868684dd742e8116c..f1e96a7bd488b734db8a3144f04b93308a80ef19 100644 --- a/web/modules/allowed_formats/config/schema/allowed_formats.schema.yml +++ b/web/modules/allowed_formats/config/schema/allowed_formats.schema.yml @@ -1,9 +1,13 @@ field.field.*.*.*.third_party.allowed_formats: - type: sequence - label: Allowed formats - sequence: - type: string - label: Allowed format + type: mapping + label: 'Allowed formats configuration' + mapping: + allowed_formats: + type: sequence + label: Allowed formats + sequence: + type: string + label: Allowed format field.widget.third_party.allowed_formats: type: mapping diff --git a/web/modules/allowed_formats/tests/modules/allowed_formats_base_fields_test/allowed_formats_base_fields_test.info.yml b/web/modules/allowed_formats/tests/modules/allowed_formats_base_fields_test/allowed_formats_base_fields_test.info.yml index 6fba0b83508a7559200336a852ba62ea31e42dcd..366d4379b487a0f2927bc370dd638fef64a7f61b 100644 --- a/web/modules/allowed_formats/tests/modules/allowed_formats_base_fields_test/allowed_formats_base_fields_test.info.yml +++ b/web/modules/allowed_formats/tests/modules/allowed_formats_base_fields_test/allowed_formats_base_fields_test.info.yml @@ -7,7 +7,7 @@ dependencies: drupal:taxonomy drupal:allowed_formats -# Information added by Drupal.org packaging script on 2020-06-23 -version: '8.x-1.3' +# Information added by Drupal.org packaging script on 2022-03-23 +version: '8.x-1.5' project: 'allowed_formats' -datestamp: 1592909221 +datestamp: 1648060332 diff --git a/web/modules/allowed_formats/tests/src/Functional/AllowedFormatsTest.php b/web/modules/allowed_formats/tests/src/Functional/AllowedFormatsTest.php index ea2109be7276fd3986c9f09dcfbf6e0df3f9a045..ce22e98dfe189091071d0804286d0a44fc4d1bfb 100644 --- a/web/modules/allowed_formats/tests/src/Functional/AllowedFormatsTest.php +++ b/web/modules/allowed_formats/tests/src/Functional/AllowedFormatsTest.php @@ -5,6 +5,7 @@ use Drupal\filter\Entity\FilterFormat; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait; +use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Tests the basic functionality of Allowed Formats. @@ -15,6 +16,7 @@ class AllowedFormatsTest extends BrowserTestBase { // Provides shortcut method createVocabulary(). use TaxonomyTestTrait; + use StringTranslationTrait; /** * {@inheritdoc} @@ -53,8 +55,14 @@ class AllowedFormatsTest extends BrowserTestBase { protected function setUp() { parent::setUp(); - $this->adminUser = $this->drupalCreateUser(['administer filters', 'administer entity_test fields']); - $this->webUser = $this->drupalCreateUser(['administer entity_test content', 'administer taxonomy']); + $this->adminUser = $this->drupalCreateUser([ + 'administer filters', + 'administer entity_test fields', + ]); + $this->webUser = $this->drupalCreateUser([ + 'administer entity_test content', + 'administer taxonomy', + ]); } /** @@ -81,28 +89,30 @@ public function testAllowedFormats() { // Change the Allowed Formats settings of the test field created by // entity_test_install(). $this->drupalLogin($this->adminUser); - $this->drupalPostForm('entity_test/structure/entity_test/fields/entity_test.entity_test.field_test_text', [ - 'third_party_settings[allowed_formats][' . $format1->id() . ']' => TRUE, - 'third_party_settings[allowed_formats][' . $format2->id() . ']' => TRUE, - ], t('Save settings')); + $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.field_test_text'); + $this->submitForm([ + 'third_party_settings[allowed_formats][allowed_formats][' . $format1->id() . ']' => TRUE, + 'third_party_settings[allowed_formats][allowed_formats][' . $format2->id() . ']' => TRUE, + ], $this->t('Save settings')); // Display the creation form. $this->drupalLogin($this->webUser); $this->drupalGet('entity_test/add'); - $this->assertFieldByName("field_test_text[0][value]", NULL, 'Widget is displayed'); - $this->assertFieldByName("field_test_text[0][format]", NULL, 'Format selector is displayed'); + $this->assertSession()->fieldExists("field_test_text[0][value]"); + $this->assertSession()->fieldExists("field_test_text[0][format]"); // Change field to allow only one format. $this->drupalLogin($this->adminUser); - $this->drupalPostForm('entity_test/structure/entity_test/fields/entity_test.entity_test.field_test_text', [ - 'third_party_settings[allowed_formats][' . $format2->id() . ']' => FALSE, - ], t('Save settings')); + $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.field_test_text'); + $this->submitForm([ + 'third_party_settings[allowed_formats][allowed_formats][' . $format2->id() . ']' => FALSE, + ], $this->t('Save settings')); // We shouldn't have the 'format' selector since only one format is allowed. $this->drupalLogin($this->webUser); $this->drupalGet('entity_test/add'); - $this->assertFieldByName("field_test_text[0][value]", NULL, 'Widget is displayed'); - $this->assertNoFieldByName("field_test_text[0][format]", NULL, 'Format selector is not displayed'); + $this->assertSession()->fieldExists("field_test_text[0][value]"); + $this->assertSession()->fieldNotExists("field_test_text[0][format]"); } /** @@ -139,11 +149,11 @@ public function testBaseFields() { // available. $this->drupalLogin($this->webUser); $this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add'); - $this->assertFieldByName("description[0][value]", NULL, 'Widget is displayed'); - $this->assertFieldByName("description[0][format]", NULL, 'Format selector is displayed'); - $this->assertOption('edit-description-0-format--2', 'basic_html'); - $this->assertOption('edit-description-0-format--2', 'restricted_html'); - $this->assertOption('edit-description-0-format--2', 'full_html'); + $this->assertSession()->fieldExists("description[0][value]"); + $this->assertSession()->fieldExists("description[0][format]"); + $this->assertSession()->optionExists('edit-description-0-format--2', 'basic_html'); + $this->assertSession()->optionExists('edit-description-0-format--2', 'restricted_html'); + $this->assertSession()->optionExists('edit-description-0-format--2', 'full_html'); // Enable our test module, which disallows using the 'full_html' format // using the allowed_formats functionality. @@ -152,11 +162,11 @@ public function testBaseFields() { // Display the term creation form again and check that 'full_html' is // not available as expected. $this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add'); - $this->assertFieldByName("description[0][value]", NULL, 'Widget is displayed'); - $this->assertFieldByName("description[0][format]", NULL, 'Format selector is displayed'); - $this->assertOption('edit-description-0-format--2', 'basic_html'); - $this->assertOption('edit-description-0-format--2', 'restricted_html'); - $this->assertNoOption('edit-description-0-format--2', 'full_html'); + $this->assertSession()->fieldExists("description[0][value]"); + $this->assertSession()->fieldExists("description[0][format]"); + $this->assertSession()->optionExists('edit-description-0-format--2', 'basic_html'); + $this->assertSession()->optionExists('edit-description-0-format--2', 'restricted_html'); + $this->assertSession()->optionNotExists('edit-description-0-format--2', 'full_html'); } } diff --git a/web/modules/config_filter/config_filter.info.yml b/web/modules/config_filter/config_filter.info.yml index 1cef5653b692ce194efd318144973193a3c18ad0..9d50c853309506b428e7d066ca4e128e46324be5 100644 --- a/web/modules/config_filter/config_filter.info.yml +++ b/web/modules/config_filter/config_filter.info.yml @@ -5,7 +5,7 @@ core: 8.x core_version_requirement: ^8 || ^9 package: Config -# Information added by Drupal.org packaging script on 2020-10-28 -version: '8.x-1.8' +# Information added by Drupal.org packaging script on 2022-04-07 +version: '8.x-1.9' project: 'config_filter' -datestamp: 1603870063 +datestamp: 1649336058 diff --git a/web/modules/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml b/web/modules/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml index 231453b850f909f655432e46ba37b53af31cdfcd..32c02faf24a93b2896ab3c66bce8143f98eb587a 100644 --- a/web/modules/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml +++ b/web/modules/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml @@ -6,7 +6,7 @@ package: Testing dependencies: - config_filter:config_filter -# Information added by Drupal.org packaging script on 2020-10-28 -version: '8.x-1.8' +# Information added by Drupal.org packaging script on 2022-04-07 +version: '8.x-1.9' project: 'config_filter' -datestamp: 1603870063 +datestamp: 1649336058 diff --git a/web/modules/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml b/web/modules/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml index 7fec84b0ed2201e791d92042e719137f64189826..3d4835ec3999a81b68064d0fb177584460bf4d05 100644 --- a/web/modules/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml +++ b/web/modules/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml @@ -6,7 +6,7 @@ package: Testing dependencies: - config_filter:config_filter -# Information added by Drupal.org packaging script on 2020-10-28 -version: '8.x-1.8' +# Information added by Drupal.org packaging script on 2022-04-07 +version: '8.x-1.9' project: 'config_filter' -datestamp: 1603870063 +datestamp: 1649336058 diff --git a/web/modules/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php b/web/modules/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php index 3056cff58f8e126a433d2c23cbc0db8ee66dcd04..2e089d745375afd5a430d64d1a5556c7ce3d7100 100644 --- a/web/modules/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php +++ b/web/modules/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php @@ -13,6 +13,8 @@ */ class ConfigFilterStorageFactoryTest extends KernelTestBase { + use ConfigStorageTestTrait; + /** * {@inheritdoc} */ @@ -38,7 +40,7 @@ public function testServiceProvider() { // Config Filter makes the sync storage a filtered storage. $this->assertInstanceOf(FilteredStorageInterface::class, $this->container->get('config.storage.sync')); // Export the configuration. The pirate filter changes system.site. - $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync')); + $this->copyConfig($this->getExportStorage(), $this->getSyncFileStorage()); // The pirate filter changes the system.site when importing. $this->assertEquals(['system.site'], $this->configImporter()->getStorageComparer()->getChangelist('update')); diff --git a/web/modules/config_filter/tests/src/Kernel/ConfigStorageTestTrait.php b/web/modules/config_filter/tests/src/Kernel/ConfigStorageTestTrait.php index 3a6fee528e5cf73562335e855ffc1c88214caf8d..0d8e29309593534180c01114391c563aebffb4b3 100644 --- a/web/modules/config_filter/tests/src/Kernel/ConfigStorageTestTrait.php +++ b/web/modules/config_filter/tests/src/Kernel/ConfigStorageTestTrait.php @@ -113,7 +113,7 @@ protected function getExportStorage(): StorageInterface { // Create a filtered storage. $filtered = $this->container->get('config_filter.storage_factory')->getFilteredStorage($memory, ['config.storage.sync']); // Then write the core export storage to this new storage. - $this->copyConfig($unfiltered, $filtered); + self::replaceAllStorageContents($unfiltered, $filtered); return $memory; } @@ -155,4 +155,42 @@ protected static function assertStorageEquals(StorageInterface $expected, Storag } } + /** + * Copy the configuration from one storage to another and remove stale items. + * + * This method is the copy of how it worked prior to Drupal 9.4. + * See https://www.drupal.org/node/3273823 for more details. + * + * @param \Drupal\Core\Config\StorageInterface $source + * The configuration storage to copy from. + * @param \Drupal\Core\Config\StorageInterface $target + * The configuration storage to copy to. + */ + private static function replaceAllStorageContents(StorageInterface $source, StorageInterface &$target) { + // Make sure there is no stale configuration in the target storage. + foreach (array_merge([StorageInterface::DEFAULT_COLLECTION], $target->getAllCollectionNames()) as $collection) { + $target->createCollection($collection)->deleteAll(); + } + + // Copy all the configuration from all the collections. + foreach (array_merge([StorageInterface::DEFAULT_COLLECTION], $source->getAllCollectionNames()) as $collection) { + $source_collection = $source->createCollection($collection); + $target_collection = $target->createCollection($collection); + foreach ($source_collection->listAll() as $name) { + $data = $source_collection->read($name); + if ($data !== FALSE) { + $target_collection->write($name, $data); + } + else { + \Drupal::logger('config')->notice('Missing required data for configuration: %config', [ + '%config' => $name, + ]); + } + } + } + + // Make sure that the target is set to the same collection as the source. + $target = $target->createCollection($source->getCollectionName()); + } + } diff --git a/web/modules/crop/config/schema/crop.schema.yml b/web/modules/crop/config/schema/crop.schema.yml index e4285ac20b2ed4bef12c598073d55b6f15a6536c..abf43db9d5ea7493e17c250bfb38cf426ed8f99a 100644 --- a/web/modules/crop/config/schema/crop.schema.yml +++ b/web/modules/crop/config/schema/crop.schema.yml @@ -47,6 +47,9 @@ image.effect.crop_crop: crop_type: label: 'Crop type' type: string + automatic_crop_provider: + label: 'Automatic crop provider' + type: string crop.settings: type: config_object diff --git a/web/modules/crop/crop.info.yml b/web/modules/crop/crop.info.yml index 4417fea4399e644e620f50ffd8acfc02fb1e0a6f..836e552e367e7341f78f2860fe244714ddfc1839 100644 --- a/web/modules/crop/crop.info.yml +++ b/web/modules/crop/crop.info.yml @@ -6,8 +6,9 @@ type: module dependencies: - drupal:image - drupal:user +configure: crop.overview_types -# Information added by Drupal.org packaging script on 2020-03-26 -version: '8.x-2.1' +# Information added by Drupal.org packaging script on 2022-02-18 +version: '8.x-2.2' project: 'crop' -datestamp: 1585251788 +datestamp: 1645187495 diff --git a/web/modules/crop/modules/crop_media_entity/crop_media_entity.info.yml b/web/modules/crop/modules/crop_media_entity/crop_media_entity.info.yml index c041b23a3e679bd9085f13674543e5c4be55838b..bbf5e8e1b96cd08053e8d3028de804cea1b4ea97 100644 --- a/web/modules/crop/modules/crop_media_entity/crop_media_entity.info.yml +++ b/web/modules/crop/modules/crop_media_entity/crop_media_entity.info.yml @@ -5,7 +5,7 @@ package: Media type: module hidden: true -# Information added by Drupal.org packaging script on 2020-03-26 -version: '8.x-2.1' +# Information added by Drupal.org packaging script on 2022-02-18 +version: '8.x-2.2' project: 'crop' -datestamp: 1585251788 +datestamp: 1645187495 diff --git a/web/modules/crop/src/Entity/CropType.php b/web/modules/crop/src/Entity/CropType.php index fc6fdd9059a01b8d13dcc88a63f0c6d4295eb00e..249738cd59c6689bd833e3c00aec33264ddf50d7 100644 --- a/web/modules/crop/src/Entity/CropType.php +++ b/web/modules/crop/src/Entity/CropType.php @@ -130,6 +130,7 @@ public function validate() { /** * {@inheritdoc} */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator(); } diff --git a/web/modules/crop/src/Events/AutomaticCrop.php b/web/modules/crop/src/Events/AutomaticCrop.php new file mode 100644 index 0000000000000000000000000000000000000000..cc893d41fc2fd880ee8a77c79ac52f7ae25073af --- /dev/null +++ b/web/modules/crop/src/Events/AutomaticCrop.php @@ -0,0 +1,107 @@ +<?php + +namespace Drupal\crop\Events; + +use Drupal\Core\Image\ImageInterface; +use Drupal\crop\CropInterface; +use Drupal\crop\Entity\CropType; +use Symfony\Component\EventDispatcher\Event; + +/** + * Represents automatic crop action as event. + */ +class AutomaticCrop extends Event { + + /** + * The crop entity. + * + * @var \Drupal\crop\CropInterface|false + */ + protected $crop = FALSE; + + + /** + * The image resource to crop. + * + * @var \Drupal\Core\Image\ImageInterface + */ + protected $image; + + /** + * The crop type loaded. + * + * @var \Drupal\crop\Entity\CropType + */ + protected $cropType; + + /** + * All data required by crop providers. + * + * @var array + */ + protected $configuration; + + /** + * Constructs a EntitySelectionEvent object. + * + * @param \Drupal\Core\Image\ImageInterface $image + * @param \Drupal\crop\Entity\CropType $cropType + * @param $configuration + */ + public function __construct(ImageInterface $image, CropType $cropType, array $configuration) { + $this->image = $image; + $this->cropType = $cropType; + $this->configuration = $configuration; + } + + /** + * Set calculated crop instance. + * + * @param \Drupal\crop\CropInterface $crop + * The crop entity instance. + */ + public function setCrop(CropInterface $crop) { + $this->crop = $crop; + } + + /** + * Get crop instance. + * + * @return \Drupal\crop\CropInterface|false + * List of fallbacks. + */ + public function getCrop() { + return $this->crop; + } + + /** + * Get the crop type entity. + * + * @return \Drupal\crop\Entity\CropType + * The crop type entity loaded. + */ + public function getCropType() { + return $this->cropType; + } + + /** + * Get image to crop. + * + * @return \Drupal\Core\Image\ImageInterface + * The image resource. + */ + public function getImage() { + return $this->image; + } + + /** + * Get all configurations to generate automatic crop. + * + * @return array + * All data to be used by automatic crop providers. + */ + public function getConfiguration() { + return $this->configuration; + } + +} diff --git a/web/modules/crop/src/Events/AutomaticCropProviders.php b/web/modules/crop/src/Events/AutomaticCropProviders.php new file mode 100644 index 0000000000000000000000000000000000000000..05daad3fd1618efe9b02ce4b2e043b8fd6bd2337 --- /dev/null +++ b/web/modules/crop/src/Events/AutomaticCropProviders.php @@ -0,0 +1,49 @@ +<?php + +namespace Drupal\crop\Events; + +use Symfony\Component\EventDispatcher\Event; + +/** + * Collects "Automatic crop" providers. + */ +class AutomaticCropProviders extends Event { + + /** + * Automatic Crop provider list. + * + * @var array + */ + protected $providers = []; + + /** + * Adds provider. + * + * @param array $provider + * Register provider to providers list. + */ + public function registerProvider(array $provider) { + $this->providers[key($provider)] = current($provider); + } + + /** + * Sets automatic crop providers. + * + * @param array $providers + * List of automatic crop providers. + */ + public function setProviders(array $providers) { + $this->providers = $providers; + } + + /** + * Gets automatic crop providers. + * + * @return array + * List of providers. + */ + public function getProviders() { + return $this->providers; + } + +} diff --git a/web/modules/crop/src/Events/Events.php b/web/modules/crop/src/Events/Events.php new file mode 100644 index 0000000000000000000000000000000000000000..671f74adde288568031b19886abc9e5b7fd0deca --- /dev/null +++ b/web/modules/crop/src/Events/Events.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\crop\Events; + +/** + * Contains all events thrown by crop API. + */ +final class Events { + + /** + * The event to subscribe to add provider as manual crop fallback provider. + * + * @var string + */ + const AUTOMATIC_CROP_PROVIDERS = 'crop.automatic_crop_providers'; + + /** + * The event to subscribe to automatic crop generate for crop API. + * + * @var string + */ + const AUTOMATIC_CROP = 'crop.automatic_crop'; + +} diff --git a/web/modules/crop/src/Plugin/ImageEffect/CropEffect.php b/web/modules/crop/src/Plugin/ImageEffect/CropEffect.php index 5f41e6b7d6e000fdf88af3a5665244502f7f1641..f6930b67bebeacd34487c09065872ed61e8966b3 100644 --- a/web/modules/crop/src/Plugin/ImageEffect/CropEffect.php +++ b/web/modules/crop/src/Plugin/ImageEffect/CropEffect.php @@ -10,9 +10,13 @@ use Drupal\crop\CropInterface; use Drupal\crop\CropStorageInterface; use Drupal\crop\Entity\Crop; +use Drupal\crop\Events\AutomaticCrop; +use Drupal\crop\Events\AutomaticCropProviders; +use Drupal\crop\Events\Events; use Drupal\image\ConfigurableImageEffectBase; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Crops an image resource. @@ -40,11 +44,11 @@ class CropEffect extends ConfigurableImageEffectBase implements ContainerFactory protected $typeStorage; /** - * Crop entity. + * Crop entity or Automated Crop Plugin. * - * @var \Drupal\crop\CropInterface + * @var \Drupal\crop\CropInterface|false */ - protected $crop; + protected $crop = FALSE; /** * The image factory service. @@ -53,14 +57,30 @@ class CropEffect extends ConfigurableImageEffectBase implements ContainerFactory */ protected $imageFactory; + /** + * Event dispatcher service. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * The automatic crop providers list. + * + * @var array + */ + protected $automaticCropProviders; + /** * {@inheritdoc} */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger, CropStorageInterface $crop_storage, ConfigEntityStorageInterface $crop_type_storage, ImageFactory $image_factory) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger, CropStorageInterface $crop_storage, ConfigEntityStorageInterface $crop_type_storage, ImageFactory $image_factory, EventDispatcherInterface $event_dispatcher) { parent::__construct($configuration, $plugin_id, $plugin_definition, $logger); $this->storage = $crop_storage; $this->typeStorage = $crop_type_storage; $this->imageFactory = $image_factory; + $this->eventDispatcher = $event_dispatcher; + $this->automaticCropProviders = $this->getAutomaticCropProvidersList(); } /** @@ -74,7 +94,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('logger.factory')->get('image'), $container->get('entity_type.manager')->getStorage('crop'), $container->get('entity_type.manager')->getStorage('crop_type'), - $container->get('image.factory') + $container->get('image.factory'), + $container->get('event_dispatcher') ); } @@ -87,21 +108,24 @@ public function applyEffect(ImageInterface $image) { return FALSE; } - if ($crop = $this->getCrop($image)) { - $anchor = $crop->anchor(); - $size = $crop->size(); + $this->getCrop($image); + if (!$this->crop) { + return FALSE; + } - if (!$image->crop($anchor['x'], $anchor['y'], $size['width'], $size['height'])) { - $this->logger->error('Manual image crop failed using the %toolkit toolkit on %path (%mimetype, %width x %height)', [ + $anchor = $this->crop->anchor(); + $size = $this->crop->size(); + + if (!$image->crop($anchor['x'], $anchor['y'], $size['width'], $size['height'])) { + $this->logger->error('Manual image crop failed using the %toolkit toolkit on %path (%mimetype, %width x %height)', [ '%toolkit' => $image->getToolkitId(), '%path' => $image->getSource(), '%mimetype' => $image->getMimeType(), '%width' => $image->getWidth(), '%height' => $image->getHeight(), ] - ); - return FALSE; - } + ); + return FALSE; } return TRUE; @@ -126,6 +150,7 @@ public function getSummary() { public function defaultConfiguration() { return parent::defaultConfiguration() + [ 'crop_type' => NULL, + 'automatic_crop_provider' => NULL, ]; } @@ -133,19 +158,25 @@ public function defaultConfiguration() { * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { - $options = []; - foreach ($this->typeStorage->loadMultiple() as $type) { - $options[$type->id()] = $type->label(); - } - $form['crop_type'] = [ '#type' => 'select', - '#title' => t('Crop type'), + '#title' => $this->t('Crop type'), '#default_value' => $this->configuration['crop_type'], - '#options' => $options, - '#description' => t('Crop type to be used for the image style.'), + '#options' => $this->getCropTypeOptions(), + '#description' => $this->t('Crop type to be used for the image style.'), ]; + if (!empty($this->automaticCropProviders)) { + $form['automatic_crop_provider'] = [ + '#type' => 'select', + '#title' => $this->t('Automatic crop provider'), + '#empty_option' => $this->t("- Select a Provider -"), + '#options' => $this->automaticCropProviders, + '#default_value' => $this->configuration['automatic_crop_provider'], + '#description' => $this->t('The name of automatic crop provider to use if crop is not set for an image.'), + ]; + } + return $form; } @@ -155,6 +186,22 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { parent::submitConfigurationForm($form, $form_state); $this->configuration['crop_type'] = $form_state->getValue('crop_type'); + $this->configuration['automatic_crop_provider'] = $form_state->getValue('automatic_crop_provider'); + } + + /** + * Get the available cropType options list. + * + * @return array + * The cropType options list. + */ + public function getCropTypeOptions() { + $options = []; + foreach ($this->typeStorage->loadMultiple() as $type) { + $options[$type->id()] = $type->label(); + } + + return $options; } /** @@ -164,14 +211,19 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s * Image object. * * @return \Drupal\Core\Entity\EntityInterface|\Drupal\crop\CropInterface|false - * Crop entity or FALSE if crop doesn't exist. + * Crop entity or FALSE. */ protected function getCrop(ImageInterface $image) { - if (!isset($this->crop)) { - $this->crop = FALSE; - if ($crop = Crop::findCrop($image->getSource(), $this->configuration['crop_type'])) { - $this->crop = $crop; - } + if ($crop = Crop::findCrop($image->getSource(), $this->configuration['crop_type'])) { + $this->crop = $crop; + } + + if (!$this->crop && !empty($this->configuration['automatic_crop_provider'])) { + /** @var \Drupal\crop\Entity\CropType $crop_type */ + $crop_type = $this->typeStorage->load($this->configuration['crop_type']); + $automatic_crop_event = new AutomaticCrop($image, $crop_type, $this->configuration); + $this->eventDispatcher->dispatch(Events::AUTOMATIC_CROP, $automatic_crop_event); + $this->crop = $automatic_crop_event->getCrop(); } return $this->crop; @@ -185,11 +237,10 @@ public function transformDimensions(array &$dimensions, $uri) { if (!$crop instanceof CropInterface) { return; } - $size = $crop->size(); // The new image will have the exact dimensions defined for the crop effect. - $dimensions['width'] = $size['width']; - $dimensions['height'] = $size['height']; + $dimensions['width'] = $crop->size()['width']; + $dimensions['height'] = $crop->size()['height']; } /** @@ -205,4 +256,17 @@ public function calculateDependencies() { return $dependencies; } + /** + * Collect automatic crop providers. + * + * @return array + * All provider + */ + public function getAutomaticCropProvidersList() { + $event = new AutomaticCropProviders(); + $this->eventDispatcher->dispatch(Events::AUTOMATIC_CROP_PROVIDERS, $event); + + return $event->getProviders(); + } + } diff --git a/web/modules/crop/templates/crop-crop-summary.html.twig b/web/modules/crop/templates/crop-crop-summary.html.twig index 7ba7cc5c08fb4c7054d6db22c8b3dd723f5cc74c..94613bda282d2d4bfc606547853735fa4d59ae1d 100644 --- a/web/modules/crop/templates/crop-crop-summary.html.twig +++ b/web/modules/crop/templates/crop-crop-summary.html.twig @@ -18,4 +18,8 @@ {% trans %} uses <em>{{ data.crop_type|e }}</em> crop type {% endtrans %} + <br> + {% if data.automatic_crop_provider|length %} + <em>Automated Crop activated</em> + {%- endif %} {%- endif %} diff --git a/web/modules/crop/tests/src/Functional/CropFunctionalTest.php b/web/modules/crop/tests/src/Functional/CropFunctionalTest.php index 333db96c87b02f6c6434e8d1009b3e9af5dafbfc..5580b822c790b3d5ec8a7f77837073f6703c7359 100644 --- a/web/modules/crop/tests/src/Functional/CropFunctionalTest.php +++ b/web/modules/crop/tests/src/Functional/CropFunctionalTest.php @@ -125,7 +125,7 @@ public function testCropTypeCrud() { $this->testStyle = $this->container->get('entity_type.manager')->getStorage('image_style')->loadUnchanged($this->testStyle->id()); self::assertEquals($this->testStyle->getEffects()->count(), 1, 'One image effect added to test image style.'); $effect_configuration = $this->testStyle->getEffects()->getIterator()->current()->getConfiguration(); - self::assertEquals($effect_configuration['data'], ['crop_type' => $edit['id']], 'Manual crop effect uses correct image style.'); + self::assertEquals($effect_configuration['data'], ['crop_type' => $edit['id'], 'automatic_crop_provider' => NULL], 'Manual crop effect uses correct image style.'); // Tests the image URI is extended with shortened hash in case of image // style and corresponding crop existence. diff --git a/web/modules/dropzonejs/README.md b/web/modules/dropzonejs/README.md index 7af1a12dc59bfee3612fa6a40f7d9ade092cf7fe..696e212fca78c04b070b212f7135f15269086054 100644 --- a/web/modules/dropzonejs/README.md +++ b/web/modules/dropzonejs/README.md @@ -36,10 +36,15 @@ installed to the `libraries` folder automatically. #### The composer way 2 -Copy the following into the root `composer.json` file's `repository` key +Add a custom package to the root `composer.json` file. Its `repositories` key +looks like the following. ``` "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + }, { "type": "package", "package": { diff --git a/web/modules/dropzonejs/dropzonejs.info.yml b/web/modules/dropzonejs/dropzonejs.info.yml index 8ffbe6068375cd3f81df1ced422debeb7a9c6aa9..423817c9d1dc9e9aeff2e2ebafb565fa52e239e6 100644 --- a/web/modules/dropzonejs/dropzonejs.info.yml +++ b/web/modules/dropzonejs/dropzonejs.info.yml @@ -6,7 +6,7 @@ package: Media dependencies: - drupal:file -# Information added by Drupal.org packaging script on 2021-03-01 -version: '8.x-2.5' +# Information added by Drupal.org packaging script on 2022-03-21 +version: '8.x-2.6' project: 'dropzonejs' -datestamp: 1614606378 +datestamp: 1647857810 diff --git a/web/modules/dropzonejs/dropzonejs.libraries.yml b/web/modules/dropzonejs/dropzonejs.libraries.yml index 1a4fe857b5f427477947cbaf5adc11bffcf91cd5..dff51fe78648bb1a9da2b345efc117cb7470b81d 100644 --- a/web/modules/dropzonejs/dropzonejs.libraries.yml +++ b/web/modules/dropzonejs/dropzonejs.libraries.yml @@ -26,3 +26,10 @@ integration: - core/drupalSettings - core/underscore - dropzonejs/dropzonejs + +media_library: + version: VERSION + js: + js/dropzone.media_library.js: {} + dependencies: + - dropzonejs/integration diff --git a/web/modules/dropzonejs/dropzonejs.module b/web/modules/dropzonejs/dropzonejs.module index 7f44502ef50f30e32d5ea74a0dd33f1e73d7564c..004a256ca4dfd6976fcaafbd61518b32c4181ac9 100644 --- a/web/modules/dropzonejs/dropzonejs.module +++ b/web/modules/dropzonejs/dropzonejs.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\dropzonejs\Form\DropzoneJsUploadForm; /** * Implements hook_help(). @@ -113,3 +114,24 @@ function dropzonejs_library_info_alter(&$libraries, $extension) { } } } + +/** + * Implements hook_media_source_info_alter(). + */ +function dropzonejs_media_source_info_alter(array &$sources) { + if (isset($sources['image'])) { + $sources['image']['forms']['media_library_add'] = DropzoneJsUploadForm::class; + } + + if (isset($sources['video_file'])) { + $sources['video_file']['forms']['media_library_add'] = DropzoneJsUploadForm::class; + } + + if (isset($sources['audio_file'])) { + $sources['audio_file']['forms']['media_library_add'] = DropzoneJsUploadForm::class; + } + + if (isset($sources['file'])) { + $sources['file']['forms']['media_library_add'] = DropzoneJsUploadForm::class; + } +} diff --git a/web/modules/dropzonejs/js/dropzone.integration.js b/web/modules/dropzonejs/js/dropzone.integration.js index b30d11e7965e8c08c48f4b1f7dd4f2e46d11b454..e640cddac513db749eee84b7633b85357049a4fc 100644 --- a/web/modules/dropzonejs/js/dropzone.integration.js +++ b/web/modules/dropzonejs/js/dropzone.integration.js @@ -15,7 +15,7 @@ attach: function (context) { Dropzone.autoDiscover = false; - $('.dropzone-enable').each(function() { + $('.dropzone-enable', context).each(function () { var selector = $(this); selector.addClass('dropzone'); diff --git a/web/modules/dropzonejs/js/dropzone.media_library.js b/web/modules/dropzonejs/js/dropzone.media_library.js new file mode 100644 index 0000000000000000000000000000000000000000..4f620a1d787fbf0fd52c23a4dd15c86cd29932e0 --- /dev/null +++ b/web/modules/dropzonejs/js/dropzone.media_library.js @@ -0,0 +1,48 @@ +/** + * @file + * dropzonejs_eb_widget.common.js + * + * Bundles various dropzone eb widget behaviours. + */ + +(function ($, Drupal, drupalSettings) { + 'use strict'; + + Drupal.behaviors.dropzonejsPostIntegrationMediaLibrary = { + attach: function (context) { + if (typeof drupalSettings.dropzonejs.instances !== 'undefined') { + _.each(drupalSettings.dropzonejs.instances, function (item) { + if (typeof item.instance !== 'undefined') { + + var $form = $(item.instance.element).parents('form'); + + item.instance.on('queuecomplete', function () { + var dzInstance = item.instance; + var filesInQueue = dzInstance.getQueuedFiles(); + var acceptedFiles; + var i; + + if (filesInQueue.length === 0) { + acceptedFiles = dzInstance.getAcceptedFiles(); + + // Ensure that there are some files that should be submitted. + if (acceptedFiles.length > 0 && dzInstance.getUploadingFiles().length === 0) { + // First submit accepted files and clear them from list of + // dropped files afterwards. + $form.find('[id="auto_select_handler"]') + .trigger('auto_select_media_library_widget'); + + // Remove accepted files -> because they are submitted. + for (i = 0; i < acceptedFiles.length; i++) { + dzInstance.removeFile(acceptedFiles[i]); + } + } + } + }); + } + }); + } + } + }; + +}(jQuery, Drupal, drupalSettings)); diff --git a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml index 3c56c35769d31eba1d10e9dc70b5d9a877b9775e..a8da51c7c2171c420f9846f3d8df329f6ec1003e 100644 --- a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml +++ b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml @@ -9,7 +9,7 @@ dependencies: - entity_browser:entity_browser -# Information added by Drupal.org packaging script on 2021-03-01 -version: '8.x-2.5' +# Information added by Drupal.org packaging script on 2022-03-21 +version: '8.x-2.6' project: 'dropzonejs' -datestamp: 1614606378 +datestamp: 1647857810 diff --git a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php index 0c18472d48718d56e0d2f9ae4f68440b03b5005c..e4164b71f7d02c1a840977da22cc8810e8f3853e 100644 --- a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php +++ b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php @@ -131,7 +131,7 @@ protected function setLibraryDiscovery(LibraryDiscoveryInterface $library_discov * {@inheritdoc} */ public function defaultConfiguration() { - return [ + return array_merge(parent::defaultConfiguration(), [ 'upload_location' => 'public://[date:custom:Y]-[date:custom:m]', 'dropzone_description' => $this->t('Drop files here to upload them'), 'max_filesize' => Environment::getUploadMaxSize() / pow(Bytes::KILOBYTE, 2) . 'M', @@ -142,7 +142,7 @@ public function defaultConfiguration() { 'resize_quality' => 1, 'resize_method' => 'contain', 'thumbnail_method' => 'contain', - ] + parent::defaultConfiguration(); + ]); } /** diff --git a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php index 3d29558fcf4297ee89479713f07e2e72ff704be6..382e843e313b6af308bc332b958d61e1e1a7ec52 100644 --- a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php +++ b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php @@ -54,9 +54,9 @@ protected function setEntityDisplayRepository(EntityDisplayRepositoryInterface $ * {@inheritdoc} */ public function defaultConfiguration() { - return [ + return array_merge(parent::defaultConfiguration(), [ 'form_mode' => 'default', - ] + parent::defaultConfiguration(); + ]); } /** diff --git a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php index c50c568992af110a09d1d767912dfedee175b095..d619490d8a72fba4bff977ed789281026ee338c4 100644 --- a/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php +++ b/web/modules/dropzonejs/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php @@ -55,9 +55,9 @@ protected function setModuleHandler(ModuleHandlerInterface $moduleHandler) { * {@inheritdoc} */ public function defaultConfiguration() { - return [ + return array_merge(parent::defaultConfiguration(), [ 'media_type' => '', - ] + parent::defaultConfiguration(); + ]); } /** diff --git a/web/modules/dropzonejs/src/DropzoneJsUploadSave.php b/web/modules/dropzonejs/src/DropzoneJsUploadSave.php index 99e1817889b647d72c0f36f8de10e95f2fcc3774..9a300d4a6a9b7f1f160248f8936586f304ec2790 100644 --- a/web/modules/dropzonejs/src/DropzoneJsUploadSave.php +++ b/web/modules/dropzonejs/src/DropzoneJsUploadSave.php @@ -170,24 +170,29 @@ public function createFile($uri, $destination, $extensions, AccountProxyInterfac return FALSE; } - // Prepare destination. - if (!$this->prepareDestination($file, $destination)) { - $this->messenger->addError($this->t('The file could not be uploaded because the destination %destination is invalid.', ['%destination' => $destination])); - return FALSE; - } - - // Move uploaded files from PHP's upload_tmp_dir to destination. - $move_result = $this->fileSystem->move($uri, $file->getFileUri()); - if (!$move_result) { - $this->messenger->addError($this->t('File upload error. Could not move uploaded file.')); - - $this->logger->notice('Upload error. Could not move uploaded file %file to destination %destination.', ['%file' => $file->getFilename(), '%destination' => $file->getFileUri()]); - return FALSE; + if (!empty($destination)) { + // Prepare destination. + if (!$this->prepareDestination($file, $destination)) { + $this->messenger->addError($this->t('The file could not be uploaded because the destination %destination is invalid.', ['%destination' => $destination])); + return FALSE; + } + + // Move uploaded files from PHP's upload_tmp_dir to destination. + $move_result = $this->fileSystem->move($uri, $file->getFileUri()); + if (!$move_result) { + $this->messenger->addError($this->t('File upload error. Could not move uploaded file.')); + + $this->logger->notice('Upload error. Could not move uploaded file %file to destination %destination.', [ + '%file' => $file->getFilename(), + '%destination' => $file->getFileUri(), + ]); + return FALSE; + } + + // Set the permissions on the new file. + $this->fileSystem->chmod($file->getFileUri()); } - // Set the permissions on the new file. - $this->fileSystem->chmod($file->getFileUri()); - return $file; } diff --git a/web/modules/dropzonejs/src/Element/DropzoneJs.php b/web/modules/dropzonejs/src/Element/DropzoneJs.php index 48d24c3c4e749c6c632707790fccd641fa8146fd..2feae5e6da4a2ca218bf8f169d6a1e1368bd1535 100644 --- a/web/modules/dropzonejs/src/Element/DropzoneJs.php +++ b/web/modules/dropzonejs/src/Element/DropzoneJs.php @@ -76,9 +76,6 @@ public function getInfo() { '#theme' => 'dropzonejs', '#theme_wrappers' => ['form_element'], '#tree' => TRUE, - '#attached' => [ - 'library' => ['dropzonejs/integration'], - ], ]; } @@ -86,6 +83,8 @@ public function getInfo() { * Processes a dropzone upload element. */ public static function processDropzoneJs(&$element, FormStateInterface $form_state, &$complete_form) { + // Generate url and collect metadata for CSRF token to be up to date. + $generated_url = Url::fromRoute('dropzonejs.upload')->toString(TRUE); $element['uploaded_files'] = [ '#type' => 'hidden', // @todo Handle defaults. @@ -93,9 +92,10 @@ public static function processDropzoneJs(&$element, FormStateInterface $form_sta // If we send a url with a token through drupalSettings the placeholder // doesn't get replaced, because the actual scripts markup is not there // yet. So we pass this information through a data attribute. - '#attributes' => ['data-upload-path' => Url::fromRoute('dropzonejs.upload')->toString()], + '#attributes' => ['data-upload-path' => $generated_url->getGeneratedUrl()], ]; - + // Apply cacheable metadata to element. + $generated_url->applyTo($element); if (empty($element['#max_filesize'])) { $element['#max_filesize'] = Environment::getUploadMaxSize(); } @@ -129,6 +129,7 @@ public static function preRenderDropzoneJs(array $element) { // Convert the human size input to bytes, convert it to MB and round it. $max_size = round(Bytes::toInt($element['#max_filesize']) / pow(Bytes::KILOBYTE, 2), 2); + $element['#attached']['library'] = ['dropzonejs/integration']; $element['#attached']['drupalSettings']['dropzonejs'] = [ 'instances' => [ // Configuration keys are matched with DropzoneJS configuration diff --git a/web/modules/dropzonejs/src/Form/DropzoneJsUploadForm.php b/web/modules/dropzonejs/src/Form/DropzoneJsUploadForm.php new file mode 100644 index 0000000000000000000000000000000000000000..e485a9cd3651722bc1da650ee17256eb08bbf424 --- /dev/null +++ b/web/modules/dropzonejs/src/Form/DropzoneJsUploadForm.php @@ -0,0 +1,194 @@ +<?php + +namespace Drupal\dropzonejs\Form; + +use Drupal\Component\Utility\Bytes; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Url; +use Drupal\dropzonejs\DropzoneJsUploadSaveInterface; +use Drupal\media_library\Form\FileUploadForm; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Creates a form to create media entities from uploaded files. + */ +class DropzoneJsUploadForm extends FileUploadForm { + + /** + * DropzoneJS module upload save service. + * + * @var \Drupal\dropzonejs\DropzoneJsUploadSaveInterface + */ + protected $dropzoneJsUploadSave; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + $form = parent::create($container); + $form->setDropzoneJsUploadSave($container->get('dropzonejs.upload_save')); + return $form; + } + + /** + * Set the upload service. + * + * @param \Drupal\dropzonejs\DropzoneJsUploadSaveInterface $dropzoneJsUploadSave + * The upload service. + */ + protected function setDropzoneJsUploadSave(DropzoneJsUploadSaveInterface $dropzoneJsUploadSave) { + $this->dropzoneJsUploadSave = $dropzoneJsUploadSave; + } + + /** + * {@inheritdoc} + */ + protected function buildInputElement(array $form, FormStateInterface $form_state) { + $form = parent::buildInputElement($form, $form_state); + // Create a file item to get the upload validators. + $media_type = $this->getMediaType($form_state); + $item = $this->createFileItem($media_type); + $settings = $item->getFieldDefinition()->getSettings(); + $slots = $form['container']['upload']['#cardinality']; + $process = (array) $this->elementInfo->getInfoProperty('dropzonejs', '#process', []); + $form['container']['upload']['#type'] = 'dropzonejs'; + $form['container']['upload']['#process'] = array_merge(['::validateUploadElement'], $process); + $dropzone_specific_properties = [ + '#max_files' => $slots < 1 ? 0 : $slots, + '#max_filesize' => $settings['max_filesize'], + '#extensions' => $settings['file_extensions'], + '#dropzone_description' => $this->t('Drop files here to upload them'), + ]; + $form['container']['upload'] += $dropzone_specific_properties; + + $form['auto_select_handler'] = [ + '#type' => 'hidden', + '#name' => 'auto_select_handler', + '#id' => 'auto_select_handler', + '#attributes' => ['id' => 'auto_select_handler'], + '#submit' => ['::uploadButtonSubmit'], + '#executes_submit_callback' => TRUE, + '#ajax' => [ + 'callback' => '::updateFormCallback', + 'wrapper' => 'media-library-wrapper', + 'event' => 'auto_select_media_library_widget', + // Add a fixed URL to post the form since AJAX forms are automatically + // posted to <current> instead of $form['#action']. + // @todo Remove when https://www.drupal.org/project/drupal/issues/2504115 + // is fixed. + // Follow along with changes in \Drupal\media_library\Form\OEmbedForm. + 'url' => Url::fromRoute('media_library.ui'), + 'options' => [ + 'query' => $this->getMediaLibraryState($form_state)->all() + [ + FormBuilderInterface::AJAX_FORM_REQUEST => TRUE, + ], + ], + ], + ]; + + $form['#attached']['library'][] = 'dropzonejs/widget'; + $form['#attached']['library'][] = 'dropzonejs/media_library'; + + return $form; + } + + /** + * Validates the upload element. + * + * @param array $element + * The upload element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The processed upload element. + */ + public function validateUploadElement(array $element, FormStateInterface $form_state) { + if ($form_state::hasAnyErrors()) { + // When an error occurs during uploading files, remove all files so the + // user can re-upload the files. + $element['#value'] = []; + } + $values = $form_state->getValue('upload', []); + if (count($values['uploaded_files']) > $element['#cardinality'] && $element['#cardinality'] !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) { + $form_state->setError($element, $this->t('A maximum of @count files can be uploaded.', [ + '@count' => $element['#cardinality'], + ])); + $form_state->setValue('upload', []); + $element['#value'] = []; + } + return $element; + } + + /** + * Submit handler for the upload button, inside the managed_file element. + * + * @param array $form + * The form render array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + public function uploadButtonSubmit(array $form, FormStateInterface $form_state) { + $files = $this->getFiles($form, $form_state); + $this->processInputValues($files, $form, $form_state); + } + + /** + * Gets uploaded files. + * + * We implement this to allow child classes to operate on different entity + * type while still having access to the files in the validate callback here. + * + * @param array $form + * Form structure. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * Form state object. + * + * @return \Drupal\file\FileInterface[] + * Array of uploaded files. + */ + protected function getFiles(array $form, FormStateInterface $form_state) { + // Create a file item to get the upload validators. + $media_type = $this->getMediaType($form_state); + $item = $this->createFileItem($media_type); + + $settings = $item->getFieldDefinition()->getSettings(); + + $additional_validators = ['file_validate_size' => [Bytes::toInt($settings['max_filesize']), 0]]; + + $files = $form_state->get(['dropzonejs', $this->getFormId(), 'files']); + + if (!$files) { + $files = []; + } + + // We do some casting because $form_state->getValue() might return NULL. + foreach ((array) $form_state->getValue(['upload', 'uploaded_files'], []) as $file) { + if (file_exists($file['path'])) { + $entity = $this->dropzoneJsUploadSave->createFile( + $file['path'], + // Need to leave destination empty, because Media Library will handle + // the moving of the file to proper location. + '', + $settings['file_extensions'], + $this->currentUser(), + $additional_validators + ); + if ($entity) { + $files[] = $entity; + } + } + } + + if ($form['container']['upload']['#max_files']) { + $files = array_slice($files, -$form['container']['upload']['#max_files']); + } + + $form_state->set(['dropzonejs', $this->getFormId(), 'files'], $files); + + return $files; + } + +} diff --git a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml index 4a269f227225c58ec1fe93c80dd3c1848cc515c6..0447d3ac19121f4533af38a3c3c08d0be5739335 100644 --- a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml +++ b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml @@ -9,7 +9,7 @@ dependencies: - dropzonejs:dropzonejs - dropzonejs:dropzonejs_eb_widget -# Information added by Drupal.org packaging script on 2021-03-01 -version: '8.x-2.5' +# Information added by Drupal.org packaging script on 2022-03-21 +version: '8.x-2.6' project: 'dropzonejs' -datestamp: 1614606378 +datestamp: 1647857810