From c969ed65cf9ca3ea5b9b6544bbaa67898db0f5af Mon Sep 17 00:00:00 2001 From: bcweaver <brianweaver@gmail.com> Date: Thu, 18 Jul 2019 11:41:17 -0400 Subject: [PATCH] Update 'field_group': 1.0 --> 3.0-rc1 1.0 is no longer supported, by security team or otherwise --- composer.json | 2 +- composer.lock | 24 +- vendor/composer/installed.json | 24 +- web/modules/field_group/CHANGELOG.txt | 17 + web/modules/field_group/README.txt | 19 +- .../field_group.entity_display.schema.yml | 6 + ...up.field_group_formatter_plugin.schema.yml | 14 +- .../field_group_migrate.info.yml | 9 +- .../d6_field_group_entity_form_display.yml | 0 .../d6_field_group_entity_view_display.yml | 0 .../d7_field_group.yml | 0 .../FieldGroupEntityFormDisplay.php | 8 +- .../FieldGroupEntityViewDisplay.php | 8 +- .../migrate/destination/d7/FieldGroup.php | 12 +- .../Plugin/migrate/source/d6/FieldGroup.php | 30 +- .../Plugin/migrate/source/d7/FieldGroup.php | 21 +- .../tests/fixtures/drupal7.php | 228 ++++---- .../Migrate/d7/MigrateFieldGroupTest.php | 1 + .../src/Unit/Migrate/d7/FieldGroupTest.php | 4 +- .../field_group/css/field_group.field_ui.css | 7 +- web/modules/field_group/field_group.api.php | 152 +++++ web/modules/field_group/field_group.info.yml | 6 +- web/modules/field_group/field_group.install | 31 + .../field_group/field_group.libraries.yml | 3 + web/modules/field_group/field_group.module | 549 +++++++++++++----- .../field_group/field_group.services.yml | 2 +- .../formatters/accordion/accordion.js | 2 +- .../formatters/tabs/horizontal-tabs.css | 9 +- .../formatters/tabs/horizontal-tabs.js | 6 +- web/modules/field_group/includes/field_ui.inc | 332 ++++++----- web/modules/field_group/includes/helpers.inc | 64 -- .../field_group/js/field_group.field_ui.js | 31 +- .../src/Annotation/FieldGroupFormatter.php | 17 +- .../field_group/src/Element/Accordion.php | 21 +- .../field_group/src/Element/AccordionItem.php | 16 +- .../src/Element/HorizontalTabs.php | 126 +++- .../field_group/src/Element/HtmlElement.php | 22 +- .../field_group/src/Element/VerticalTabs.php | 85 +++ .../src/FieldGroupFormatterBase.php | 89 ++- .../src/FieldGroupFormatterInterface.php | 14 +- .../src/FieldGroupFormatterPluginManager.php | 23 +- web/modules/field_group/src/FieldgroupUi.php | 10 +- .../src/Form/FieldGroupAddForm.php | 151 +++-- .../src/Form/FieldGroupDeleteForm.php | 39 +- .../field_group/src/FormatterHelper.php | 34 ++ .../Derivative/FieldGroupLocalAction.php | 2 +- .../FieldGroupFormatter/Accordion.php | 40 +- .../FieldGroupFormatter/AccordionItem.php | 54 +- .../FieldGroupFormatter/Details.php | 54 +- .../FieldGroupFormatter/Fieldset.php | 54 +- .../FieldGroupFormatter/HtmlElement.php | 133 +++-- .../field_group/FieldGroupFormatter/Tab.php | 64 +- .../field_group/FieldGroupFormatter/Tabs.php | 79 +-- .../src/Routing/FieldGroupConverter.php | 4 +- .../src/Routing/RouteSubscriber.php | 46 +- .../field-group-html-element.html.twig | 4 +- web/modules/field_group/templates/theme.inc | 17 +- .../field_group_test.info.yml | 7 +- .../field_group_test/field_group_test.module | 17 +- .../src/Functional/EntityDisplayTest.php | 181 +++--- .../src/Functional/FieldGroupTestTrait.php | 16 +- .../FieldGroupWithoutFieldUiTest.php | 2 +- .../src/Functional/ManageDisplayTest.php | 41 +- .../FunctionalJavascript/FieldGroupUiTest.php | 24 +- 64 files changed, 2017 insertions(+), 1090 deletions(-) create mode 100644 web/modules/field_group/CHANGELOG.txt rename web/modules/field_group/contrib/field_group_migrate/{migration_templates => migrations}/d6_field_group_entity_form_display.yml (100%) rename web/modules/field_group/contrib/field_group_migrate/{migration_templates => migrations}/d6_field_group_entity_view_display.yml (100%) rename web/modules/field_group/contrib/field_group_migrate/{migration_templates => migrations}/d7_field_group.yml (100%) create mode 100644 web/modules/field_group/field_group.api.php create mode 100644 web/modules/field_group/field_group.install delete mode 100644 web/modules/field_group/includes/helpers.inc create mode 100644 web/modules/field_group/src/Element/VerticalTabs.php create mode 100644 web/modules/field_group/src/FormatterHelper.php diff --git a/composer.json b/composer.json index 729c1a3095..1cf6e8b9a4 100644 --- a/composer.json +++ b/composer.json @@ -123,7 +123,7 @@ "drupal/entity_reference_revisions": "1.3", "drupal/externalauth": "1.1", "drupal/features": "3.8", - "drupal/field_group": "1.0", + "drupal/field_group": "3.0-rc1", "drupal/field_permissions": "1.0-beta1", "drupal/file_browser": "1.1", "drupal/focal_point": "1.0-beta6", diff --git a/composer.lock b/composer.lock index afe7ff1122..b2e677c7df 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": "f915b3d06c6bf036ff097201bc919a2f", + "content-hash": "3caed5dbd094aa4540ec32282a537ca5", "packages": [ { "name": "alchemy/zippy", @@ -4704,17 +4704,17 @@ }, { "name": "drupal/field_group", - "version": "1.0.0", + "version": "3.0.0-rc1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/field_group.git", - "reference": "8.x-1.0" + "reference": "8.x-3.0-rc1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/field_group-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "e8aa3fae5c3c5dec84644bb577996938d638a611" + "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.0-rc1.zip", + "reference": "8.x-3.0-rc1", + "shasum": "e291b5468c834a344e9aa6cafd3a76171d473a22" }, "require": { "drupal/core": "*" @@ -4722,14 +4722,14 @@ "type": "drupal-module", "extra": { "branch-alias": { - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev" }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1510352885", + "version": "8.x-3.0-rc1", + "datestamp": "1558647185", "security-coverage": { - "status": "covered", - "message": "Covered by Drupal's security advisory policy" + "status": "not-covered", + "message": "RC releases are not covered by Drupal security advisories." } } }, @@ -4762,7 +4762,7 @@ "description": "Provides the field_group module.", "homepage": "https://www.drupal.org/project/field_group", "support": { - "source": "http://cgit.drupalcode.org/field_group" + "source": "https://git.drupalcode.org/project/field_group" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 13e8917023..16c9d039d4 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -4845,18 +4845,18 @@ }, { "name": "drupal/field_group", - "version": "1.0.0", - "version_normalized": "1.0.0.0", + "version": "3.0.0-rc1", + "version_normalized": "3.0.0.0-RC1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/field_group.git", - "reference": "8.x-1.0" + "reference": "8.x-3.0-rc1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/field_group-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "e8aa3fae5c3c5dec84644bb577996938d638a611" + "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.0-rc1.zip", + "reference": "8.x-3.0-rc1", + "shasum": "e291b5468c834a344e9aa6cafd3a76171d473a22" }, "require": { "drupal/core": "*" @@ -4864,14 +4864,14 @@ "type": "drupal-module", "extra": { "branch-alias": { - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev" }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1510352885", + "version": "8.x-3.0-rc1", + "datestamp": "1558647185", "security-coverage": { - "status": "covered", - "message": "Covered by Drupal's security advisory policy" + "status": "not-covered", + "message": "RC releases are not covered by Drupal security advisories." } } }, @@ -4905,7 +4905,7 @@ "description": "Provides the field_group module.", "homepage": "https://www.drupal.org/project/field_group", "support": { - "source": "http://cgit.drupalcode.org/field_group" + "source": "https://git.drupalcode.org/project/field_group" } }, { diff --git a/web/modules/field_group/CHANGELOG.txt b/web/modules/field_group/CHANGELOG.txt new file mode 100644 index 0000000000..a9d603fd15 --- /dev/null +++ b/web/modules/field_group/CHANGELOG.txt @@ -0,0 +1,17 @@ +8.3.0-beta1, 2017-11-10 +------------------- +- JS error: Modernizr is not defined. +- Add the new region property to the schema. +- Adding Multiple Fields wrapped by a Tabs Group cause maximum execution error. +- Branch tests are failing. +- . +- Creating Duplicate Fieldgroup Name Overwrites Existing Fieldgroup. +- Field groups are not compatible with field layout. Part 1: Make sure regions are changed when changing layout. +- Typo in Field Group Formatter Plugin HtmlElement::prerender. +- Revert "Issue #2846589 by huzooka: Typo in Field Group Formatter Plugin HtmlElement::prerender". +- Undefined index: form_display. +- Typo in Field Group Formatter Plugin HtmlElement::prerender. +- Replace all deprecated uses. +- MessageWarning: Invalid argument supplied for foreach() in field_group_info_groups() (line 663 of modules/contrib/field_group/field_group.module). +- Replace removed formBuilder->setError with formstate->setError. +- Undefined index: id in template_preprocess_fieldset() notice. diff --git a/web/modules/field_group/README.txt b/web/modules/field_group/README.txt index 2eb008f541..6c72570811 100644 --- a/web/modules/field_group/README.txt +++ b/web/modules/field_group/README.txt @@ -39,6 +39,23 @@ To submit bug reports and feature suggestions, or to track changes: 4. The field grouping done in managed display will be reflected on the view detail page of the entity, while that done in the managed_form_display will be reflected in the add/edit form of the entity. +-- Create field groups -- +This section explains how to create groups of fields according to the type chosen. + - Fieldsets : This group of fields makes the internal content in a fieldset. + It is possible to add a title and a caption (which appears at the bottom of the fieldset). + - Details : Similar to Fieldsets. You can configure them to be open (normal fieldset) or collapsed. + - Html element : This fieldgroup renders the inner content in a HTML element. + You can configure attributes and label element. +The following two groupings works differently because you must associate them with an other grouping. + - Accordions : This group of fields makes the child groups as a jQuery accordion. + As a first step you must create an Accordions group. You can set a label and choose an effect. + Then you can create an Accordion Item as a child. This group can contain fields. + - Tabs : This fieldgroup renders child groups in its own tabs wrapper. + As a first step you must create an Tabs group. You can set choose if you want that your tabs are show horizontally or vertically. + Then, you can create Tab as a child and choose one to be open by default. This group can contain fields. +For all groups, you can add id or classes. +You can also choose if you want to mark a group as required if one of his fields is require (except for Accordions and Tabs : you must passed by their children). + -- MAINTAINERS -- stalski - http://drupal.org/user/322618 @@ -47,4 +64,4 @@ swentel - http://drupal.org/user/107403 -- INSPIRATORS -- -yched - http://drupal.org/user/39567 \ No newline at end of file +yched - http://drupal.org/user/39567 diff --git a/web/modules/field_group/config/schema/field_group.entity_display.schema.yml b/web/modules/field_group/config/schema/field_group.entity_display.schema.yml index c47e78474b..a9fe072ec4 100644 --- a/web/modules/field_group/config/schema/field_group.entity_display.schema.yml +++ b/web/modules/field_group/config/schema/field_group.entity_display.schema.yml @@ -17,6 +17,9 @@ core.entity_view_display.*.*.*.third_party.field_group: parent_name: type: string label: 'The parent group of this group' + region: + type: string + label: 'The region of this group' weight: type: integer label: 'The weight of the group' @@ -42,6 +45,9 @@ core.entity_form_display.*.*.*.third_party.field_group: label: type: string label: Readable name of the group + region: + type: string + label: 'The region of this group' parent_name: type: string label: 'The parent group of this group' diff --git a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml index 82b8f274aa..c897f4aac9 100644 --- a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml +++ b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml @@ -55,6 +55,9 @@ field_group.field_group_formatter_plugin.html_element: label_element: type: string label: 'html element tag to be used for the label' + label_element_classes: + type: string + label: 'html classes to be used for the label' attributes: type: string label: 'html attributes for the element' @@ -86,6 +89,15 @@ field_group.field_group_formatter_plugin.tabs: type: field_group.field_group_formatter_plugin.base label: 'Mapping for the tab formatter settings' mapping: + formatter: + type: string + label: 'default state for the tabs' + description: + type: string + label: 'description of the tabs' + required_fields: + type: boolean + label: 'Mark for required fields' direction: type: string label: 'Direction of the tabs' @@ -102,4 +114,4 @@ field_group.field_group_formatter_plugin.base: label: 'Classes of the fieldgroup' id: type: string - label: 'Html id of the fieldgroup' \ No newline at end of file + label: 'Html id of the fieldgroup' diff --git a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml index 53f8c6e63f..96ef3018cf 100644 --- a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml +++ b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml @@ -1,14 +1,13 @@ name: 'Field Group Migrate' type: module description: 'Provides the ability to migrate field groups from D6/D7 to D8.' -package: Migrate -# version: VERSION +package: Migration # core: 8.x dependencies: - field_group:field_group -# Information added by Drupal.org packaging script on 2017-11-10 -version: '8.x-1.0' +# Information added by Drupal.org packaging script on 2019-05-23 +version: '8.x-3.0-rc1' core: '8.x' project: 'field_group' -datestamp: 1510352889 +datestamp: 1558647188 diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_form_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml similarity index 100% rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_form_display.yml rename to web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_view_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml similarity index 100% rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_view_display.yml rename to web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d7_field_group.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml similarity index 100% rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d7_field_group.yml rename to web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php index f0b4f3bf54..860f91ad36 100644 --- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php +++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php @@ -17,8 +17,8 @@ class FieldGroupEntityFormDisplay extends PerComponentEntityFormDisplay { /** * {@inheritdoc} */ - public function import(Row $row, array $old_destination_id_values = array()) { - $values = array(); + public function import(Row $row, array $old_destination_id_values = []) { + $values = []; // array_intersect_key() won't work because the order is important because // this is also the return value. foreach (array_keys($this->getIds()) as $id) { @@ -27,6 +27,10 @@ public function import(Row $row, array $old_destination_id_values = array()) { $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values[static::MODE_NAME]); if (!$entity->isNew()) { $settings = $row->getDestinationProperty('field_group'); + $settings += [ + 'region' => 'content', + 'parent_name' => '', + ]; $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings); if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) { $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id')); diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php index 2ef0a5d8d2..3277e934c3 100644 --- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php +++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php @@ -17,8 +17,8 @@ class FieldGroupEntityViewDisplay extends PerComponentEntityDisplay { /** * {@inheritdoc} */ - public function import(Row $row, array $old_destination_id_values = array()) { - $values = array(); + public function import(Row $row, array $old_destination_id_values = []) { + $values = []; // array_intersect_key() won't work because the order is important because // this is also the return value. foreach (array_keys($this->getIds()) as $id) { @@ -28,6 +28,10 @@ public function import(Row $row, array $old_destination_id_values = array()) { foreach ($row->getSourceProperty('view_modes') as $view_mode => $settings) { $entity = $this->getEntity($values['entity_type'], $values['bundle'], $view_mode); if (!$entity->isNew()) { + $settings += [ + 'region' => 'content', + 'parent_name' => '', + ]; $settings = array_merge($row->getDestinationProperty('field_group'), $settings); $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings); if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) { diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php index 1110f1889f..828715ffd8 100644 --- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php +++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php @@ -1,10 +1,5 @@ <?php -/** - * @file - * Contains \Drupal\field_group_migrate\Plugin\migrate\destination\d7\FieldGroup. - */ - namespace Drupal\field_group_migrate\Plugin\migrate\destination\d7; use Drupal\migrate\Plugin\migrate\destination\DestinationBase; @@ -23,8 +18,8 @@ class FieldGroup extends DestinationBase { /** * {@inheritdoc} */ - public function import(Row $row, array $old_destination_id_values = array()) { - $values = array(); + public function import(Row $row, array $old_destination_id_values = []) { + $values = []; // array_intersect_key() won't work because the order is important because // this is also the return value. foreach (array_keys($this->getIds()) as $id) { @@ -34,6 +29,9 @@ public function import(Row $row, array $old_destination_id_values = array()) { $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values['mode'], $values['type']); if (!$entity->isNew()) { $settings = $row->getDestinationProperty('settings'); + $settings += [ + 'region' => 'content', + ]; $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('group_name'), $settings); if (isset($settings['format_type']) && ($settings['format_type'] == 'hidden')) { $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('group_name')); diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php index ef53935fa4..6438e5fba6 100644 --- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php +++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php @@ -9,7 +9,9 @@ * Drupal 6 field_group source. * * @MigrateSource( - * id = "d6_field_group" + * id = "d6_field_group", + * source_module = "fieldgroup", + * destination_module = "field_group" * ) */ class FieldGroup extends DrupalSqlBase { @@ -19,14 +21,14 @@ class FieldGroup extends DrupalSqlBase { */ public function query() { $query = $this->select('content_group', 'g') - ->fields('g', [ - 'group_type', - 'type_name', - 'group_name', - 'label', - 'settings', - 'weight', - ]); + ->fields('g', [ + 'group_type', + 'type_name', + 'group_name', + 'label', + 'settings', + 'weight', + ]); return $query; } @@ -55,6 +57,9 @@ public function prepareRow(Row $row) { return parent::prepareRow($row); } + /** + * + */ protected function transformEntityFormDisplaySettings(Row $row) { $row->setSourceProperty('extracted_settings', $row->getSourceProperty('settings/form')); $source_settings = $row->getSourceProperty('extracted_settings'); @@ -96,6 +101,9 @@ protected function transformEntityFormDisplaySettings(Row $row) { $row->setSourceProperty('converted_settings', $settings); } + /** + * + */ protected function transformEntityViewDisplaySettings(Row $row) { $row->setSourceProperty('extracted_settings', $row->getSourceProperty('settings/display')); $view_modes = array_diff(array_keys($row->getSourceProperty('extracted_settings')), ['label', 'description', 'weight']); @@ -150,7 +158,7 @@ protected function transformEntityViewDisplaySettings(Row $row) { $view_mode = 'default'; } - // $row->setSourceProperty('view_modes/' . $view_mode, $settings); + // $row->setSourceProperty('view_modes/' . $view_mode, $settings);. $view_modes[$view_mode] = $settings; } @@ -180,7 +188,7 @@ public function fields() { 'group_name', 'label', 'settings', - 'weight' + 'weight', ]; return array_combine($fields, $fields); } diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php index dc69ec2bf5..4825c84594 100644 --- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php +++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php @@ -1,10 +1,5 @@ <?php -/** - * @file - * Contains \Drupal\field_group_migrate\Plugin\migrate\source\d7\FieldGroup. - */ - namespace Drupal\field_group_migrate\Plugin\migrate\source\d7; use Drupal\migrate\Row; @@ -14,7 +9,9 @@ * Drupal 7 field_group source. * * @MigrateSource( - * id = "d7_field_group" + * id = "d7_field_group", + * source_module = "field_group", + * destination_module = "field_group" * ) */ class FieldGroup extends DrupalSqlBase { @@ -33,14 +30,15 @@ public function prepareRow(Row $row) { $data = unserialize($row->getSourceProperty('data')); $format_settings = $data['format_settings'] + $data['format_settings']['instance_settings']; unset($format_settings['instance_settings']); - $settings = array( + $settings = [ 'children' => $data['children'], 'parent_name' => $row->getSourceProperty('parent_name'), 'weight' => $data['weight'], 'label' => $data['label'], 'format_settings' => $format_settings, 'format_type' => $data['format_type'], - ); + 'region' => 'content', + ]; switch ($data['format_type']) { case 'div': $settings['format_type'] = 'html_element'; @@ -67,7 +65,7 @@ public function prepareRow(Row $row) { break; case 'multipage': - // @todo Check if there is a better way to deal with this format type. + // @todo Check if there is a better way to deal with this format type. $settings['format_type'] = 'tab'; break; @@ -88,7 +86,7 @@ public function getIds() { * {@inheritdoc} */ public function fields() { - $fields = array( + $fields = [ 'id' => $this->t('ID'), 'identifier' => $this->t('Identifier'), 'group_name' => $this->t('Group name'), @@ -96,8 +94,9 @@ public function fields() { 'bundle' => $this->t('Bundle'), 'mode' => $this->t('View mode'), 'parent_name' => $this->t('Parent name'), + 'region' => $this->t('Region'), 'data' => $this->t('Data'), - ); + ]; return $fields; } diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php b/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php index f418f173a6..347b5f73ff 100644 --- a/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php +++ b/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php @@ -1,4 +1,5 @@ <?php + /** * @file * A database agnostic dump for testing purposes. @@ -8,140 +9,165 @@ $connection = Database::getConnection(); -$connection->schema()->createTable('field_group', array( - 'fields' => array( - 'id' => array( +$connection->schema()->createTable('field_group', [ + 'fields' => [ + 'id' => [ 'type' => 'serial', 'not null' => TRUE, 'size' => 'normal', - ), - 'identifier' => array( + ], + 'identifier' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '255', 'default' => '', - ), - 'group_name' => array( + ], + 'group_name' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '32', 'default' => '', - ), - 'entity_type' => array( + ], + 'entity_type' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '32', 'default' => '', - ), - 'bundle' => array( + ], + 'bundle' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '128', 'default' => '', - ), - 'mode' => array( + ], + 'mode' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '128', 'default' => '', - ), - 'parent_name' => array( + ], + 'parent_name' => [ 'type' => 'varchar', 'not null' => TRUE, 'length' => '32', 'default' => '', - ), - 'data' => array( + ], + 'data' => [ 'type' => 'blob', 'not null' => TRUE, 'size' => 'big', - ), - ), - 'primary key' => array( + ], + ], + 'primary key' => [ 'id', - ), - 'unique keys' => array( - 'identifier' => array( + ], + 'unique keys' => [ + 'identifier' => [ 'identifier', - ), - ), - 'indexes' => array( - 'group_name' => array( + ], + ], + 'indexes' => [ + 'group_name' => [ 'group_name', - ), - ), + ], + ], 'mysql_character_set' => 'utf8', -)); +]); $connection->insert('field_group') -->fields(array( - 'id', - 'identifier', - 'group_name', - 'entity_type', - 'bundle', - 'mode', - 'parent_name', - 'data', -)) -->values(array( - 'id' => '1', - 'identifier' => 'group_page|node|page|default', - 'group_name' => 'group_page', - 'entity_type' => 'node', - 'bundle' => 'page', - 'mode' => 'default', - 'parent_name' => '', - 'data' => 'a:5:{s:5:"label";s:10:"Node group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', -)) -->values(array( - 'id' => '2', - 'identifier' => 'group_user|user|user|default', - 'group_name' => 'group_user', - 'entity_type' => 'user', - 'bundle' => 'user', - 'mode' => 'default', - 'parent_name' => '', - 'data' => 'a:5:{s:5:"label";s:17:"User group parent";s:6:"weight";i:1;s:8:"children";a:0:{}s:11:"format_type";s:3:"div";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', -)) -->values(array( - 'id' => '3', - 'identifier' => 'group_user_child|user|user|default', - 'group_name' => 'group_user_child', - 'entity_type' => 'user', - 'bundle' => 'user', - 'mode' => 'default', - 'parent_name' => 'group_user', - 'data' => 'a:5:{s:5:"label";s:16:"User group child";s:6:"weight";i:99;s:8:"children";a:1:{i:0;s:12:"user_picture";}s:11:"format_type";s:4:"tabs";s:15:"format_settings";a:2:{s:5:"label";s:16:"User group child";s:17:"instance_settings";a:2:{s:7:"classes";s:16:"user-group-child";s:2:"id";s:33:"group_article_node_article_teaser";}}}', -)) -->values(array( - 'id' => '4', - 'identifier' => 'group_article|node|article|teaser', - 'group_name' => 'group_article', - 'entity_type' => 'node', - 'bundle' => 'article', - 'mode' => 'teaser', - 'parent_name' => '', - 'data' => 'a:5:{s:5:"label";s:10:"htab group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:1:{s:7:"classes";s:10:"htab-group";}}}', -)) -->values(array( - 'id' => '5', - 'identifier' => 'group_page|node|page|form', - 'group_name' => 'group_page', - 'entity_type' => 'node', - 'bundle' => 'page', - 'mode' => 'form', - 'parent_name' => '', - 'data' => 'a:5:{s:5:"label";s:15:"Node form group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', -)) -->values(array( - 'id' => '6', - 'identifier' => 'group_article|node|article|form', - 'group_name' => 'group_article', - 'entity_type' => 'node', - 'bundle' => 'article', - 'mode' => 'form', - 'parent_name' => '', - 'data' => 'a:5:{s:5:"label";s:15:"htab form group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', -)) -->execute(); + ->fields([ + 'id', + 'identifier', + 'group_name', + 'entity_type', + 'bundle', + 'mode', + 'parent_name', + 'data', + ]) + ->values([ + 'id' => '1', + 'identifier' => 'group_page|node|page|default', + 'group_name' => 'group_page', + 'entity_type' => 'node', + 'bundle' => 'page', + 'mode' => 'default', + 'parent_name' => '', + 'data' => 'a:5:{s:5:"label";s:10:"Node group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', + ]) + ->values([ + 'id' => '2', + 'identifier' => 'group_user|user|user|default', + 'group_name' => 'group_user', + 'entity_type' => 'user', + 'bundle' => 'user', + 'mode' => 'default', + 'parent_name' => '', + 'data' => 'a:5:{s:5:"label";s:17:"User group parent";s:6:"weight";i:1;s:8:"children";a:0:{}s:11:"format_type";s:3:"div";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', + ]) + ->values([ + 'id' => '3', + 'identifier' => 'group_user_child|user|user|default', + 'group_name' => 'group_user_child', + 'entity_type' => 'user', + 'bundle' => 'user', + 'mode' => 'default', + 'parent_name' => 'group_user', + 'data' => 'a:5:{s:5:"label";s:16:"User group child";s:6:"weight";i:99;s:8:"children";a:1:{i:0;s:12:"user_picture";}s:11:"format_type";s:4:"tabs";s:15:"format_settings";a:2:{s:5:"label";s:16:"User group child";s:17:"instance_settings";a:2:{s:7:"classes";s:16:"user-group-child";s:2:"id";s:33:"group_article_node_article_teaser";}}}', + ]) + ->values([ + 'id' => '4', + 'identifier' => 'group_article|node|article|teaser', + 'group_name' => 'group_article', + 'entity_type' => 'node', + 'bundle' => 'article', + 'mode' => 'teaser', + 'parent_name' => '', + 'data' => 'a:5:{s:5:"label";s:10:"htab group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:1:{s:7:"classes";s:10:"htab-group";}}}', + ]) + ->values([ + 'id' => '5', + 'identifier' => 'group_page|node|page|form', + 'group_name' => 'group_page', + 'entity_type' => 'node', + 'bundle' => 'page', + 'mode' => 'form', + 'parent_name' => '', + 'data' => 'a:5:{s:5:"label";s:15:"Node form group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', + ]) + ->values([ + 'id' => '6', + 'identifier' => 'group_article|node|article|form', + 'group_name' => 'group_article', + 'entity_type' => 'node', + 'bundle' => 'article', + 'mode' => 'form', + 'parent_name' => '', + 'data' => 'a:5:{s:5:"label";s:15:"htab form group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}', + ]) + ->execute(); + +$connection->insert('system') + ->fields([ + 'filename', + 'name', + 'type', + 'owner', + 'status', + 'bootstrap', + 'schema_version', + 'weight', + 'info', + ]) + ->values([ + 'filename' => 'sites/all/modules/field_group/field_group.module', + 'name' => 'field_group', + 'type' => 'module', + 'owner' => '', + 'status' => '1', + 'bootstrap' => '0', + 'schema_version' => '7008', + 'weight' => '1', + 'info' => 'a:12:{s:4:"name";s:11:"Field Group";s:11:"description";s:67:"Provides the ability to group your fields on both form and display.";s:7:"package";s:6:"Fields";s:12:"dependencies";a:2:{i:0;s:5:"field";i:1;s:6:"ctools";}s:4:"core";s:3:"7.x";s:5:"files";a:2:{i:0;s:25:"tests/field_group.ui.test";i:1;s:30:"tests/field_group.display.test";}s:7:"version";s:7:"7.x-1.5";s:7:"project";s:11:"field_group";s:9:"datestamp";s:10:"1452033709";s:5:"mtime";i:1486548096;s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}', + ]) + ->execute(); diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php index ba8e92a54a..e83c38d647 100644 --- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php +++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php @@ -117,4 +117,5 @@ public function testFieldGroup() { $field_group_settings = $entity->getThirdPartySettings('field_group'); $this->assertEmpty($field_group_settings); } + } diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php index 1150015080..5a43c27838 100644 --- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php +++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php @@ -2,14 +2,14 @@ namespace Drupal\Tests\field_group_migrate\Unit\Migrate\d7; -use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase; +use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase; /** * Tests D7 field group source plugin. * * @group field_group */ -class FieldGroupTest extends MigrateSqlSourceTestCase { +class FieldGroupTest extends MigrateSqlSourceTestBase { const PLUGIN_CLASS = 'Drupal\field_group_migrate\Plugin\migrate\source\d7\FieldGroup'; diff --git a/web/modules/field_group/css/field_group.field_ui.css b/web/modules/field_group/css/field_group.field_ui.css index 7584e99e34..9a57546898 100644 --- a/web/modules/field_group/css/field_group.field_ui.css +++ b/web/modules/field_group/css/field_group.field_ui.css @@ -1,4 +1,3 @@ - #field-overview tr.field-group .group-label, #field-display-overview tr.field-group .group-label { font-weight: bold; @@ -6,9 +5,9 @@ #field-overview tr.static-region, #field-display-overview tr.static-region { - background-color: #ddd; + background-color: #ddd; } #edit-refresh { - display:none; -} \ No newline at end of file + display: none; +} diff --git a/web/modules/field_group/field_group.api.php b/web/modules/field_group/field_group.api.php new file mode 100644 index 0000000000..0125f5b380 --- /dev/null +++ b/web/modules/field_group/field_group.api.php @@ -0,0 +1,152 @@ +<?php + +/** + * @file + * Hooks for the field_group module. + */ + +use Drupal\Core\Form\FormStateInterface; + +/** + * @addtogroup hooks + * @{ + */ + +/** + * Pre render the build of the field group element. + * + * @param array $element + * Group being rendered. + * @param object $group + * The Field group info. + * @param object $rendering_object + * The entity / form being rendered. + */ +function hook_field_group_pre_render(array &$element, &$group, &$rendering_object) { + // Add all field_group format types to the js settings. + $element['#attached']['drupalSettings']['field_group'] = [ + $group->format_type => [ + 'mode' => $group->mode, + 'context' => $group->context, + 'settings' => $group->format_settings, + ], + ]; + + $element['#weight'] = $group->weight; + + // Call the pre render function for the format type. + $manager = Drupal::service('plugin.manager.field_group.formatters'); + $plugin = $manager->getInstance([ + 'format_type' => $group->format_type, + 'configuration' => ['label' => $group->label, 'settings' => $group->format_settings], + 'group' => $group, + ]); + $plugin->preRender($element, $rendering_object); +} + +/** + * Alter the pre_rendered build of the field group element. + * + * @param array $element + * Group being rendered. + * @param object $group + * The Field group info. + * @param object $rendering_object + * The entity / form being rendered. + */ +function hook_field_group_pre_render_alter(array &$element, &$group, &$rendering_object) { + if ($group->format_type == 'htab') { + $element['#theme_wrappers'] = [ + 'container' => [ + '#attributes' => ['class' => 'foobar'], + ], + ]; + } +} + +/** + * Alter the pre_rendered build of the form. + * + * @param array $element + * Group being rendered. + */ +function hook_field_group_build_pre_render_alter(array &$element) { + $form_id = $element['#form_id']; + if ($form_id == 'my_example_form' && isset($element['group_example'])) { + // Add form states to the field group. + $element['group_example']['#states'] = [ + 'visible' => [ + ':input[name="field_are_you_ok"]' => ['value' => 'yes'], + ], + ]; + } +} + +/** + * Process the field group. + * + * @param array $element + * The element being processed. + * @param $group + * The group info. + * @param $complete_form + * The complete form. + */ +function hook_field_group_form_process(array &$element, &$group, &$complete_form) { + $element['#states'] = [ + 'visible' => [ + ':input[name="field_are_you_ok"]' => ['value' => 'yes'], + ], + ]; +} + +/** + * Alter the processed build of the group. + * + * @param array $element + * The element being processed. + * @param $group + * The group info. + * @param $complete_form + * The complete form. + */ +function hook_field_group_form_process_alter(array &$element, &$group, &$complete_form) { + $element['#states'] = [ + 'visible' => [ + ':input[name="field_are_you_ok"]' => ['value' => 'yes'], + ], + ]; +} + +/** + * Alter the form after all groups are processed. + * + * @param array $element + * The element being processed. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state + * @param $complete_form + * The complete form. + */ +function hook_field_group_form_process_build_alter(array &$element, FormStateInterface $form_state, &$complete_form) { + $element['group_example']['#states'] = [ + 'visible' => [ + ':input[name="field_are_you_ok"]' => ['value' => 'yes'], + ], + ]; +} + +/** + * Hook into the deletion event of a fieldgroup. + * + * @param $group + * The deleted group. + */ +function hook_field_group_delete_field_group($group) { + // Extra cleanup code. +} + + +/** + * @} End of "addtogroup hooks". + */ diff --git a/web/modules/field_group/field_group.info.yml b/web/modules/field_group/field_group.info.yml index 5654d7f35f..d1c746ca45 100644 --- a/web/modules/field_group/field_group.info.yml +++ b/web/modules/field_group/field_group.info.yml @@ -6,8 +6,8 @@ package : Fields dependencies: - drupal:field -# Information added by Drupal.org packaging script on 2017-11-10 -version: '8.x-1.0' +# Information added by Drupal.org packaging script on 2019-05-23 +version: '8.x-3.0-rc1' core: '8.x' project: 'field_group' -datestamp: 1510352889 +datestamp: 1558647188 diff --git a/web/modules/field_group/field_group.install b/web/modules/field_group/field_group.install new file mode 100644 index 0000000000..7213f09bc4 --- /dev/null +++ b/web/modules/field_group/field_group.install @@ -0,0 +1,31 @@ +<?php + +/** + * @file + * Update hooks for the Field Group module. + */ + +/** + * Set the `region` portion of each field group. + */ +function field_group_update_8301() { + foreach (['entity_form_display', 'entity_view_display'] as $entity_type) { + foreach (\Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple() as $display) { + /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */ + if (in_array('field_group', $display->getThirdPartyProviders())) { + $field_groups = $display->getThirdPartySettings('field_group'); + $updated = FALSE; + foreach ($field_groups as $group_name => $data) { + if (!isset($data['region'])) { + $data['region'] = 'content'; + $display->setThirdPartySetting('field_group', $group_name, $data); + $updated = TRUE; + } + } + if ($updated) { + $display->save(); + } + } + } + } +} diff --git a/web/modules/field_group/field_group.libraries.yml b/web/modules/field_group/field_group.libraries.yml index 01f43f6ac2..e09631b7ce 100644 --- a/web/modules/field_group/field_group.libraries.yml +++ b/web/modules/field_group/field_group.libraries.yml @@ -47,6 +47,8 @@ formatter.tabs: version: VERSION js: formatters/tabs/tabs.js: {} + dependencies: + - core/modernizr element.horizontal_tabs: version: VERSION @@ -58,3 +60,4 @@ element.horizontal_tabs: formatters/tabs/horizontal-tabs.css: {} dependencies: - core/drupal.collapse + - core/modernizr diff --git a/web/modules/field_group/field_group.module b/web/modules/field_group/field_group.module index e85c489e25..b2711b2408 100644 --- a/web/modules/field_group/field_group.module +++ b/web/modules/field_group/field_group.module @@ -5,6 +5,8 @@ * Allows administrators to attach custom fields to fieldable types. */ +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\ds\Ds; use Drupal\Core\Entity\ContentEntityFormInterface; use Drupal\Core\Entity\Display\EntityDisplayInterface; use Drupal\Core\Entity\Entity\EntityFormDisplay; @@ -13,8 +15,22 @@ use Drupal\Core\Form\ConfirmFormInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; +use Drupal\field_group\Element\VerticalTabs; -require_once __DIR__ . '/includes/helpers.inc'; +/** + * Implements hook_help(). + */ +function field_group_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + case 'help.page.field_group': + $output = '<h3>' . t('About') . '</h3>'; + $output .= '<p>' . t('Fieldgroup will, as the name implies, group fields together. All fieldable entities will have the possibility to add groups to wrap their fields together. Fieldgroup comes with default HTML wrappers like vertical tabs, horizontal tabs, accordions, fieldsets or div wrappers.') . '</p>'; + $output .= '<p>' . t('The field group project is a follow-up on the field group module in <a href="@linkcck">CCK</a>. The release will only exist for Drupal 7 release and higher, so since the existence of the Fields API in core.</br>By moving field group to a separate module, this may open some new perspectives.', ['@linkcck' => 'http://drupal.org/project/cck']) . '</p>'; + $output .= '<h3>' . t('More Information') . '</h3>'; + $output .= '<p>' . t('For more information about this module please visit the <a href="@link">module page</a>.', ['@link' => 'https://www.drupal.org/project/field_group']) . '</p>'; + return $output; + } +} /** * Implements hook_theme_registry_alter(). @@ -23,7 +39,7 @@ function field_group_theme_registry_alter(&$theme_registry) { // Inject field_group_build_entity_groups in all entity theming functions. $entity_info = Drupal::entityTypeManager()->getDefinitions(); - $entity_types = array(); + $entity_types = []; foreach ($entity_info as $entity_type_id => $entity_type) { if ($route_name = $entity_type->get('field_ui_base_route')) { $entity_types[] = $entity_type_id; @@ -47,36 +63,32 @@ function field_group_theme_registry_alter(&$theme_registry) { * Implements hook_theme(). */ function field_group_theme() { - return array( - 'horizontal_tabs' => array( + return [ + 'horizontal_tabs' => [ 'render element' => 'element', 'template' => 'horizontal-tabs', 'file' => 'templates/theme.inc', - ), - 'field_group_accordion_item' => array( + ], + 'field_group_accordion_item' => [ 'render element' => 'element', 'template' => 'field-group-accordion-item', 'file' => 'templates/theme.inc', - ), - 'field_group_accordion' => array( + ], + 'field_group_accordion' => [ 'render element' => 'element', 'template' => 'field-group-accordion', 'file' => 'templates/theme.inc', - ), - 'field_group_html_element' => array( + ], + 'field_group_html_element' => [ 'render element' => 'element', 'template' => 'field-group-html-element', 'file' => 'templates/theme.inc', - ), - ); + ], + ]; } /** * Implements hook_theme_suggestions_alter(). - * - * @param array $suggestions - * @param array $variables - * @param $hook */ function field_group_theme_suggestions_alter(array &$suggestions, array $variables, $hook) { switch ($hook) { @@ -86,9 +98,9 @@ function field_group_theme_suggestions_alter(array &$suggestions, array $variabl case 'field_group_html_element': $element = $variables['element']; - $name = $element['#group_name']; - $entity_type = $element['#entity_type']; - $bundle = $element['#bundle']; + $name = !empty($element['#group_name']) ? $element['#group_name'] : NULL; + $entity_type = !empty($element['#entity_type']) ? $element['#entity_type'] : NULL; + $bundle = !empty($element['#bundle']) ? $element['#bundle'] : NULL; $wrapper = ''; if (isset($element['#wrapper_element'])) { @@ -96,26 +108,58 @@ function field_group_theme_suggestions_alter(array &$suggestions, array $variabl $suggestions[] = $hook . '__' . $wrapper; } - $suggestions[] = $hook . '__' . $entity_type; - $suggestions[] = $hook . '__' . $bundle; - $suggestions[] = $hook . '__' . $name; + if (!empty($entity_type)) { + $suggestions[] = $hook . '__' . $entity_type; + } + if (!empty($bundle)) { + $suggestions[] = $hook . '__' . $bundle; + } + if (!empty($name)) { + $suggestions[] = $hook . '__' . $name; + } - if ($wrapper) { + if ($wrapper && !empty($entity_type)) { $suggestions[] = $hook . '__' . $entity_type . '__' . $wrapper; } - $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle; - $suggestions[] = $hook . '__' . $entity_type . '__' . $name; + if (!empty($entity_type) && !empty($bundle)) { + $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle; + } + if (!empty($entity_type) && !empty($name)) { + $suggestions[] = $hook . '__' . $entity_type . '__' . $name; + } - if ($wrapper) { + if ($wrapper && !empty($entity_type) && !empty($bundle)) { $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $wrapper; } - $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $name; + if (!empty($entity_type) && !empty($bundle) && !empty($name)) { + $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $name; + } break; } } +/** + * Implements hook_element_info_alter(). + */ +function field_group_element_info_alter(array &$info) { + // Core does not support #group options on vertical tabs. Add support for it. + if (isset($info['vertical_tabs'])) { + + if (!isset($info['vertical_tabs']['#process'])) { + $info['vertical_tabs']['#process'] = []; + } + + if (!isset($info['vertical_tabs']['#pre_render'])) { + $info['vertical_tabs']['#pre_render'] = []; + } + + $info['vertical_tabs']['#process'][] = [VerticalTabs::class, 'processGroup']; + $info['vertical_tabs']['#pre_render'][] = [VerticalTabs::class, 'preRenderGroup']; + } +} + /** * Implements hook_form_FORM_ID_alter(). * Using hook_form_field_ui_form_display_overview_form_alter. @@ -141,7 +185,7 @@ function field_group_field_info_max_weight($entity_type, $bundle, $context, $con $groups = field_group_info_groups($entity_type, $bundle, $context, $context_mode); - $weights = array(); + $weights = []; foreach ($groups as $group) { $weights[] = $group->weight; } @@ -157,24 +201,24 @@ function field_group_form_alter(array &$form, FormStateInterface $form_state) { if ($form_object instanceof ContentEntityFormInterface && !$form_object instanceof ConfirmFormInterface) { /** - * @var EntityFormDisplayInterface $form_display + * @var \Drupal\Core\Entity\Entity\EntityFormDisplayInterface $form_display */ $storage = $form_state->getStorage(); if (!empty($storage['form_display'])) { $form_display = $storage['form_display']; $entity = $form_object->getEntity(); - $context = array( + $context = [ 'entity_type' => $entity->getEntityTypeId(), 'bundle' => $entity->bundle(), 'entity' => $entity, 'context' => 'form', 'display_context' => 'form', 'mode' => $form_display->getMode(), - ); + ]; field_group_attach_groups($form, $context); - $form['#pre_render'][] = 'field_group_form_pre_render'; + $form['#process'][] = 'field_group_form_process'; } } @@ -195,7 +239,7 @@ function field_group_inline_entity_form_entity_form_alter(&$entity_form, FormSta ]; field_group_attach_groups($entity_form, $context); - $entity_form['#pre_render'][] = 'field_group_form_pre_render'; + $entity_form['#process'][] = 'field_group_form_process'; } /** @@ -203,13 +247,13 @@ function field_group_inline_entity_form_entity_form_alter(&$entity_form, FormSta */ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityDisplayInterface $display) { - $context = array( + $context = [ 'entity_type' => $display->getTargetEntityTypeId(), 'bundle' => $entity->bundle(), 'entity' => $entity, 'display_context' => 'view', 'mode' => $display->getMode(), - ); + ]; field_group_attach_groups($build, $context); @@ -217,11 +261,11 @@ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityD // Add a prerender. if (empty($build['#theme'])) { - $ds_enabled = false; + $ds_enabled = FALSE; if (Drupal::moduleHandler()->moduleExists('ds')) { // Check if DS is enabled for this display. - if ($display->getThirdPartySetting('ds', 'layout') && !Drupal\ds\Ds::isDisabled()) { - $ds_enabled = true; + if ($display->getThirdPartySetting('ds', 'layout') && !Ds::isDisabled()) { + $ds_enabled = TRUE; } } @@ -234,70 +278,181 @@ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityD /** * Pre render callback for rendering groups. - * @see field_group_field_attach_form - * @param $element Form that is being rendered. + * + * @param array $element + * Form that is being rendered. + * + * @deprecated Use field_group_form_process instead. + */ +function field_group_form_pre_render(array $element) { + return field_group_form_process($element); +} + +/** + * Process callback for field groups. + * + * @param array $element + * Form that is being processed. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $form + * The complete form structure. + * + * @return array */ -function field_group_form_pre_render($element) { - if (empty($element['#field_group_form_pre_render'])) { - $element['#field_group_form_pre_render'] = TRUE; - field_group_build_entity_groups($element, 'form'); +function field_group_form_process(array &$element, FormStateInterface $form_state = NULL, array &$form = []) { + if (empty($element['#field_group_form_process'])) { + $element['#field_group_form_process'] = TRUE; + if (empty($element['#fieldgroups'])) { + return $element; + } + + // Create all groups and keep a flat list of references to these groups. + $group_references = []; + foreach ($element['#fieldgroups'] as $group_name => $group) { + if (!isset($element[$group_name])) { + $element[$group_name] = []; + } + + $group_parents = $element['#array_parents']; + $group_parents[] = empty($group->parent_name) ? $group->region : $group->parent_name; + $group_references[$group_name] = &$element[$group_name]; + $element[$group_name]['#group'] = implode('][', $group_parents); + + // Use array parents to set the group name. This will cover multilevel forms (eg paragraphs). + $parents = $element['#array_parents']; + $parents[] = $group_name; + $element[$group_name]['#parents'] = $parents; + $group_children_parent_group = implode('][', $parents); + foreach ($group->children as $child) { + $element[$child]['#group'] = $group_children_parent_group; + } + } + + foreach ($element['#fieldgroups'] as $group_name => $group) { + $field_group_element = &$element[$group_name]; + + // Let modules define their wrapping element. + // Note that the group element has no properties, only elements. + foreach (Drupal::moduleHandler()->getImplementations('field_group_form_process') as $module) { + // The intention here is to have the opportunity to alter the + // elements, as defined in hook_field_group_formatter_info. + // Note, implement $element by reference! + $function = $module . '_field_group_form_process'; + $function($field_group_element, $group, $element); + } + + // Allow others to alter the pre_render. + Drupal::moduleHandler()->alter('field_group_form_process', $field_group_element, $group, $element); + } + + // Allow others to alter the complete processed build. + Drupal::moduleHandler()->alter('field_group_form_process_build', $element, $form_state, $form); } + return $element; } /** * Pre render callback for rendering groups on entities without theme hook. - * @param $element + * + * @param array $element * Entity being rendered. */ -function field_group_entity_view_pre_render($element) { +function field_group_entity_view_pre_render(array $element) { field_group_build_entity_groups($element, 'view'); return $element; } +/** + * Implements hook_field_group_form_process(). + */ +function field_group_field_group_form_process(array &$element, &$group, &$complete_form) { + // Add all field_group format types to the js settings. + $element['#attached']['drupalSettings']['field_group'] = [ + $group->format_type => [ + 'mode' => $group->mode, + 'context' => $group->context, + 'settings' => $group->format_settings, + ], + ]; + + $element['#weight'] = $group->weight; + + // Call the pre render function for the format type. + $manager = Drupal::service('plugin.manager.field_group.formatters'); + $plugin = $manager->getInstance([ + 'format_type' => $group->format_type, + 'configuration' => ['label' => $group->label, 'settings' => $group->format_settings], + 'group' => $group, + ]); + if ($plugin) { + $plugin->process($element, $complete_form); + } +} + /** * Implements hook_field_group_pre_render(). * - * @param Array $element + * @param array $element * Group beïng rendered. - * @param Object $group + * @param object $group * The Field group info. * @param $rendering_object * The entity / form beïng rendered */ function field_group_field_group_pre_render(&$element, &$group, &$rendering_object) { - // Add all field_group format types to the js settings. - $element['#attached']['drupalSettings']['field_group'] = array( + $element['#attached']['drupalSettings']['field_group'] = [ $group->format_type => [ 'mode' => $group->mode, 'context' => $group->context, 'settings' => $group->format_settings, ], - ); + ]; $element['#weight'] = $group->weight; // Call the pre render function for the format type. $manager = Drupal::service('plugin.manager.field_group.formatters'); - $plugin = $manager->getInstance(array( + $plugin = $manager->getInstance([ 'format_type' => $group->format_type, - 'configuration' => array('label' => $group->label, 'settings' => $group->format_settings), + 'configuration' => [ + 'label' => $group->label, + 'settings' => $group->format_settings, + ], 'group' => $group, - )); - $plugin->preRender($element, $rendering_object); + ]); + if ($plugin) { + $plugin->preRender($element, $rendering_object); + } +} +/** + * Implements hook_field_group_form_process_build_alter(). + * + * @param array $element + * Element being processed. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $form + * The complete form structure. + */ +function field_group_field_group_form_process_build_alter(array &$element, $form_state = NULL, &$form = []) { + $groups = array_keys($element['#fieldgroups']); + field_group_remove_empty_form_groups($element, $groups, $element['#entity_type']); } /** * Implements hook_field_group_build_pre_render_alter(). - * @param Array $elements by address. + * + * @param array $elements + * By address.field_group_entity_display_build_alter */ function field_group_field_group_build_pre_render_alter(& $element) { - // Someone is doing a node view, in a node view. Reset content. if (isset($element['#node']->content) && count($element['#node']->content) > 0) { - $element['#node']->content = array(); + $element['#node']->content = []; } $display = isset($element['#view_mode']); @@ -307,23 +462,26 @@ function field_group_field_group_build_pre_render_alter(& $element) { if ($display) { field_group_remove_empty_display_groups($element, $groups); } + // Remove all empty groups on the form. else { - // Fix the problem on forms with additional settings. - field_group_remove_empty_form_groups('form', $element, $groups, $element['#fieldgroups'], $element['#entity_type']); + field_group_remove_empty_form_groups($element, $groups, $element['#entity_type']); } - } /** * Attach groups to the (form) build. * - * @param Array $element + * @param array $element * The part of the form. - * @param Array $context + * @param array $context * The contextual information. */ function field_group_attach_groups(&$element, $context) { + if ($context['mode'] == '_custom') { + return; + } + $entity_type = $context['entity_type']; $bundle = $context['bundle']; $mode = $context['mode']; @@ -332,7 +490,7 @@ function field_group_attach_groups(&$element, $context) { $element['#fieldgroups'] = field_group_info_groups($entity_type, $bundle, $display_context, $mode); // Create a lookup array. - $group_children = array(); + $group_children = []; foreach ($element['#fieldgroups'] as $group_name => $group) { foreach ($group->children as $child) { $group_children[$child] = $group_name; @@ -340,110 +498,115 @@ function field_group_attach_groups(&$element, $context) { } $element['#group_children'] = $group_children; $element['#entity_type'] = $entity_type; - } /** - * Preprocess/ Pre-render callback. + * Pre-render callback for entity views. + * + * @param preprocess $vars + * Variables. + * @param $context + * The display context (entity type, form or view). + * + * @return array + * With re-arranged fields in groups. * - * @see field_group_form_pre_render() * @see field_group_theme_registry_alter * @see field_group_fields_nest() - * @param $vars preprocess vars or form element - * @param $context The display context (entity type, form or view) - * @return $element Array with re-arranged fields in groups. */ -function field_group_build_entity_groups(&$vars, $context = 'view') { - - if ($context == 'form') { - $element = &$vars; - $nest_vars = NULL; +function field_group_build_entity_groups(array &$vars, $context = 'view') { + if (isset($vars['elements'])) { + $element = &$vars['elements']; + } + elseif (isset($vars['content'])) { + $element = &$vars['content']; } else { - if (isset($vars['elements'])) { - $element = &$vars['elements']; - } - elseif (isset($vars['content'])) { - $element = &$vars['content']; + if ($context === 'eck_entity') { + $element = &$vars['entity']; } else { - if ($context === 'eck_entity') { - $element = &$vars['entity']; - } - else { - $element = &$vars; - } + $element = &$vars; } - - $nest_vars = &$vars; } + $nest_vars = &$vars; + // No groups on the entity. if (empty($element['#fieldgroups'])) { return $element; } - // Nest the fields in the corresponding field groups. - field_group_fields_nest($element, $nest_vars, $context); + // Use other nest function if field layout is active. + if (isset($element['_field_layout'])) { + field_group_field_layout_fields_nest($element, $nest_vars, $context); + } + else { + field_group_fields_nest($element, $nest_vars, $context); + } // Allow others to alter the pre_rendered build. Drupal::moduleHandler()->alter('field_group_build_pre_render', $element); - // Return the element on forms. - if ($context == 'form') { - return $element; - } - // No groups on the entity. Prerender removed empty field groups. if (empty($element['#fieldgroups'])) { return $element; } // Put groups inside content if we are rendering an entity_view. + $render_key = field_group_get_content_element_key($context); foreach ($element['#fieldgroups'] as $group) { if (!empty($element[$group->group_name])) { - $key = field_group_get_content_element_key($context); - if (isset($vars[$key])) { - $vars[$key][$group->group_name] = $element[$group->group_name]; + if (isset($vars[$render_key])) { + // Field layout enabled? Place it in correct region of the + // _field_layout key. + if (isset($vars[$render_key]['_field_layout'])) { + $vars[$render_key]['_field_layout'][$group->region][$group->group_name] = $element[$group->group_name]; + } + else { + $vars[$render_key][$group->group_name] = $element[$group->group_name]; + } } } } - } /** - * Recursive function to nest fields in the field groups. + * Nests all the fields in the field groups. * * This function will take out all the elements in the form and * place them in the correct container element, a fieldgroup. * The current group element in the loop is passed recursively so we can * stash fields and groups in it while we go deeper in the array. - * @param Array $element + * + * @param array $element * The current element to analyse for grouping. - * @param Array $vars + * @param array $vars * Rendering vars from the entity being viewed. - * @param Array $context + * @param array $context * The display context (entity type, form or view). */ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { // Create all groups and keep a flat list of references to these groups. - $group_references = array(); + $group_references = []; foreach ($element['#fieldgroups'] as $group_name => $group) { // Construct own weight, as some fields (for example preprocess fields) don't have weight set. - $element[$group_name] = array(); + if (!isset($element[$group_name])) { + $element[$group_name] = []; + } $group_references[$group_name] = &$element[$group_name]; } // Loop through all form children looking for those that are supposed to be // in groups, and insert placeholder element for the new group field in the // correct location within the form structure. - $element_clone = array(); + $element_clone = []; foreach (Element::children($element) as $child_name) { $element_clone[$child_name] = $element[$child_name]; // If this element is in a group, create the placeholder element. if (isset($element['#group_children'][$child_name])) { - $element_clone[$element['#group_children'][$child_name]] = array(); + $element_clone[$element['#group_children'][$child_name]] = []; } } $element = array_merge($element_clone, $element); @@ -453,11 +616,17 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { // parent currently is situated. foreach ($element['#group_children'] as $child_name => $parent_name) { - // Entity being viewed + // Entity being viewed. if ($vars) { // If not a group, check the content variable for empty field. $key = field_group_get_content_element_key($context); if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key][$child_name])) { + + // ECK marks his defaut properties as printed, while it is not printed yet. + if ($context === 'eck_entity' && !empty($vars[$key][$child_name]['#printed'])) { + $vars[$key][$child_name]['#printed'] = FALSE; + } + $group_references[$parent_name][$child_name] = $vars[$key][$child_name]; unset($vars[$key][$child_name]); } @@ -468,7 +637,7 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { unset($element[$child_name]); } } - // Form being viewed + // Form being viewed. else { // Block denied fields (#access) before they are put in groups. // Fields (not groups) that don't have children (like field_permissions) are removed @@ -477,6 +646,11 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { // If this is a group, we have to use a reference to keep the reference // list intact (but if it is a field we don't mind). $group_references[$parent_name][$child_name] = &$element[$child_name]; + + // Remove the #group property, otherwise core will move this element to + // the field layout region. + unset($group_references[$parent_name][$child_name]['#group']); + $group_references[$parent_name]['#weight'] = $element['#fieldgroups'][$parent_name]->weight; } @@ -491,7 +665,76 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { foreach ($element['#fieldgroups'] as $group_name => $group) { field_group_pre_render($group_references[$group_name], $group, $element); } +} + +/** + * Nests all the fields in the field groups. + * + * Ror entity display elements managed by field layout. + * + * @param array $element + * @param $vars + * @param $context + */ +function field_group_field_layout_fields_nest(array &$element, &$vars = NULL, $context = NULL) { + // Create all groups and keep a flat list of references to these groups. + $group_references = []; + foreach ($element['#fieldgroups'] as $group_name => $group) { + // Construct own weight, as some fields (for example preprocess fields) + // don't have weight set. + if (!isset($element[$group_name])) { + $element[$group_name] = []; + } + $group_references[$group_name] = &$element[$group_name]; + } + + // Loop through all children looking for those that are supposed to be + // in groups, and insert placeholder element for the new group field in the + // correct location within the form structure. + $element_clone = []; + foreach (Element::children($element['_field_layout']) as $region_name) { + foreach (Element::children($element['_field_layout'][$region_name]) as $child_name) { + $element_clone['_field_layout'][$region_name][$child_name] = $element['_field_layout'][$region_name][$child_name]; + // If this element is in a group, create the placeholder element. + if (isset($element['_field_layout'][$region_name]['#group_children'][$child_name])) { + $element_clone['_field_layout'][$region_name][$element['#group_children'][$child_name]] = []; + } + } + } + + $element = array_merge($element_clone, $element); + + // Move all children to their parents. Use the flat list of references for + // direct access as we don't know where in the root_element hierarchy the + // parent currently is situated. + foreach ($element['#group_children'] as $child_name => $group_name) { + $region = $element['#fieldgroups'][$group_name]->region; + + // If not a group, check the content variable for empty field. + $key = field_group_get_content_element_key($context); + if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key]['_field_layout'][$region][$child_name])) { + + // ECK marks his defaut properties as printed, while it is not printed yet. + if ($context === 'eck_entity' && !empty($vars[$key]['_field_layout'][$region][$child_name]['#printed'])) { + $vars[$key]['_field_layout'][$region][$child_name]['#printed'] = FALSE; + } + + $group_references[$group_name][$child_name] = $vars[$key]['_field_layout'][$region][$child_name]; + unset($vars[$key]['_field_layout'][$region][$child_name]); + } + // If this is a group, we have to use a reference to keep the reference + // list intact (but if it is a field we don't mind). + else { + $group_references[$group_name][$child_name] = &$element[$child_name]; + unset($element[$child_name]); + } + } + // Bring extra element wrappers to achieve a grouping of fields. + // This will mainly be prefix and suffix altering. + foreach ($element['#fieldgroups'] as $group_name => $group) { + field_group_pre_render($group_references[$group_name], $group, $element); + } } /** @@ -509,8 +752,8 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) { function field_group_pre_render(& $element, $group, & $rendering_object) { // Only run the pre_render function if the group has elements. - // $group->group_name - if ($element == array()) { + // $group->group_name. + if ($element == []) { return; } @@ -554,7 +797,6 @@ function field_group_get_content_element_key($context = 'default') { return $key; } - /** * Saves a group definition. * @@ -567,7 +809,7 @@ function field_group_get_content_element_key($context = 'default') { * @param \Drupal\Core\Entity\Display\EntityDisplayInterface $display * The display to update if known. * - * @return \Drupal\Core\Entity\Display\EntityDisplayInterface|NULL + * @return \Drupal\Core\Entity\Display\EntityDisplayInterface|null * The updated entity display. */ function field_group_group_save($group, $display = NULL) { @@ -583,23 +825,26 @@ function field_group_group_save($group, $display = NULL) { // If no display was found. It doesn't exist yet, create it. if (!isset($display)) { if ($group->context == 'form') { - $display = EntityFormDisplay::create(array( + $display = EntityFormDisplay::create([ 'targetEntityType' => $group->entity_type, 'bundle' => $group->bundle, 'mode' => $group->mode, - ))->setStatus(TRUE); + ])->setStatus(TRUE); } elseif ($group->context == 'view') { - $display = EntityViewDisplay::create(array( + $display = EntityViewDisplay::create([ 'targetEntityType' => $group->entity_type, 'bundle' => $group->bundle, 'mode' => $group->mode, - ))->setStatus(TRUE); + ])->setStatus(TRUE); } } if (isset($display)) { + // Remove label from the format_settings. + unset($group->format_settings['label']); + $data = (array) $group; unset($data['group_name'], $data['entity_type'], $data['bundle'], $data['mode'], $data['form'], $data['context']); $display->setThirdPartySetting('field_group', $group->group_name, $data); @@ -631,7 +876,7 @@ function field_group_group_delete($group) { $display->save(); } - Drupal::moduleHandler()->invokeAll('field_group_delete_field_group', array($group)); + Drupal::moduleHandler()->invokeAll('field_group_delete_field_group', [$group]); } /** @@ -650,27 +895,27 @@ function field_group_info_groups($entity_type, $bundle, $context, $mode) { if ($context == 'form') { $display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $mode); if (!$display) { - return array(); + return []; } $data = $display->getThirdPartySettings('field_group'); } if ($context == 'view') { $display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $mode); if (!$display) { - return array(); + return []; } $data = $display->getThirdPartySettings('field_group'); } - $groups = array(); + $groups = []; if (isset($data) && is_array($data)) { foreach ($data as $group_name => $definition) { - $definition += array( + $definition += [ 'group_name' => $group_name, 'entity_type' => $entity_type, 'bundle' => $bundle, 'context' => $context, 'mode' => $mode, - ); + ]; $groups[$group_name] = (object) $definition; } } @@ -701,15 +946,15 @@ function field_group_load_field_group($group_name, $entity_type, $bundle, $conte /** * Checks if a field_group exists in required context. * - * @param String $group_name + * @param string $group_name * The name of the group. - * @param String $entity_type + * @param string $entity_type * The name of the entity. - * @param String $bundle + * @param string $bundle * The bundle for the entity. * @param $context * The context of the view mode (form or view) - * @param String $mode + * @param string $mode * The view mode context the group will be rendered. */ function field_group_exists($group_name, $entity_type, $bundle, $context, $mode) { @@ -719,50 +964,38 @@ function field_group_exists($group_name, $entity_type, $bundle, $context, $mode) /** * Remove empty groups on forms. * - * @param String $parent_name - * The name of the element. * @param array $element * The element to check the empty state. * @param array $groups * Array of group objects. + * @param string $entity_type + * The entity type. */ -function field_group_remove_empty_form_groups($name, & $element, $groups, &$form_groups, $entity) { +function field_group_remove_empty_form_groups(&$element, $groups, $entity_type) { + $exceptions = ['user__account', 'comment__author']; - $exceptions = array('user__account', 'comment__author'); - - $children = Element::children($element); - - $hasChildren = FALSE; + $children = Element::getVisibleChildren($element); + $empty_groups_indication = array_fill_keys($groups, TRUE); if (count($children)) { foreach ($children as $childname) { - - if (in_array($childname, $groups)) { - field_group_remove_empty_form_groups($childname, $element[$childname], $groups, $form_groups, $entity); + $exception = $entity_type . '__' . $childname; + $empty_element = !(isset($element[$childname]['#type']) || isset($element[$childname]['#markup']) || in_array($exception, $exceptions)); + + // If the element is not empty, and it has a group. Mark the group as not + // empty. + if (!$empty_element && isset($element[$childname]['#group']) && (!isset($element[$childname]['#access']) || $element[$childname]['#access'])) { + $name_prefix = implode('][', $element['#array_parents']) . ']['; + $group_name = str_replace($name_prefix, '', $element[$childname]['#group']); + $empty_groups_indication[$group_name] = FALSE; } - $exception = $entity . '__' . $childname; - $hasChildren = $hasChildren ? TRUE : (isset($element[$childname]['#type']) || isset($element[$childname]['#markup']) || in_array($exception, $exceptions)); - } } - if (!$hasChildren) { - - // Remove empty elements from the #fieldgroups. - if (empty($element) && isset($form_groups[$name]) && !is_array($form_groups[$name])) { - foreach ($form_groups as $group_name => $group) { - if (isset($group->children)) { - $group_children = array_flip($group->children); - if (isset($group_children[$name])) { - unset($form_groups[$group_name]->children[$group_children[$name]]); - } - } - } - } - - $element['#access'] = FALSE; - + // Set access to false for all empty groups. + $empty_groups = array_filter($empty_groups_indication); + foreach (array_keys($empty_groups) as $group_name) { + $element[$group_name]['#access'] = FALSE; } - } /** diff --git a/web/modules/field_group/field_group.services.yml b/web/modules/field_group/field_group.services.yml index b7528819ad..1eafd00a99 100644 --- a/web/modules/field_group/field_group.services.yml +++ b/web/modules/field_group/field_group.services.yml @@ -10,4 +10,4 @@ services: field_group.param_converter: class: Drupal\field_group\Routing\FieldGroupConverter tags: - - { name: paramconverter } \ No newline at end of file + - { name: paramconverter } diff --git a/web/modules/field_group/formatters/accordion/accordion.js b/web/modules/field_group/formatters/accordion/accordion.js index d4a141fb3c..a114af701e 100644 --- a/web/modules/field_group/formatters/accordion/accordion.js +++ b/web/modules/field_group/formatters/accordion/accordion.js @@ -49,7 +49,7 @@ if ($('.error', $this).length) { // Save first error item, for focussing it. if (!$firstErrorItem) { - $firstErrorItem = $this.parent().accordion('activate', i); + $firstErrorItem = $this.parent().accordion('option', 'active', i); } $('h3.ui-accordion-header').eq(i).addClass('error'); } diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.css b/web/modules/field_group/formatters/tabs/horizontal-tabs.css index 088e59ed8b..5cb6ce314f 100644 --- a/web/modules/field_group/formatters/tabs/horizontal-tabs.css +++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.css @@ -6,7 +6,7 @@ } [dir="rtl"] .horizontal-tabs { - margin: 0 0 1em 0; + margin: 0 0 1em 0; } .horizontal-tabs .horizontal-tabs-list { @@ -27,9 +27,10 @@ border-left: 1px solid #dedede; } -.horizontal-tabs-pane { +.horizontal-tabs-panes .horizontal-tabs-pane { padding: 0 1em; border: 0; + background-color: unset; } .horizontal-tabs-pane > summary { @@ -95,7 +96,7 @@ display: block; text-decoration: none; padding: 0.5em 0.6em 0.3em 0.6em; - position:relative; + position: relative; top: 0px; } @@ -124,6 +125,6 @@ div.field-group-htabs-wrapper .field-group-format-wrapper { .horizontal-tabs .horizontal-tab-hidden { display: block; position: absolute; - top: -100000px; + top: -100000000px; width: 100%; } diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.js b/web/modules/field_group/formatters/tabs/horizontal-tabs.js index acf08f377e..363e63e4e1 100644 --- a/web/modules/field_group/formatters/tabs/horizontal-tabs.js +++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.js @@ -82,8 +82,8 @@ // If the current URL has a fragment and one of the tabs contains an // element that matches the URL fragment, activate that tab. var hash = window.location.hash.replace(/[=%;,\/]/g, ''); - if (hash !== '#' && $(hash, this).length) { - tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-pane'); + if (hash !== '#' && $(this).find(hash).length) { + tab_focus = $(this).find(hash).closest('.horizontal-tabs-pane'); } else { tab_focus = $this.find('> .horizontal-tabs-pane:first'); @@ -118,8 +118,8 @@ // Keyboard events added: // Pressing the Enter key will open the tab pane. this.link.on('keydown', function (event) { - event.preventDefault(); if (event.keyCode === 13) { + event.preventDefault(); self.focus(); // Set focus on the first input field of the visible details/tab pane. $('.horizontal-tabs-pane :input:visible:enabled:first').trigger('focus'); diff --git a/web/modules/field_group/includes/field_ui.inc b/web/modules/field_group/includes/field_ui.inc index 6a3cf76a58..318dd1ef90 100644 --- a/web/modules/field_group/includes/field_ui.inc +++ b/web/modules/field_group/includes/field_ui.inc @@ -6,9 +6,15 @@ * needed on the Fields UI Manage forms (display and fields). */ +use Drupal\field_group\FieldgroupUi; +use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Entity\Display\EntityFormDisplayInterface; +use Drupal\Core\Entity\EntityDisplayBase; use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Link; use Drupal\Core\Render\Element; +use Drupal\field_group\FormatterHelper; use Drupal\field_ui\Form\EntityDisplayFormBase; /** @@ -21,26 +27,40 @@ * * @return \stdClass */ -function field_group_field_ui_form_params($form, \Drupal\Core\Entity\EntityDisplayBase $display) { +function field_group_field_ui_form_params($form, EntityDisplayBase $display) { $params = new stdClass(); $params->entity_type = $display->getTargetEntityTypeId(); $params->bundle = $display->getTargetBundle(); - $params->region_callback = 'field_group_display_overview_row_region'; $params->mode = $display->getMode(); $params->context = field_group_get_context_from_display($display); - $params->groups = array(); + $params->groups = []; $params->groups = field_group_info_groups($params->entity_type, $params->bundle, $params->context, $params->mode); // Gather parenting data. - $params->parents = array(); + $params->parents = []; foreach ($params->groups as $name => $group) { foreach ($group->children as $child) { - $params->parents[$child] = $name; + // Field UI js sometimes can trigger an endless loop. Check if the parent of this field is not a child. + if ($child !== $group->parent_name) { + $params->parents[$child] = $name; + } } } + // Get possible regions. + $layout_info = $display->getThirdPartySettings('field_layout'); + if (!empty($layout_info) && isset($layout_info['id'])) { + $layout = \Drupal::service('plugin.manager.core.layout')->getDefinition($layout_info['id']); + $params->available_regions = $layout->getRegionNames(); + $params->default_region = $layout->getDefaultRegion() ?: 'hidden'; + } + else { + $params->available_regions = ['content', 'hidden']; + $params->default_region = 'hidden'; + } + return $params; } @@ -51,11 +71,11 @@ function field_group_field_ui_form_params($form, \Drupal\Core\Entity\EntityDispl * * @return string */ -function field_group_get_context_from_display(\Drupal\Core\Entity\EntityDisplayBase $display) { - if ($display instanceof \Drupal\Core\Entity\Display\EntityFormDisplayInterface) { +function field_group_get_context_from_display(EntityDisplayBase $display) { + if ($display instanceof EntityFormDisplayInterface) { return 'form'; } - elseif ($display instanceof \Drupal\Core\Entity\Display\EntityViewDisplayInterface) { + elseif ($display instanceof EntityViewDisplayInterface) { return 'view'; } @@ -71,12 +91,12 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for return; } - $callback_object = $form_state->getBuildInfo()['callback_object']; - if (!$callback_object instanceof EntityDisplayFormBase) { + $entity_display_form = $form_state->getBuildInfo()['callback_object']; + if (!$entity_display_form instanceof EntityDisplayFormBase) { throw new InvalidArgumentException('Unkown callback object.'); } - $display = $callback_object->getEntity(); + $display = $entity_display_form->getEntity(); $params = field_group_field_ui_form_params($form, $display); $form['#fieldgroups'] = array_keys($params->groups); @@ -106,9 +126,10 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for } } - $formatter_options = field_group_field_formatter_options($params->context); + $formatter_options = FormatterHelper::formatterOptions($params->context); $refresh_rows = isset($form_state_values['refresh_rows']) ? $form_state_values['refresh_rows'] : (isset($form_state->getUserInput()['refresh_rows']) ? $form_state->getUserInput()['refresh_rows'] : NULL); + // Create the group rows and check actions. foreach ($form['#fieldgroups'] as $name) { $group = &$field_group_form_state[$name]; @@ -134,132 +155,139 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for $settings = field_group_format_settings_form($group, $form, $form_state); $id = strtr($name, '_', '-'); - $js_rows_data[$id] = array('type' => 'group', 'name' => $name); + $js_rows_data[$id] = ['type' => 'group', 'name' => $name]; // A group cannot be selected as its own parent. $parent_options = $table['#parent_options']; + $region = isset($group->region) && in_array($group->region, $params->available_regions) ? $group->region : $params->default_region; unset($parent_options[$name]); - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'field-group'), 'id' => $id), + $table[$name] = [ + '#attributes' => ['class' => ['draggable', 'field-group'], 'id' => $id], '#row_type' => 'group', - '#region_callback' => $params->region_callback, - '#js_settings' => array('rowHandler' => 'group'), - 'human_name' => array( + '#region_callback' => 'field_group_display_overview_row_region', + '#js_settings' => ['rowHandler' => 'group'], + 'human_name' => [ '#markup' => Html::escape(t($group->label)), '#prefix' => '<span class="group-label">', '#suffix' => '</span>', - ), - 'weight' => array( + ], + 'weight' => [ '#type' => 'textfield', '#default_value' => $group->weight, '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - ), - 'parent_wrapper' => array( - 'parent' => array( + '#attributes' => ['class' => ['field-weight']], + ], + 'parent_wrapper' => [ + 'parent' => [ '#type' => 'select', - '#options' => $parent_options, + '#options' => $parent_options, '#empty_value' => '', '#default_value' => isset($params->parents[$name]) ? $params->parents[$name] : '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( + '#attributes' => ['class' => ['field-parent']], + '#parents' => ['fields', $name, 'parent'], + ], + 'hidden_name' => [ '#type' => 'hidden', '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - ); + '#attributes' => ['class' => ['field-name']], + ], + ], + 'region' => [ + '#type' => 'select', + '#options' => $entity_display_form->getRegionOptions(), + '#default_value' => $region, + '#attributes' => ['class' => ['field-region']], + ], + ]; // For view settings. Add a spacer cell. We can't use colspan because of the javascript . if ($params->context == 'view') { - $table[$name] += array( - 'spacer' => array( - '#markup' => ' ' - ) - ); + $table[$name] += [ + 'spacer' => [ + '#markup' => ' ', + ], + ]; } - $table[$name] += array( - 'format' => array( - 'type' => array( + $table[$name] += [ + 'format' => [ + 'type' => [ '#type' => 'select', '#options' => $formatter_options, '#default_value' => $group->format_type, - '#attributes' => array('class' => array('field-group-type')), - ), - ), - ); - - $base_button = array( - '#submit' => array( - array($form_state->getBuildInfo()['callback_object'], 'multistepSubmit') - ), - '#ajax' => array( - 'callback' => array($form_state->getBuildInfo()['callback_object'], 'multistepAjax'), + '#attributes' => ['class' => ['field-group-type']], + ], + ], + ]; + + $base_button = [ + '#submit' => [ + [$form_state->getBuildInfo()['callback_object'], 'multistepSubmit'], + ], + '#ajax' => [ + 'callback' => [$form_state->getBuildInfo()['callback_object'], 'multistepAjax'], 'wrapper' => 'field-display-overview-wrapper', 'effect' => 'fade', - ), + ], '#field_name' => $name, - ); + ]; if ($form_state->get('plugin_settings_edit') == $name) { - $table[$name]['format']['#cell_attributes'] = array('colspan' => 2); - $table[$name]['format']['format_settings'] = array( + $table[$name]['format']['#cell_attributes'] = ['colspan' => 2]; + $table[$name]['format']['format_settings'] = [ '#type' => 'container', - '#attributes' => array('class' => array('field-plugin-settings-edit-form')), - '#parents' => array('fields', $name, 'settings_edit_form'), + '#attributes' => ['class' => ['field-plugin-settings-edit-form']], + '#parents' => ['fields', $name, 'settings_edit_form'], '#weight' => -5, - 'label' => array( + 'label' => [ '#markup' => t('Field group format:') . ' <span class="formatter-name">' . $group->format_type . '</span>', - ), + ], // Create a settings form where hooks can pick in. 'settings' => $settings, - 'actions' => array( + 'actions' => [ '#type' => 'actions', - 'save_settings' => $base_button + array( + 'save_settings' => $base_button + [ '#type' => 'submit', '#name' => $name . '_plugin_settings_update', '#value' => t('Update'), '#op' => 'update', - ), - 'cancel_settings' => $base_button + array( + ], + 'cancel_settings' => $base_button + [ '#type' => 'submit', '#name' => $name . '_plugin_settings_cancel', '#value' => t('Cancel'), '#op' => 'cancel', // Do not check errors for the 'Cancel' button. - '#limit_validation_errors' => array(), - ), - ), - ); + '#limit_validation_errors' => [], + ], + ], + ]; $table[$name]['#attributes']['class'][] = 'field-formatter-settings-editing'; - $table[$name]['format']['type']['#attributes']['class'] = array('visually-hidden'); + $table[$name]['format']['type']['#attributes']['class'] = ['visually-hidden']; } else { // After saving, the settings are updated here aswell. First we create // the element for the table cell. - $table[$name]['settings_summary'] = array('#markup' => ''); + $table[$name]['settings_summary'] = ['#markup' => '']; if (!empty($group->format_settings)) { $table[$name]['settings_summary'] = field_group_format_settings_summary($name, $group); } // Add the configure button. - $table[$name]['settings_edit'] = $base_button + array( + $table[$name]['settings_edit'] = $base_button + [ '#type' => 'image_button', '#name' => $name . '_group_settings_edit', '#src' => 'core/misc/icons/787878/cog.svg', - '#attributes' => array('class' => array('field-plugin-settings-edit'), 'alt' => t('Edit')), + '#attributes' => ['class' => ['field-plugin-settings-edit'], 'alt' => t('Edit')], '#op' => 'edit', // Do not check errors for the 'Edit' button, but make sure we get // the value of the 'plugin type' select. - '#limit_validation_errors' => array(array('fields', $name, 'type')), + '#limit_validation_errors' => [['fields', $name, 'type']], '#prefix' => '<div class="field-plugin-settings-edit-wrapper">', '#suffix' => '</div>', - ); + ]; - $delete_route = \Drupal\field_group\FieldgroupUi::getDeleteRoute($group); + $delete_route = FieldgroupUi::getDeleteRoute($group); - $table[$name]['settings_edit']['#suffix'] .= Drupal::l(t('delete'), $delete_route); + $table[$name]['settings_edit']['#suffix'] .= Link::fromTextAndUrl(t('delete'), $delete_route)->toString(); } $form_state->set('field_group', $field_group_form_state); @@ -276,29 +304,29 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for // Create the settings for fieldgroup as vertical tabs (merged with DS). field_group_field_ui_create_vertical_tabs($form, $form_state, $params); - // Show a warning if the user has not set up required containers + // Show a warning if the user has not set up required containers. if ($form['#fieldgroups']) { - $parent_requirements = array( - 'accordion-item' => array( + $parent_requirements = [ + 'accordion-item' => [ 'parent' => 'accordion', 'message' => 'Each Accordion item element needs to have a parent Accordion group element.', - ), - ); + ], + ]; // On display overview tabs need to be checked. if (field_group_get_context_from_display($display) == 'view') { - $parent_requirements['tab'] = array( + $parent_requirements['tab'] = [ 'parent' => 'tabs', 'message' => 'Each tab element needs to have a parent tabs group element.', - ); + ]; } foreach ($form['#fieldgroups'] as $group_name) { $group_check = field_group_load_field_group($group_name, $params->entity_type, $params->bundle, $params->context, $params->mode); if (isset($parent_requirements[$group_check->format_type])) { if (!$group_check->parent_name || field_group_load_field_group($group_check->parent_name, $params->entity_type, $params->bundle, $params->context, $params->mode)->format_type != $parent_requirements[$group_check->format_type]['parent']) { - drupal_set_message(t($parent_requirements[$group_check->format_type]['message']), 'warning', FALSE); + \Drupal::messenger()->addMessage(t($parent_requirements[$group_check->format_type]['message']), 'warning', FALSE); } } } @@ -313,7 +341,7 @@ function field_group_field_ui_create_vertical_tabs(&$form, &$form_state, $params $form_state->set('field_group_params', $params); $existing_group_config = \Drupal::configFactory()->listAll('field_group.' . $params->entity_type . '.' . $params->bundle); - $displays = array(); + $displays = []; foreach ($existing_group_config as $config) { $group = \Drupal::config($config)->get(); if ($group['context'] == $params->context && $group['mode'] == $params->mode) { @@ -329,73 +357,82 @@ function field_group_field_ui_create_vertical_tabs(&$form, &$form_state, $params // Add additional settings vertical tab. if (!isset($form['additional_settings'])) { - $form['additional_settings'] = array( + $form['additional_settings'] = [ '#type' => 'vertical_tabs', - '#theme_wrappers' => array('vertical_tabs'), + '#theme_wrappers' => ['vertical_tabs'], '#prefix' => '<div>', '#suffix' => '</div>', '#tree' => TRUE, - ); + ]; } // Add extra guidelines for webmaster. - $form['field_group'] = array( + $form['field_group'] = [ '#type' => 'details', '#group' => 'additional_settings', '#title' => t('Fieldgroups'), '#description' => t('<p class="fieldgroup-help">Fields can be dragged into groups with unlimited nesting. Each fieldgroup format comes with a configuration form, specific for that format type.<br />Note that some formats come in pair. These types have a html wrapper to nest its fieldgroup children. E.g. Place accordion items into the accordion, vertical tabs in vertical tab group and horizontal tabs in the horizontal tab group. There is one exception to this rule, you can use a vertical tab without a wrapper when the additional settings tabs are available. E.g. node forms.</p>'), '#collapsible' => TRUE, '#open' => TRUE, - ); - $form['field_group']['fieldgroup_clone'] = array( + ]; + $form['field_group']['fieldgroup_clone'] = [ '#title' => t('Select source display'), '#description' => t('Clone fieldgroups from selected display to the current display'), '#type' => 'select', '#options' => $displays, - '#default_value' => 'none' - ); - $form['field_group']['fieldgroup_submit'] = array( + '#default_value' => 'none', + ]; + $form['field_group']['fieldgroup_submit'] = [ '#type' => 'submit', '#value' => t('Clone'), - '#validate' => array('field_group_field_ui_clone_field_groups_validate'), - '#submit' => array('field_group_field_ui_clone_field_groups') - ); + '#validate' => ['field_group_field_ui_clone_field_groups_validate'], + '#submit' => ['field_group_field_ui_clone_field_groups'], + ]; } /** * Returns the region to which a row in the 'Manage display' screen belongs. - * @param Array $row A field or field_group row + * + * @param array $row + * A field or field_group row. + * * @return String the current region. */ function field_group_display_overview_row_region($row) { - switch ($row['#row_type']) { - case 'group': - return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'content'); - } + // We already cleaned region when building the form. + return $row['region']['#value']; } /** * Submit handler for the overview screens. - * @param Array $form The complete form. - * @param FormStateInterface $form_state The state of the form. + * + * @param array $form + * The complete form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The state of the form. */ function field_group_field_overview_submit($form, FormStateInterface $form_state) { $form_values = $form_state->getValue('fields'); - $fields_added = $form_state->getValue('fields_added'); /** * @var \Drupal\Core\Entity\EntityDisplayBase $display */ $display = $form['#context']; + $manager = Drupal::service('plugin.manager.field_group.formatters'); $entity_type = $display->get('targetEntityType'); $bundle = $display->get('bundle'); $mode = $display->get('mode'); $context = field_group_get_context_from_display($display); + // Load field layout info. + $field_group_params = $form_state->get('field_group_params'); + $layout_regions = $field_group_params->available_regions; + $default_region = $field_group_params->default_region; + // Collect children. - $children = array_fill_keys($form['#fieldgroups'], array()); + $children = array_fill_keys($form['#fieldgroups'], []); foreach ($form_values as $name => $value) { if (!empty($value['parent'])) { $children[$value['parent']][$name] = $name; @@ -403,7 +440,7 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state } // Update existing groups. - $groups = field_group_info_groups($entity_type, $bundle, $context, $mode, TRUE); + $groups = field_group_info_groups($entity_type, $bundle, $context, $mode); $field_group_form_state = $form_state->get('field_group'); if (!empty($field_group_form_state)) { foreach ($form['#fieldgroups'] as $group_name) { @@ -415,10 +452,17 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state $group = $groups[$group_name]; $group->label = $field_group_form_state[$group_name]->label; + + // Sometimes field UI does a fuckup if people drag to fast when switching nested values. + // This results in an endless loop => Cleanup before saving. + // unset($children[$group_name][$form_values[$group_name]['parent']]);. $group->children = array_keys($children[$group_name]); $group->parent_name = $form_values[$group_name]['parent']; $group->weight = $form_values[$group_name]['weight']; + // If region is changed, make sure the group ends up in an existing region. + $group->region = !in_array($form_values[$group_name]['region'], $layout_regions) ? $default_region : $form_values[$group_name]['region']; + $old_format_type = $group->format_type; $group->format_type = isset($form_values[$group_name]['format']['type']) ? $form_values[$group_name]['format']['type'] : 'visible'; if (isset($field_group_form_state[$group_name]->format_settings)) { @@ -427,8 +471,7 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state // If the format type is changed, make sure we have all required format settings. if ($group->format_type != $old_format_type) { - $default_formatter_settings = _field_group_get_default_formatter_settings($group->format_type, $context); - $group->format_settings += $default_formatter_settings; + $group->format_settings += $manager->getDefaultSettings($group->format_type, $context); } /** @var EntityFormInterface $entity_form */ @@ -446,27 +489,37 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state /** * Creates a form for field_group formatters. - * @param Object $group The FieldGroup object. + * + * @param Object $group + * The FieldGroup object. */ function field_group_format_settings_form(&$group, $form, $form_state) { $manager = \Drupal::service('plugin.manager.field_group.formatters'); - $plugin = $manager->getInstance(array( + $plugin = $manager->getInstance([ 'format_type' => $group->format_type, - 'configuration' => array('label' => $group->label, 'settings' => $group->format_settings), + 'configuration' => [ + 'label' => $group->label, + 'settings' => $group->format_settings, + ], 'group' => $group, - )); + ]); + + if ($plugin) { + return $plugin->settingsForm($form, $form_state); + } - return $plugin->settingsForm($form, $form_state); + return []; } /** * Update the row so that the group variables are updated. * The rendering of the elements needs the updated defaults. + * * @param Object $group * @param array $settings */ function field_group_formatter_row_update(& $group, $settings) { - // if the row has changed formatter type, update the group object + // If the row has changed formatter type, update the group object. if (!empty($settings['format']['type']) && $settings['format']['type'] != $group->format_type) { $group->format_type = $settings['format']['type']; field_group_formatter_settings_update($group, $settings); @@ -475,14 +528,17 @@ function field_group_formatter_row_update(& $group, $settings) { /** * Update handler for field_group configuration settings. - * @param Object $group The group object - * @param Array $settings Configuration settings + * + * @param Object $group + * The group object. + * @param array $settings + * Configuration settings. */ function field_group_formatter_settings_update(& $group, $settings) { - // for format changes we load the defaults. + // For format changes we load the defaults. if (empty($settings['settings_edit_form']['settings'])) { - $group->format_settings = _field_group_get_default_formatter_settings($group->format_type, $group->context); + $group->format_settings = Drupal::service('plugin.manager.field_group.formatters')->getDefaultSettings($group->format_type, $group->context); } else { $group->format_type = $settings['format']['type']; @@ -493,25 +549,37 @@ function field_group_formatter_settings_update(& $group, $settings) { /** * Creates a summary for the field format configuration summary. - * @param String $group_name The name of the group - * @param Object $group The group object + * + * @param string $group_name + * The name of the group. + * @param Object $group + * The group object. + * * @return Array ready to be rendered. */ function field_group_format_settings_summary($group_name, $group) { $manager = \Drupal::service('plugin.manager.field_group.formatters'); - $plugin = $manager->getInstance(array( + $plugin = $manager->getInstance([ 'format_type' => $group->format_type, - 'configuration' => array('label' => $group->label, 'settings' => $group->format_settings), + 'configuration' => [ + 'label' => $group->label, + 'settings' => $group->format_settings, + ], 'group' => $group, - )); + ]); - $summary = $plugin->settingsSummary(); + if ($plugin) { + $summary = $plugin->settingsSummary(); + } + else { + $summary = ''; + } - return array( + return [ '#markup' => '<div class="field-plugin-summary">' . implode('<br />', $summary) . '</div>', - '#cell_attributes' => array('class' => array('field-plugin-summary-cell')), - ); + '#cell_attributes' => ['class' => ['field-plugin-summary-cell']], + ]; } /** @@ -536,7 +604,7 @@ function field_group_field_ui_clone_field_groups_validate($form, FormStateInterf foreach ($source_groups as $key => $group) { if (in_array($group->format_type, $non_existing_types)) { unset($source_groups[$key]); - drupal_set_message(t('Skipping @group because this type does not exist in current mode', array('@group' => $group->label)), 'warning'); + \Drupal::messenger()->addMessage(t('Skipping @group because this type does not exist in current mode', ['@group' => $group->label]), 'warning'); } } @@ -562,16 +630,16 @@ function field_group_field_ui_clone_field_groups($form, FormStateInterface $form $field_group_params = $form_state->get('field_group_params'); foreach ($source_groups as $source_group) { if (in_array($source_group->group_name, $fields)) { - drupal_set_message(t('Fieldgroup @group is not cloned since a group already exists with the same name.', array('@group' => $source_group->group_name)), 'warning'); + \Drupal::messenger()->addMessage(t('Fieldgroup @group is not cloned since a group already exists with the same name.', ['@group' => $source_group->group_name]), 'warning'); continue; } $source_group->context = $field_group_params->context; $source_group->mode = $field_group_params->mode; - $source_group->children = array(); + $source_group->children = []; field_group_group_save($source_group); - drupal_set_message(t('Fieldgroup @group cloned successfully.', array('@group' => $source_group->group_name))); + \Drupal::messenger()->addMessage(t('Fieldgroup @group cloned successfully.', ['@group' => $source_group->group_name])); } } diff --git a/web/modules/field_group/includes/helpers.inc b/web/modules/field_group/includes/helpers.inc deleted file mode 100644 index a6735f094d..0000000000 --- a/web/modules/field_group/includes/helpers.inc +++ /dev/null @@ -1,64 +0,0 @@ -<?php - -use Drupal\Core\Form\FormStateInterface; - -/* - * @file - * Helper functions for the fieldgroup module. - */ - -/** - * Get the default formatter settings for a given formatter and context. - */ -function _field_group_get_default_formatter_settings($format_type, $context) { - $manager = Drupal::service('plugin.manager.field_group.formatters'); - return $manager->getDefaultSettings($format_type, $context); -} - -/** - * Return an array of field_group_formatter options. - */ -function field_group_field_formatter_options($type) { - $options = &drupal_static(__FUNCTION__); - - if (!isset($options)) { - $options = array(); - - $manager = Drupal::service('plugin.manager.field_group.formatters'); - $formatters = $manager->getDefinitions(); - - foreach ($formatters as $formatter) { - if (in_array($type, $formatter['supported_contexts'])) { - $options[$formatter['id']] = $formatter['label']; - } - } - } - - return $options; -} - -/** - * Validate the entered css class from the submitted format settings. - * @param Array $element The validated element - * @param FormStateInterface $form_state The state of the form. - */ -function field_group_validate_css_class($element, FormStateInterface $form_state) { - $form_state_values = $form_state->getValues(); - $plugin_name = $form_state->get('plugin_settings_edit'); - if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes']) && !preg_match('!^[A-Za-z0-9-_ ]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes'])) { - $form_state->setError($element, $form_state, t('The css class must include only letters, numbers, underscores and dashes.')); - } -} - -/** - * Validate the entered id attribute from the submitted format settings. - * @param Array $element The validated element - * @param FormStateInterface $form_state The state of the form. - */ -function field_group_validate_id($element, FormStateInterface $form_state) { - $form_state_values = $form_state->getValues(); - $plugin_name = $form_state->get('plugin_settings_edit'); - if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id']) && !preg_match('!^[A-Za-z0-9-_]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id'])) { - Drupal::formBuilder()->setError($element, $form_state, t('The id must include only letters, numbers, underscores and dashes.')); - } -} \ No newline at end of file diff --git a/web/modules/field_group/js/field_group.field_ui.js b/web/modules/field_group/js/field_group.field_ui.js index b23a51235d..7aba6df1c6 100644 --- a/web/modules/field_group/js/field_group.field_ui.js +++ b/web/modules/field_group/js/field_group.field_ui.js @@ -68,15 +68,15 @@ this.tableDrag = data.tableDrag; // Attach change listener to the 'group format' select. - this.$formatSelect = $('select.field-group-type', row); - this.$formatSelect.change(Drupal.fieldUIOverview.onChange); + this.$regionSelect = $(row).find('select.field-region'); + this.$regionSelect.on('change', Drupal.fieldUIOverview.onChange); return this; }; Drupal.fieldUIDisplayOverview.group.prototype = { - getRegion: function () { - return (this.$formatSelect.val() === 'hidden') ? 'hidden' : 'content'; + getRegion: function getRegion() { + return this.$regionSelect.val(); }, regionChange: function (region, recurse) { @@ -84,28 +84,13 @@ // Default recurse to true. recurse = (typeof recurse === 'undefined') || recurse; - // When triggered by a row drag, the 'format' select needs to be adjusted to + // When triggered by a row drag, the 'region' select needs to be adjusted to // the new region. - var currentValue = this.$formatSelect.val(); - var value; - switch (region) { - case 'visible': - if (currentValue === 'hidden') { - // Restore the group format back to 'fieldset'. - value = 'fieldset'; - } - break; - - default: - value = 'hidden'; - break; - } - if (typeof value !== 'undefined') { - this.$formatSelect.val(value); - } + region = region.replace(/-/g, '_'); + this.$regionSelect.val(region); var refreshRows = {}; - refreshRows[this.name] = this.$formatSelect.get(0); + refreshRows[this.name] = this.$regionSelect.get(0); if (recurse) { this.regionChangeFields(region, this, refreshRows); diff --git a/web/modules/field_group/src/Annotation/FieldGroupFormatter.php b/web/modules/field_group/src/Annotation/FieldGroupFormatter.php index 0e3752d8a9..d7acb983dd 100644 --- a/web/modules/field_group/src/Annotation/FieldGroupFormatter.php +++ b/web/modules/field_group/src/Annotation/FieldGroupFormatter.php @@ -31,20 +31,11 @@ class FieldGroupFormatter extends Plugin { /** * The human-readable name of the formatter type. * - * @ingroup plugin_translatable - * * @var \Drupal\Core\Annotation\Translation - */ - public $label; - - /** - * A short description of the formatter type. * * @ingroup plugin_translatable - * - * @var \Drupal\Core\Annotation\Translation */ - public $description; + public $label; /** * The name of the fieldgroup formatter class. @@ -60,20 +51,20 @@ class FieldGroupFormatter extends Plugin { * * @var array */ - public $supported_contexts = array(); + public $supported_contexts = []; /** * The different format types available for this formatter. * * @var array */ - public $format_types = array(); + public $format_types = []; /** * An integer to determine the weight of this formatter relative to other * formatter in the Field UI when selecting a formatter for a given group. * - * @var int optional + * @var int */ public $weight = NULL; diff --git a/web/modules/field_group/src/Element/Accordion.php b/web/modules/field_group/src/Element/Accordion.php index 3addbebcae..72ba8e608f 100644 --- a/web/modules/field_group/src/Element/Accordion.php +++ b/web/modules/field_group/src/Element/Accordion.php @@ -18,12 +18,16 @@ class Accordion extends RenderElement { public function getInfo() { $class = get_class($this); - return array( - '#process' => array( - array($class, 'processAccordion'), - ), - '#theme_wrappers' => array('field_group_accordion'), - ); + return [ + '#process' => [ + [$class, 'processGroup'], + [$class, 'processAccordion'], + ], + '#pre_render' => [ + [$class, 'preRenderGroup'], + ], + '#theme_wrappers' => ['field_group_accordion'], + ]; } /** @@ -38,15 +42,16 @@ public function getInfo() { * @return array * The processed element. */ - public static function processAccordion(&$element, FormStateInterface $form_state) { + public static function processAccordion(array &$element, FormStateInterface $form_state) { // Add the jQuery UI accordion. $element['#attached']['library'][] = 'field_group/formatter.accordion'; + $element['#attached']['library'][] = 'field_group/core'; // Add the effect class. if (isset($element['#effect'])) { if (!isset($element['#attributes']['class'])) { - $element['#attributes']['class'] = array(); + $element['#attributes']['class'] = []; } $element['#attributes']['class'][] = 'effect-' . $element['#effect']; } diff --git a/web/modules/field_group/src/Element/AccordionItem.php b/web/modules/field_group/src/Element/AccordionItem.php index 8d6dfe4580..dbfd913630 100644 --- a/web/modules/field_group/src/Element/AccordionItem.php +++ b/web/modules/field_group/src/Element/AccordionItem.php @@ -15,10 +15,18 @@ class AccordionItem extends RenderElement { * {@inheritdoc} */ public function getInfo() { - return array( - '#open' => TRUE, - '#theme_wrappers' => array('field_group_accordion_item'), - ); + $class = get_class($this); + + return [ + '#process' => [ + [$class, 'processGroup'], + ], + '#pre_render' => [ + [$class, 'preRenderGroup'], + ], + '#open' => FALSE, + '#theme_wrappers' => ['field_group_accordion_item'], + ]; } } diff --git a/web/modules/field_group/src/Element/HorizontalTabs.php b/web/modules/field_group/src/Element/HorizontalTabs.php index f1ee96fe03..dab221c922 100644 --- a/web/modules/field_group/src/Element/HorizontalTabs.php +++ b/web/modules/field_group/src/Element/HorizontalTabs.php @@ -3,6 +3,7 @@ namespace Drupal\field_group\Element; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; use Drupal\Core\Render\Element\RenderElement; /** @@ -21,13 +22,57 @@ class HorizontalTabs extends RenderElement { public function getInfo() { $class = get_class($this); - return array( + return [ '#default_tab' => '', - '#process' => array( - array($class, 'processHorizontalTabs'), - ), - '#theme_wrappers' => array('horizontal_tabs'), - ); + '#process' => [ + [$class, 'processHorizontalTabs'], + [$class, 'processGroup'], + ], + '#pre_render' => [ + [$class, 'preRenderGroup'], + ], + '#theme_wrappers' => ['horizontal_tabs'], + ]; + } + + /** + * Pre render the group to support #group parameter. + * + * @param array $element + * An associative array containing the properties and children of the + * element. + * + * @return array + * The modified element with all group members. + */ + public static function preRenderGroup($element) { + // The element may be rendered outside of a Form API context. + if (!isset($element['#parents']) || !isset($element['#groups'])) { + return $element; + } + + if (isset($element['#group'])) { + // Contains form element summary functionalities. + $element['#attached']['library'][] = 'core/drupal.form'; + + $group = $element['#group']; + // If this element belongs to a group, but the group-holding element does + // not exist, we need to render it (at its original location). + if (!isset($element['#groups'][$group]['#group_exists'])) { + // Intentionally empty to clarify the flow; we simply return $element. + } + // If we injected this element into the group, then we want to render it. + elseif (!empty($element['#group_details'])) { + // Intentionally empty to clarify the flow; we simply return $element. + } + // Otherwise, this element belongs to a group and the group exists, so we do + // not render it. + elseif (Element::children($element['#groups'][$group])) { + $element['#printed'] = TRUE; + } + } + + return $element; } /** @@ -44,15 +89,15 @@ public function getInfo() { * @return array * The processed element. */ - public static function processHorizontalTabs(&$element, FormStateInterface $form_state, $on_form = TRUE) { + public static function processHorizontalTabs(array &$element, FormStateInterface $form_state, $on_form = TRUE) { // Inject a new details as child, so that form_process_details() processes // this details element like any other details. - $element['group'] = array( + $element['group'] = [ '#type' => 'details', - '#theme_wrappers' => array(), + '#theme_wrappers' => [], '#parents' => $element['#parents'], - ); + ]; // Add an invisible label for accessibility. if (!isset($element['#title'])) { @@ -68,19 +113,66 @@ public static function processHorizontalTabs(&$element, FormStateInterface $form $element['#attached']['library'][] = 'core/drupal.form'; } + $name = implode('__', $element['#parents']); + if ($form_state->hasValue($name . '__active_tab')) { + $element['#default_tab'] = $form_state->getValue($name . '__active_tab'); + } + + $groups = &$form_state->getGroups(); + $group_name = $element['#group_name']; + $displayed_tab = isset($element['#default_tab']) ? $element['#default_tab'] : ''; + if (isset($groups[$group_name]) && empty($displayed_tab)) { + foreach (Element::children($groups[$group_name]) as $child) { + $child_group = $groups[$group_name][$child]; + if (!empty($child_group['#open']) || empty($displayed_tab)) { + // Use the last open group or the first group if none are open. + $displayed_tab = $child_group['#id']; + } + } + } + // The JavaScript stores the currently selected tab in this hidden // field so that the active tab can be restored the next time the // form is rendered, e.g. on preview pages or when form validation // fails. - $name = implode('__', $element['#parents']); - if ($form_state->hasValue($name . '__active_tab')){ - $element['#default_tab'] = $form_state->getValue($name . '__active_tab'); - } - $element[$name . '__active_tab'] = array( + $element['#default_tab'] = $displayed_tab; + $element[$name . '__active_tab'] = [ '#type' => 'hidden', '#default_value' => $element['#default_tab'], - '#attributes' => array('class' => array('horizontal-tabs-active-tab')), - ); + '#attributes' => ['class' => ['horizontal-tabs-active-tab']], + ]; + + return $element; + } + + /** + * Arranges elements into groups. + * + * This method is useful for non-input elements that can be used in and + * outside the context of a form. + * + * @param array $element + * An associative array containing the properties and children of the + * element. Note that $element must be taken by reference here, so processed + * child elements are taken over into $form_state. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + * + * @return array + * The processed element. + */ + public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) { + + $groups = &$form_state->getGroups(); + $element['#groups'] = &$groups; + + if (isset($element['#group'])) { + // Add this element to the defined group (by reference). + $group = $element['#group']; + $groups[$group][] = &$element; + } return $element; } diff --git a/web/modules/field_group/src/Element/HtmlElement.php b/web/modules/field_group/src/Element/HtmlElement.php index e58d6e1150..cdb78c5bff 100644 --- a/web/modules/field_group/src/Element/HtmlElement.php +++ b/web/modules/field_group/src/Element/HtmlElement.php @@ -18,27 +18,31 @@ class HtmlElement extends RenderElement { public function getInfo() { $class = get_class($this); - return array( - '#process' => array( - array($class, 'processHtmlElement'), - ), - '#theme_wrappers' => array('field_group_html_element'), - ); + return [ + '#process' => [ + [$class, 'processGroup'], + [$class, 'processHtmlElement'], + ], + '#pre_render' => [ + [$class, 'preRenderGroup'], + ], + '#theme_wrappers' => ['field_group_html_element'], + ]; } /** - * Process a html element + * Process a html element. * * @param array $element * An associative array containing the properties and children of the * details element. - * @param FormStateInterface $form_state + * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @return array * The processed element. */ - public static function processHtmlElement(&$element, FormStateInterface $form_state) { + public static function processHtmlElement(array &$element, FormStateInterface $form_state) { // If an effect is set, we need to load extra js. if (!empty($element['#effect']) && $element['#effect'] !== 'none') { diff --git a/web/modules/field_group/src/Element/VerticalTabs.php b/web/modules/field_group/src/Element/VerticalTabs.php new file mode 100644 index 0000000000..5b56bf4694 --- /dev/null +++ b/web/modules/field_group/src/Element/VerticalTabs.php @@ -0,0 +1,85 @@ +<?php + +namespace Drupal\field_group\Element; + +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; + +/** + * Provides extra processing and pre rendering on the vertical tabs. + */ +class VerticalTabs { + + /** + * Pre render the group to support #group parameter. + * + * @param array $element + * An associative array containing the properties and children of the + * element. + * + * @return array + * The modified element with all group members. + */ + public static function preRenderGroup($element) { + // The element may be rendered outside of a Form API context. + if (!isset($element['#parents']) || !isset($element['#groups'])) { + return $element; + } + + if (isset($element['#group'])) { + // Contains form element summary functionalities. + $element['#attached']['library'][] = 'core/drupal.form'; + + $group = $element['#group']; + // If this element belongs to a group, but the group-holding element does + // not exist, we need to render it (at its original location). + if (!isset($element['#groups'][$group]['#group_exists'])) { + // Intentionally empty to clarify the flow; we simply return $element. + } + // If we injected this element into the group, then we want to render it. + elseif (!empty($element['#group_details'])) { + // Intentionally empty to clarify the flow; we simply return $element. + } + // Otherwise, this element belongs to a group and the group exists, so we do + // not render it. + elseif (Element::children($element['#groups'][$group])) { + $element['#printed'] = TRUE; + } + } + + return $element; + } + + /** + * Arranges elements into groups. + * + * This method is useful for non-input elements that can be used in and + * outside the context of a form. + * + * @param array $element + * An associative array containing the properties and children of the + * element. Note that $element must be taken by reference here, so processed + * child elements are taken over into $form_state. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + * + * @return array + * The processed element. + */ + public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) { + + $groups = &$form_state->getGroups(); + $element['#groups'] = &$groups; + + if (isset($element['#group'])) { + // Add this element to the defined group (by reference). + $group = $element['#group']; + $groups[$group][] = &$element; + } + + return $element; + } + +} diff --git a/web/modules/field_group/src/FieldGroupFormatterBase.php b/web/modules/field_group/src/FieldGroupFormatterBase.php index b9028c9b86..0230b9ac3b 100644 --- a/web/modules/field_group/src/FieldGroupFormatterBase.php +++ b/web/modules/field_group/src/FieldGroupFormatterBase.php @@ -3,6 +3,7 @@ namespace Drupal\field_group; use Drupal\Core\Field\PluginSettingsBase; +use Drupal\Core\Form\FormStateInterface; /** * Base class for 'Fieldgroup formatter' plugin implementations. @@ -13,7 +14,8 @@ abstract class FieldGroupFormatterBase extends PluginSettingsBase implements Fie /** * The group this formatter needs to render. - * @var stdClass + * + * @var object */ protected $group; @@ -52,15 +54,15 @@ abstract class FieldGroupFormatterBase extends PluginSettingsBase implements Fie * The plugin_id for the formatter. * @param mixed $plugin_definition * The plugin implementation definition. - * @param $group + * @param \stdClass $group * The group object. * @param array $settings * The formatter settings. * @param string $label * The formatter label. */ - public function __construct($plugin_id, $plugin_definition, $group, array $settings, $label) { - parent::__construct(array(), $plugin_id, $plugin_definition); + public function __construct($plugin_id, $plugin_definition, \stdClass $group, array $settings, $label) { + parent::__construct([], $plugin_id, $plugin_definition); $this->group = $group; $this->settings = $settings; @@ -70,7 +72,9 @@ public function __construct($plugin_id, $plugin_definition, $group, array $setti /** * Get the current label. + * * @return string + * The current label. */ public function getLabel() { return $this->label; @@ -81,29 +85,31 @@ public function getLabel() { */ public function settingsForm() { - $form = array(); - $form['label'] = array( + $class = get_class($this); + + $form = []; + $form['label'] = [ '#type' => 'textfield', '#title' => t('Field group label'), '#default_value' => $this->label, '#weight' => -5, - ); + ]; - $form['id'] = array( + $form['id'] = [ '#title' => t('ID'), '#type' => 'textfield', '#default_value' => $this->getSetting('id'), '#weight' => 10, - '#element_validate' => array('field_group_validate_id'), - ); + '#element_validate' => [[$class, 'validateId']], + ]; - $form['classes'] = array( + $form['classes'] = [ '#title' => t('Extra CSS classes'), '#type' => 'textfield', '#default_value' => $this->getSetting('classes'), '#weight' => 11, - '#element_validate' => array('field_group_validate_css_class'), - ); + '#element_validate' => [[$class, 'validateCssClass']], + ]; return $form; @@ -114,18 +120,18 @@ public function settingsForm() { */ public function settingsSummary() { - $summary = array(); + $summary = []; if ($this->getSetting('formatter')) { $summary[] = $this->pluginDefinition['label'] . ': ' . $this->getSetting('formatter'); } if ($this->getSetting('id')) { - $summary[] = $this->t('Id: @id', array('@id' => $this->getSetting('id'))); + $summary[] = $this->t('Id: @id', ['@id' => $this->getSetting('id')]); } if ($this->getSetting('classes')) { - $summary[] = \Drupal::translation()->translate('Extra CSS classes: @classes', array('@classes' => $this->getSetting('classes'))); + $summary[] = \Drupal::translation()->translate('Extra CSS classes: @classes', ['@classes' => $this->getSetting('classes')]); } return $summary; @@ -142,10 +148,10 @@ public static function defaultSettings() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - return array( + return [ 'classes' => '', 'id' => '', - ); + ]; } /** @@ -153,7 +159,7 @@ public static function defaultContextSettings($context) { */ protected function getClasses() { - $classes = array(); + $classes = []; // Add a required-fields class to trigger the js. if ($this->getSetting('required_fields')) { $classes[] = 'required-fields'; @@ -176,4 +182,49 @@ public function preRender(&$element, $rendering_object) { $element['#bundle'] = $this->group->bundle; } + /** + * {@inheritdoc} + */ + public function process(&$element, $processed_object) { + + $element['#group_name'] = $this->group->group_name; + $element['#entity_type'] = $this->group->entity_type; + $element['#bundle'] = $this->group->bundle; + + // BC: Call the pre render layer to not break contrib plugins. + return $this->preRender($element, $processed_object); + } + + /** + * Validate the entered css class from the submitted format settings. + * + * @param array $element + * The validated element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The state of the form. + */ + public static function validateCssClass(array $element, FormStateInterface $form_state) { + $form_state_values = $form_state->getValues(); + $plugin_name = $form_state->get('plugin_settings_edit'); + if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes']) && !preg_match('!^[A-Za-z0-9-_ ]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes'])) { + $form_state->setError($element, t('The css class must include only letters, numbers, underscores and dashes.')); + } + } + + /** + * Validate the entered id attribute from the submitted format settings. + * + * @param array $element + * The validated element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The state of the form. + */ + public static function validateId(array $element, FormStateInterface $form_state) { + $form_state_values = $form_state->getValues(); + $plugin_name = $form_state->get('plugin_settings_edit'); + if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id']) && !preg_match('!^[A-Za-z0-9-_]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id'])) { + $form_state->setError($element, t('The id must include only letters, numbers, underscores and dashes.')); + } + } + } diff --git a/web/modules/field_group/src/FieldGroupFormatterInterface.php b/web/modules/field_group/src/FieldGroupFormatterInterface.php index 538e8007b8..fc9dc82c48 100644 --- a/web/modules/field_group/src/FieldGroupFormatterInterface.php +++ b/web/modules/field_group/src/FieldGroupFormatterInterface.php @@ -11,6 +11,18 @@ */ interface FieldGroupFormatterInterface extends PluginInspectionInterface { + /** + * Allows the field group formatter to manipulate the field group array and attach the formatters elements. + * The process method is called in the #process part of theme layer, and is currently used for forms. + * The preRender method is called in the #pre_render part of the theme layer, and is currently used for entity displays. + * + * @param array $element + * The field group render array. + * @param object $processed_object + * The object / entity beïng processed. + */ + public function process(&$element, $processed_object); + /** * Allows the field group formatter to manipulate the field group array and attach the formatters rendering element. * @@ -39,7 +51,7 @@ public function settingsForm(); * If an empty result is returned, a UI can still be provided to display * a settings form in case the formatter has configurable settings. * - * @return array() + * @return array * A short summary of the formatter settings. */ public function settingsSummary(); diff --git a/web/modules/field_group/src/FieldGroupFormatterPluginManager.php b/web/modules/field_group/src/FieldGroupFormatterPluginManager.php index 939bc3000a..f93afbe168 100644 --- a/web/modules/field_group/src/FieldGroupFormatterPluginManager.php +++ b/web/modules/field_group/src/FieldGroupFormatterPluginManager.php @@ -20,8 +20,6 @@ class FieldGroupFormatterPluginManager extends DefaultPluginManager { * keyed by the corresponding namespace to look for plugin implementations. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * Cache backend instance to use. - * @param \Drupal\Core\Language\LanguageManager $language_manager - * The language manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler to invoke the alter hook with. */ @@ -35,7 +33,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac /** * {@inheritdoc} */ - public function createInstance($plugin_id, array $configuration = array()) { + public function createInstance($plugin_id, array $configuration = []) { $plugin_definition = $this->getDefinition($plugin_id); $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition); @@ -86,9 +84,9 @@ public function getInstance(array $options) { return NULL; } - $configuration += array( + $configuration += [ 'group' => $options['group'], - ); + ]; return $this->createInstance($plugin_id, $configuration); } @@ -97,21 +95,20 @@ public function getInstance(array $options) { * Merges default values for formatter configuration. * * @param string $format_type - * The format type + * The format type. * @param string $context * The context to prepare configuration for. - * @param array $properties - * An array of formatter configuration. - * + * @param array $configuration + * The configuration of the group. * @return array * The display properties with defaults added. */ public function prepareConfiguration($format_type, $context, array $configuration) { // Fill in defaults for missing properties. - $configuration += array( + $configuration += [ 'label' => '', - 'settings' => array(), - ); + 'settings' => [], + ]; // Fill in default settings values for the formatter. $configuration['settings'] += $this->getDefaultSettings($format_type, $context); @@ -137,7 +134,7 @@ public function getDefaultSettings($type, $context) { $plugin_class = DefaultFactory::getPluginClass($type, $plugin_definition); return $plugin_class::defaultContextSettings($context); } - return array(); + return []; } } diff --git a/web/modules/field_group/src/FieldgroupUi.php b/web/modules/field_group/src/FieldgroupUi.php index fa9514a6a3..1c0c98c544 100644 --- a/web/modules/field_group/src/FieldgroupUi.php +++ b/web/modules/field_group/src/FieldgroupUi.php @@ -1,6 +1,7 @@ <?php namespace Drupal\field_group; + use Drupal\Core\Url; use Drupal\field_ui\FieldUI; @@ -11,7 +12,8 @@ class FieldgroupUi { /** * Get the field ui route that should be used for given arguments. - * @param stdClass $group + * + * @param object $group * The group to get the field ui route for. * * @return \Drupal\Core\Url @@ -52,12 +54,14 @@ public static function getFieldUiRoute($group) { /** * Get the field group delete route for a given group. + * * @param \stdClass $group + * The group to delete. * * @return \Drupal\Core\Url * A URL object. */ - public static function getDeleteRoute($group) { + public static function getDeleteRoute(\stdClass $group) { $entity_type_id = $group->entity_type; $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id); @@ -94,4 +98,4 @@ public static function getDeleteRoute($group) { } -} \ No newline at end of file +} diff --git a/web/modules/field_group/src/Form/FieldGroupAddForm.php b/web/modules/field_group/src/Form/FieldGroupAddForm.php index de37914cda..987a3757b2 100644 --- a/web/modules/field_group/src/Form/FieldGroupAddForm.php +++ b/web/modules/field_group/src/Form/FieldGroupAddForm.php @@ -4,8 +4,12 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\field\Entity\FieldStorageConfig; +use Drupal\field_group\FieldGroupFormatterPluginManager; use Drupal\field_group\FieldgroupUi; +use Drupal\field_group\FormatterHelper; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Provides a form for adding a fieldgroup to a bundle. @@ -54,6 +58,43 @@ class FieldGroupAddForm extends FormBase { */ protected $currentStep; + /** + * The field group formatter plugin manager. + * + * @var \Drupal\field_group\FieldGroupFormatterPluginManager + */ + protected $fieldGroupFormatterPluginManager; + + /** + * The messenger. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + + /** + * FieldGroupAddForm constructor. + * + * @param \Drupal\field_group\FieldGroupFormatterPluginManager $fieldGroupFormatterPluginManager + * The field group formatter plugin manager. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger. + */ + public function __construct(FieldGroupFormatterPluginManager $fieldGroupFormatterPluginManager, MessengerInterface $messenger) { + $this->fieldGroupFormatterPluginManager = $fieldGroupFormatterPluginManager; + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.field_group.formatters'), + $container->get('messenger') + ); + } + /** * {@inheritdoc} */ @@ -66,6 +107,10 @@ public function getFormId() { */ public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL, $context = NULL) { + $this->entityTypeId = $entity_type_id; + $this->bundle = $bundle; + $this->context = $context; + if ($context == 'form') { $this->mode = \Drupal::request()->get('form_mode_name'); } @@ -77,22 +122,9 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t $this->mode = 'default'; } - if (!$form_state->get('context')) { - $form_state->set('context', $context); - } - if (!$form_state->get('entity_type_id')) { - $form_state->set('entity_type_id', $entity_type_id); - } - if (!$form_state->get('bundle')) { - $form_state->set('bundle', $bundle); - } if (!$form_state->get('step')) { $form_state->set('step', 'formatter'); } - - $this->entityTypeId = $form_state->get('entity_type_id'); - $this->bundle = $form_state->get('bundle'); - $this->context = $form_state->get('context'); $this->currentStep = $form_state->get('step'); if ($this->currentStep == 'formatter') { @@ -103,46 +135,45 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } return $form; - } /** * Build the formatter selection step. */ - function buildFormatterSelectionForm(array &$form, FormStateInterface $form_state) { + public function buildFormatterSelectionForm(array &$form, FormStateInterface $form_state) { // Gather group formatters. - $formatter_options = \field_group_field_formatter_options($form_state->get('context')); - $form['add'] = array( + $formatter_options = FormatterHelper::formatterOptions($this->context); + $form['add'] = [ '#type' => 'container', - '#attributes' => array('class' => array('form--inline', 'clearfix')), - ); + '#attributes' => ['class' => ['form--inline', 'clearfix']], + ]; - $form['add']['group_formatter'] = array( + $form['add']['group_formatter'] = [ '#type' => 'select', '#title' => $this->t('Add a new group'), '#options' => $formatter_options, '#empty_option' => $this->t('- Select a group type -'), '#required' => TRUE, - ); + ]; // Field label and field_name. - $form['new_group_wrapper'] = array( + $form['new_group_wrapper'] = [ '#type' => 'container', - '#states' => array( - '!visible' => array( - ':input[name="group_formatter"]' => array('value' => ''), - ), - ), - ); - $form['new_group_wrapper']['label'] = array( + '#states' => [ + '!visible' => [ + ':input[name="group_formatter"]' => ['value' => ''], + ], + ], + ]; + $form['new_group_wrapper']['label'] = [ '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 15, '#required' => TRUE, - ); + ]; - $form['new_group_wrapper']['group_name'] = array( + $form['new_group_wrapper']['group_name'] = [ '#type' => 'machine_name', '#size' => 15, // This field should stay LTR even for RTL languages. @@ -150,22 +181,22 @@ function buildFormatterSelectionForm(array &$form, FormStateInterface $form_stat '#field_suffix' => '</span>‎', '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'), '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen(self::GROUP_PREFIX), - '#machine_name' => array( - 'source' => array('new_group_wrapper', 'label'), - 'exists' => array($this, 'groupNameExists'), - ), + '#machine_name' => [ + 'source' => ['new_group_wrapper', 'label'], + 'exists' => [$this, 'groupNameExists'], + ], '#required' => TRUE, - ); + ]; - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( + $form['actions'] = ['#type' => 'actions']; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Save and continue'), '#button_type' => 'primary', - '#validate' => array( - array($this, 'validateFormatterSelection') - ), - ); + '#validate' => [ + [$this, 'validateFormatterSelection'], + ], + ]; $form['#attached']['library'][] = 'field_ui/drupal.field_ui'; } @@ -173,7 +204,7 @@ function buildFormatterSelectionForm(array &$form, FormStateInterface $form_stat /** * Build the formatter configuration form. */ - function buildConfigurationForm(array &$form, FormStateInterface $form_state) { + public function buildConfigurationForm(array &$form, FormStateInterface $form_state) { $group = new \stdClass(); $group->context = $this->context; @@ -182,27 +213,27 @@ function buildConfigurationForm(array &$form, FormStateInterface $form_state) { $group->mode = $this->mode; $manager = \Drupal::service('plugin.manager.field_group.formatters'); - $plugin = $manager->getInstance(array( + $plugin = $manager->getInstance([ 'format_type' => $form_state->getValue('group_formatter'), 'configuration' => [ 'label' => $form_state->getValue('label'), ], 'group' => $group, - )); + ]); - $form['format_settings'] = array( + $form['format_settings'] = [ '#type' => 'container', '#tree' => TRUE, - ); + ]; $form['format_settings'] += $plugin->settingsForm(); - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( + $form['actions'] = ['#type' => 'actions']; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Create group'), '#button_type' => 'primary', - ); + ]; } @@ -231,29 +262,29 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } else { - $new_group = (object) array( + $new_group = (object) [ 'group_name' => $form_state->get('group_name'), 'entity_type' => $this->entityTypeId, 'bundle' => $this->bundle, 'mode' => $this->mode, 'context' => $this->context, - 'children' =>[], + 'children' => [], 'parent_name' => '', 'weight' => 20, 'format_type' => $form_state->get('group_formatter'), - ); + ]; $new_group->format_settings = $form_state->getValue('format_settings'); $new_group->label = $new_group->format_settings['label']; unset($new_group->format_settings['label']); - $new_group->format_settings += _field_group_get_default_formatter_settings($form_state->get('group_formatter'), $this->context); + $new_group->format_settings += $this->fieldGroupFormatterPluginManager->getDefaultSettings($form_state->get('group_formatter'), $this->context); field_group_group_save($new_group); // Store new group information for any additional submit handlers. $groups_added = $form_state->get('groups_added'); $groups_added['_add_new_group'] = $new_group->group_name; - drupal_set_message(t('New group %label successfully created.', array('%label' => $new_group->label))); + $this->messenger->addMessage(t('New group %label successfully created.', ['%label' => $new_group->label])); $form_state->setRedirectUrl(FieldgroupUi::getFieldUiRoute($new_group)); \Drupal::cache()->invalidate('field_groups'); @@ -269,22 +300,18 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * The machine name, not prefixed. * @param array $element * An array containing the structure of the 'group_name' element. - * @param FormStateInterface $form_state + * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @return bool * Whether or not the group machine name is taken. */ - public function groupNameExists($value, $element, FormStateInterface $form_state) { + public function groupNameExists($value, array $element, FormStateInterface $form_state) { // Add the prefix. $group_name = self::GROUP_PREFIX . $value; - $entity_type = $form_state->get('entity_type_id'); - $bundle = $form_state->get('bundle'); - $context = $form_state->get('context'); - $mode = $form_state->get('mode'); - return field_group_exists($group_name, $entity_type, $bundle, $context, $mode); + return field_group_exists($group_name, $this->entityTypeId, $this->bundle, $this->context, $this->mode); } } diff --git a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php index 1b82729234..3cf86b88f9 100644 --- a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php +++ b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php @@ -4,7 +4,9 @@ use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\field_group\FieldgroupUi; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Provides a form for removing a fieldgroup from a bundle. @@ -14,10 +16,36 @@ class FieldGroupDeleteForm extends ConfirmFormBase { /** * The fieldgroup to delete. * - * @var stdClass + * @var object */ protected $fieldGroup; + /** + * The messenger. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + + /** + * FieldGroupDeleteForm constructor. + * + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger. + */ + public function __construct(MessengerInterface $messenger) { + $this->messenger = $messenger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('messenger') + ); + } + /** * {@inheritdoc} */ @@ -25,6 +53,9 @@ public function getFormId() { return 'field_group_delete_form'; } + /** + * {@inheritdoc} + */ public function buildForm(array $form, FormStateInterface $form_state, $field_group_name = NULL, $entity_type_id = NULL, $bundle = NULL, $context = NULL) { if ($context == 'form') { @@ -46,12 +77,12 @@ public function buildForm(array $form, FormStateInterface $form_state, $field_gr * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - $bundles = entity_get_bundles(); + $bundles = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo(); $bundle_label = $bundles[$this->fieldGroup->entity_type][$this->fieldGroup->bundle]['label']; field_group_group_delete($this->fieldGroup); - drupal_set_message(t('The group %group has been deleted from the %type content type.', array('%group' => t($this->fieldGroup->label), '%type' => $bundle_label))); + $this->messenger->addMessage(t('The group %group has been deleted from the %type content type.', ['%group' => t($this->fieldGroup->label), '%type' => $bundle_label])); // Redirect. $form_state->setRedirectUrl($this->getCancelUrl()); @@ -62,7 +93,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { * {@inheritdoc} */ public function getQuestion() { - return $this->t('Are you sure you want to delete the group %group?', array('%group' => t($this->fieldGroup->label))); + return $this->t('Are you sure you want to delete the group %group?', ['%group' => t($this->fieldGroup->label)]); } /** diff --git a/web/modules/field_group/src/FormatterHelper.php b/web/modules/field_group/src/FormatterHelper.php new file mode 100644 index 0000000000..436d7d71ca --- /dev/null +++ b/web/modules/field_group/src/FormatterHelper.php @@ -0,0 +1,34 @@ +<?php + +namespace Drupal\field_group; + +use Drupal; + +/** + * Static methods for fieldgroup formatters. + */ +class FormatterHelper { + + /** + * Return an array of field_group_formatter options. + */ + public static function formatterOptions($type) { + $options = &drupal_static(__FUNCTION__); + + if (!isset($options)) { + $options = []; + + $manager = Drupal::service('plugin.manager.field_group.formatters'); + $formatters = $manager->getDefinitions(); + + foreach ($formatters as $formatter) { + if (in_array($type, $formatter['supported_contexts'])) { + $options[$formatter['id']] = $formatter['label']; + } + } + } + + return $options; + } + +} diff --git a/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php b/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php index 96bd638bb7..64972b603c 100644 --- a/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php +++ b/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php @@ -57,7 +57,7 @@ public static function create(ContainerInterface $container, $base_plugin_id) { * {@inheritdoc} */ public function getDerivativeDefinitions($base_plugin_definition) { - $this->derivatives = array(); + $this->derivatives = []; foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->get('field_ui_base_route')) { diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php index 378f5897f5..75444dfd71 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php @@ -2,6 +2,7 @@ namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter; +use Drupal\field_group\Element\Accordion as AccordionElement; use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormState; use Drupal\field_group\FieldGroupFormatterBase; @@ -24,26 +25,35 @@ class Accordion extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { - $form_state = new FormState(); + // Keep using preRender parent for BC. + parent::preRender($element, $processed_object); - $element += array( + $element += [ '#type' => 'field_group_accordion', '#effect' => $this->getSetting('effect'), - ); + ]; if ($this->getSetting('id')) { - $element['#id'] = Html::getId($this->getSetting('id')); + $element['#id'] = Html::getUniqueId($this->getSetting('id')); } $classes = $this->getClasses(); if (!empty($classes)) { - $element += array('#attributes' => array('class' => $classes)); + $element += ['#attributes' => ['class' => $classes]]; } - \Drupal\field_group\Element\Accordion::processAccordion($element, $form_state); + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + $this->process($element, $rendering_object); + + $form_state = new FormState(); + AccordionElement::processAccordion($element, $form_state); } /** @@ -53,13 +63,13 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['effect'] = array( + $form['effect'] = [ '#title' => $this->t('Effect'), '#type' => 'select', - '#options' => array('none' => $this->t('None'), 'bounceslide' => $this->t('Bounce slide')), + '#options' => ['none' => $this->t('None'), 'bounceslide' => $this->t('Bounce slide')], '#default_value' => $this->getSetting('effect'), '#weight' => 2, - ); + ]; return $form; } @@ -69,9 +79,9 @@ public function settingsForm() { */ public function settingsSummary() { - $summary = array(); + $summary = []; $summary[] = $this->t('Effect : @effect', - array('@effect' => $this->getSetting('effect')) + ['@effect' => $this->getSetting('effect')] ); return $summary; @@ -81,9 +91,9 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - return array( + return [ 'effect' => 'none', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); } } diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php index a92ee3c09f..afab3bc4a1 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php @@ -2,7 +2,6 @@ namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter; -use Drupal; use Drupal\Component\Utility\Html; use Drupal\field_group\FieldGroupFormatterBase; @@ -28,29 +27,48 @@ class AccordionItem extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { - $element += array( + // Keep using preRender parent for BC. + parent::preRender($element, $processed_object); + + $element += [ '#type' => 'field_group_accordion_item', - '#open' => $this->getSetting('formatter') == 'open' ? TRUE : FALSE, - '#description' => $this->getSetting('description'), - '#title' => Drupal::translation()->translate($this->getLabel()), - ); + '#effect' => $this->getSetting('effect'), + '#title' => Html::escape($this->t($this->getLabel())), + ]; if ($this->getSetting('id')) { - $element['#id'] = Html::getId($this->getSetting('id')); + $element['#id'] = Html::getUniqueId($this->getSetting('id')); } $classes = $this->getClasses(); if (!empty($classes)) { - $element += array('#attributes' => array('class' => $classes)); + $element += ['#attributes' => ['class' => $classes]]; } if ($this->getSetting('required_fields')) { $element['#attached']['library'][] = 'field_group/formatter.details'; } + if ($this->getSetting('formatter') == 'open') { + $element['#open'] = TRUE; + } + + foreach ($element as $key => $value) { + if (is_array($value) && !empty($value['#children_errors'])) { + $element['#open'] = TRUE; + } + } + + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + parent::preRender($element, $rendering_object); + $this->process($element, $rendering_object); } /** @@ -60,21 +78,21 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['formatter'] = array( + $form['formatter'] = [ '#title' => $this->t('Default state'), '#type' => 'select', '#options' => array_combine($this->pluginDefinition['format_types'], $this->pluginDefinition['format_types']), '#default_value' => $this->getSetting('formatter'), '#weight' => -4, - ); + ]; if ($this->context == 'form') { - $form['required_fields'] = array( + $form['required_fields'] = [ '#type' => 'checkbox', '#title' => $this->t('Mark group as required if it contains required fields.'), '#default_value' => $this->getSetting('required_fields'), '#weight' => 2, - ); + ]; } return $form; @@ -85,7 +103,7 @@ public function settingsForm() { */ public function settingsSummary() { - $summary = array(); + $summary = []; if ($this->getSetting('required_fields')) { $summary[] = $this->t('Mark as required'); @@ -93,7 +111,7 @@ public function settingsSummary() { if ($this->getSetting('description')) { $summary[] = $this->t('Description : @description', - array('@description' => $this->getSetting('description')) + ['@description' => $this->getSetting('description')] ); } @@ -104,10 +122,10 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - $defaults = array( + $defaults = [ 'formatter' => 'closed', 'description' => '', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); if ($context == 'form') { $defaults['required_fields'] = 1; diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php index 8a78c6e820..d1384cc1c6 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php @@ -23,36 +23,39 @@ class Details extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { - $element += array( + $element += [ '#type' => 'details', '#title' => Html::escape($this->t($this->getLabel())), - '#open' => $this->getSetting('open') - ); + '#open' => $this->getSetting('open'), + '#description' => $this->getSetting('description'), + ]; if ($this->getSetting('id')) { - $element['#id'] = Html::getId($this->getSetting('id')); + $element['#id'] = Html::getUniqueId($this->getSetting('id')); } $classes = $this->getClasses(); if (!empty($classes)) { - $element += array( - '#attributes' => array('class' => $classes), - ); - } - - if ($this->getSetting('description')) { - $element += array( - '#description' => $this->getSetting('description'), - ); + $element += [ + '#attributes' => ['class' => $classes], + ]; } if ($this->getSetting('required_fields')) { $element['#attached']['library'][] = 'field_group/formatter.details'; $element['#attached']['library'][] = 'field_group/core'; } + + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + parent::preRender($element, $rendering_object); + $this->process($element, $rendering_object); } /** @@ -61,19 +64,26 @@ public function preRender(&$element, $rendering_object) { public function settingsForm() { $form = parent::settingsForm(); - $form['open'] = array( + $form['description'] = [ + '#title' => $this->t('Description'), + '#type' => 'textarea', + '#default_value' => $this->getSetting('description'), + '#weight' => -4, + ]; + + $form['open'] = [ '#type' => 'checkbox', '#title' => $this->t('Display element open by default.'), '#default_value' => $this->getSetting('open'), - ); + ]; if ($this->context == 'form') { - $form['required_fields'] = array( + $form['required_fields'] = [ '#type' => 'checkbox', '#title' => $this->t('Mark group as required if it contains required fields.'), '#default_value' => $this->getSetting('required_fields'), '#weight' => 2, - ); + ]; } return $form; @@ -84,7 +94,7 @@ public function settingsForm() { */ public function settingsSummary() { - $summary = array(); + $summary = []; if ($this->getSetting('open')) { $summary[] = $this->t('Default state open'); } @@ -103,10 +113,10 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - $defaults = array( + $defaults = [ 'open' => FALSE, 'required_fields' => $context == 'form', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); if ($context == 'form') { $defaults['required_fields'] = 1; diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php index ecbf217dac..4245b7ee35 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php @@ -23,40 +23,42 @@ class Fieldset extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { + public function process(&$element, $processed_object) { - $element += array( + $element += [ '#type' => 'fieldset', '#title' => Html::escape($this->t($this->getLabel())), - '#pre_render' => array(), - '#attributes' => array(), - ); - - if ($this->getSetting('description')) { - $element += array( - '#description' => $this->getSetting('description'), - ); - - // When a fieldset has a description, an id is required. - if (!$this->getSetting('id')) { - $element['#id'] = Html::getId($this->group->group_name); - } + '#attributes' => [], + '#description' => $this->getSetting('description'), + ]; + // When a fieldset has a description, an id is required. + if ($this->getSetting('description') && !$this->getSetting('id')) { + $element['#id'] = Html::getUniqueId($this->group->group_name); } if ($this->getSetting('id')) { - $element['#id'] = Html::getId($this->getSetting('id')); + $element['#id'] = Html::getUniqueId($this->getSetting('id')); } $classes = $this->getClasses(); if (!empty($classes)) { - $element['#attributes'] += array('class' => $classes); + $element['#attributes'] += ['class' => $classes]; } if ($this->getSetting('required_fields')) { $element['#attached']['library'][] = 'field_group/formatter.fieldset'; $element['#attached']['library'][] = 'field_group/core'; } + + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + parent::preRender($element, $rendering_object); + $this->process($element, $rendering_object); } /** @@ -66,20 +68,20 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['description'] = array( + $form['description'] = [ '#title' => $this->t('Description'), '#type' => 'textarea', '#default_value' => $this->getSetting('description'), '#weight' => -4, - ); + ]; if ($this->context == 'form') { - $form['required_fields'] = array( + $form['required_fields'] = [ '#type' => 'checkbox', '#title' => $this->t('Mark group as required if it contains required fields.'), '#default_value' => $this->getSetting('required_fields'), '#weight' => 2, - ); + ]; } return $form; @@ -96,12 +98,6 @@ public function settingsSummary() { $summary[] = $this->t('Mark as required'); } - if ($this->getSetting('description')) { - $summary[] = $this->t('Description : @description', - array('@description' => $this->getSetting('description')) - ); - } - return $summary; } @@ -109,9 +105,9 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - $defaults = array( + $defaults = [ 'description' => '', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); if ($context == 'form') { $defaults['required_fields'] = 1; diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php index 41f2d7e4e3..60e4d539c1 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php @@ -2,6 +2,7 @@ namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter; +use Drupal\field_group\Element\HtmlElement as HtmlElementRenderElement; use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormState; use Drupal\Core\Template\Attribute; @@ -25,8 +26,10 @@ class HtmlElement extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { + + // Keep using preRender parent for BC. + parent::preRender($element, $processed_object); $element_attributes = new Attribute(); @@ -45,18 +48,18 @@ public function preRender(&$element, $rendering_object) { // Add the id to the attributes array. if ($this->getSetting('id')) { - $element_attributes['id'] = Html::getId($this->getSetting('id')); + $element_attributes['id'] = Html::getUniqueId($this->getSetting('id')); } // Add the classes to the attributes array. $classes = $this->getClasses(); if (!empty($classes)) { if (!isset($element_attributes['class'])) { - $element_attributes['class'] = array(); + $element_attributes['class'] = []; } // If user also entered class in the attributes textfield, force it to an array. else { - $element_attributes['class'] = array($element_attributes['class']); + $element_attributes['class'] = [$element_attributes['class']]; } $element_attributes['class'] = array_merge($classes, $element_attributes['class']->value()); } @@ -69,10 +72,16 @@ public function preRender(&$element, $rendering_object) { if ($this->getSetting('show_label')) { $element['#title_element'] = $this->getSetting('label_element'); $element['#title'] = Html::escape($this->t($this->getLabel())); - } + $element['#title_attributes'] = new Attribute(); - $form_state = new FormState(); - \Drupal\field_group\Element\HtmlElement::processHtmlElement($element, $form_state); + if (!empty($this->getSetting('label_element_classes'))) { + $element['#title_attributes']->addClass(explode(' ', $this->getSetting('label_element_classes'))); + } + + if (!empty($this->getSetting('effect')) && $this->getSetting('effect') !== 'none') { + $element['#title_attributes']->addClass('field-group-toggler'); + } + } if ($this->getSetting('required_fields')) { $element['#attributes']['class'][] = 'field-group-html-element'; @@ -81,6 +90,16 @@ public function preRender(&$element, $rendering_object) { } } + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + $this->process($element, $rendering_object); + + $form_state = new FormState(); + HtmlElementRenderElement::processHtmlElement($element, $form_state); + } + /** * {@inheritdoc} */ @@ -88,81 +107,93 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['element'] = array( + $form['element'] = [ '#title' => $this->t('Element'), '#type' => 'textfield', '#default_value' => $this->getSetting('element'), '#description' => $this->t('E.g. div, section, aside etc.'), '#weight' => 1, - ); + ]; - $form['show_label'] = array( + $form['show_label'] = [ '#title' => $this->t('Show label'), '#type' => 'select', - '#options' => array(0 => $this->t('No'), 1 => $this->t('Yes')), + '#options' => [0 => $this->t('No'), 1 => $this->t('Yes')], '#default_value' => $this->getSetting('show_label'), '#weight' => 2, - '#attributes' => array( - 'data-fieldgroup-selector' => 'show_label' - ), - ); + '#attributes' => [ + 'data-fieldgroup-selector' => 'show_label', + ], + ]; - $form['label_element'] = array( + $form['label_element'] = [ '#title' => $this->t('Label element'), '#type' => 'textfield', '#default_value' => $this->getSetting('label_element'), '#weight' => 3, - '#states' => array( - 'visible' => array( - ':input[data-fieldgroup-selector="show_label"]' => array('value' => 1), - ), - ), - ); + '#states' => [ + 'visible' => [ + ':input[data-fieldgroup-selector="show_label"]' => ['value' => 1], + ], + ], + ]; + + $form['label_element_classes'] = [ + '#title' => $this->t('Label element HTML classes'), + '#type' => 'textfield', + '#default_value' => $this->getSetting('label_element_classes'), + '#weight' => 3, + '#states' => [ + 'visible' => [ + ':input[data-fieldgroup-selector="show_label"]' => ['value' => 1], + ], + ], + ]; if ($this->context == 'form') { - $form['required_fields'] = array( + $form['required_fields'] = [ '#title' => $this->t('Mark group as required if it contains required fields.'), '#type' => 'checkbox', '#default_value' => $this->getSetting('required_fields'), '#weight' => 4, - ); + ]; } - $form['attributes'] = array( + $form['attributes'] = [ '#title' => $this->t('Attributes'), '#type' => 'textfield', '#default_value' => $this->getSetting('attributes'), '#description' => $this->t('E.g. name="anchor"'), '#weight' => 5, - ); + ]; - $form['effect'] = array( + $form['effect'] = [ '#title' => $this->t('Effect'), '#type' => 'select', - '#options' => array( + '#options' => [ 'none' => $this->t('None'), 'collapsible' => $this->t('Collapsible'), - 'blind' => $this->t('Blind') - ), + 'blind' => $this->t('Blind'), + ], '#default_value' => $this->getSetting('effect'), '#weight' => 6, - '#attributes' => array( - 'data-fieldgroup-selector' => 'effect' - ), - ); + '#attributes' => [ + 'data-fieldgroup-selector' => 'effect', + ], + ]; - $form['speed'] = array( + $form['speed'] = [ '#title' => $this->t('Speed'), '#type' => 'select', - '#options' => array('slow' => $this->t('Slow'), 'fast' => $this->t('Fast')), + '#options' => ['slow' => $this->t('Slow'), 'fast' => $this->t('Fast')], '#default_value' => $this->getSetting('speed'), '#weight' => 7, - '#states' => array( - '!visible' => array( - ':input[data-fieldgroup-selector="effect"]' => array('value' => 'none'), - ), - ), - ); + '#states' => [ + '!visible' => [ + ':input[data-fieldgroup-selector="effect"]' => ['value' => 'none'], + ], + ], + ]; return $form; } @@ -174,18 +205,23 @@ public function settingsSummary() { $summary = parent::settingsSummary(); $summary[] = $this->t('Element: @element', - array('@element' => $this->getSetting('element')) + ['@element' => $this->getSetting('element')] ); if ($this->getSetting('show_label')) { $summary[] = $this->t('Label element: @element', - array('@element' => $this->getSetting('label_element')) + ['@element' => $this->getSetting('label_element')] ); + if (!empty($this->getSetting('label_element_classes'))) { + $summary[] = $this->t('Label element HTML classes: @label_classes', [ + '@label_classes' => $this->getSetting('label_element_classes'), + ]); + } } if ($this->getSetting('attributes')) { $summary[] = $this->t('Attributes: @attributes', - array('@attributes' => $this->getSetting('attributes')) + ['@attributes' => $this->getSetting('attributes')] ); } @@ -200,14 +236,15 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - $defaults = array( + $defaults = [ 'element' => 'div', 'show_label' => 0, 'label_element' => 'h3', + 'label_element_classes' => '', 'effect' => 'none', 'speed' => 'fast', 'attributes' => '', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); if ($context == 'form') { $defaults['required_fields'] = 1; diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php index 7cc8a64456..fe58da6dfb 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php @@ -19,7 +19,7 @@ * supported_contexts = { * "form", * "view", - * }, + * } * ) */ class Tab extends FieldGroupFormatterBase { @@ -27,40 +27,36 @@ class Tab extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { - $add = array( + // Keep using preRender parent for BC. + parent::preRender($element, $processed_object); + + $add = [ '#type' => 'details', '#title' => Html::escape($this->t($this->getLabel())), '#description' => $this->getSetting('description'), - ); + '#group' => $this->group->parent_name, + ]; if ($this->getSetting('id')) { - $add['#id'] = Html::getId($this->getSetting('id')); + $add['#id'] = Html::getUniqueId($this->getSetting('id')); } else { - $add['#id'] = Html::getId('edit-' . $this->group->group_name); + $add['#id'] = Html::getUniqueId('edit-' . $this->group->group_name); } $classes = $this->getClasses(); if (!empty($classes)) { - $element += array( - '#attributes' => array('class' => $classes), - ); + $element += [ + '#attributes' => ['class' => $classes], + ]; } if ($this->getSetting('formatter') == 'open') { $element['#open'] = TRUE; } - // Front-end and back-end on configuration will lead - // to vertical tabs nested in a separate vertical group. - if (!empty($this->group->parent_name)) { - $add['#group'] = $this->group->parent_name; - $add['#parents'] = array($add['#group']); - } - if ($this->getSetting('required_fields')) { $element['#attached']['library'][] = 'field_group/formatter.tabs'; $element['#attached']['library'][] = 'field_group/core'; @@ -70,6 +66,14 @@ public function preRender(&$element, $rendering_object) { } + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + parent::preRender($element, $rendering_object); + $this->process($element, $rendering_object); + } + /** * {@inheritdoc} */ @@ -77,28 +81,28 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['formatter'] = array( + $form['description'] = [ + '#title' => $this->t('Description'), + '#type' => 'textarea', + '#default_value' => $this->getSetting('description'), + '#weight' => -4, + ]; + + $form['formatter'] = [ '#title' => $this->t('Default state'), '#type' => 'select', '#options' => array_combine($this->pluginDefinition['format_types'], $this->pluginDefinition['format_types']), '#default_value' => $this->getSetting('formatter'), '#weight' => -4, - ); - - $form['description'] = array( - '#title' => $this->t('Description'), - '#type' => 'textarea', - '#default_value' => $this->getSetting('description'), - '#weight' => -4, - ); + ]; if ($this->context == 'form') { - $form['required_fields'] = array( + $form['required_fields'] = [ '#type' => 'checkbox', '#title' => $this->t('Mark group as required if it contains required fields.'), '#default_value' => $this->getSetting('required_fields'), '#weight' => 2, - ); + ]; } return $form; @@ -108,10 +112,10 @@ public function settingsForm() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - $defaults = array( + $defaults = [ 'formatter' => 'closed', 'description' => '', - ) + parent::defaultSettings($context); + ] + parent::defaultSettings($context); if ($context == 'form') { $defaults['required_fields'] = 1; diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php index 4f49ec3343..56d58d45db 100644 --- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php +++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php @@ -27,19 +27,21 @@ class Tabs extends FieldGroupFormatterBase { /** * {@inheritdoc} */ - public function preRender(&$element, $rendering_object) { - parent::preRender($element, $rendering_object); + public function process(&$element, $processed_object) { + + // Keep using preRender parent for BC. + parent::preRender($element, $processed_object); - $element += array( - '#prefix' => '<div class=" ' . implode(' ' , $this->getClasses()) . '">', + $element += [ + '#prefix' => '<div class=" ' . implode(' ', $this->getClasses()) . '">', '#suffix' => '</div>', '#tree' => TRUE, - '#parents' => array($this->group->group_name), + '#parents' => [$this->group->group_name], '#default_tab' => '', - ); + ]; if ($this->getSetting('id')) { - $element['#id'] = Html::getId($this->getSetting('id')); + $element['#id'] = Html::getUniqueId($this->getSetting('id')); } // By default tabs don't have titles but you can override it in the theme. @@ -47,39 +49,44 @@ public function preRender(&$element, $rendering_object) { $element['#title'] = Html::escape($this->getLabel()); } - $form_state = new FormState(); + $element += [ + '#type' => $this->getSetting('direction') . '_tabs', + '#theme_wrappers' => [$this->getSetting('direction') . '_tabs'], + ]; - if ($this->getSetting('direction') == 'vertical') { + // Search for a tab that was marked as open. First one wins. + foreach (Element::children($element) as $tab_name) { + if (!empty($element[$tab_name]['#open'])) { + $element[$this->group->group_name . '__active_tab']['#default_value'] = $tab_name; + break; + } + } - $element += array( - '#type' => 'vertical_tabs', - '#theme_wrappers' => array('vertical_tabs'), - ); - $complete_form = array(); + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object) { + + $this->process($element, $rendering_object); + + if ($this->getSetting('direction') == 'vertical') { + $form_state = new FormState(); + $complete_form = []; $element = VerticalTabs::processVerticalTabs($element, $form_state, $complete_form); } else { - $element += array( - '#type' => 'horizontal_tabs', - '#theme_wrappers' => array('horizontal_tabs'), - ); - $on_form = $this->context == 'form'; - $element = HorizontalTabs::processHorizontalTabs($element, $form_state, $on_form); + $form_state = new FormState(); + $complete_form = []; + $element = HorizontalTabs::processHorizontalTabs($element, $form_state, $complete_form); } // Make sure the group has 1 child. This is needed to succeed at form_pre_render_vertical_tabs(). // Skipping this would force us to move all child groups to this array, making it an un-nestable. - $element['group']['#groups'][$this->group->group_name] = array(0 => array()); + $element['group']['#groups'][$this->group->group_name] = [0 => []]; $element['group']['#groups'][$this->group->group_name]['#group_exists'] = TRUE; - // Search for a tab that was marked as open. First one wins. - foreach (Element::children($element) as $tab_name) { - if (!empty($element[$tab_name]['#open'])) { - $element[$this->group->group_name . '__active_tab']['#default_value'] = $tab_name; - break; - } - } - } /** @@ -89,16 +96,16 @@ public function settingsForm() { $form = parent::settingsForm(); - $form['direction'] = array( + $form['direction'] = [ '#title' => $this->t('Direction'), '#type' => 'select', - '#options' => array( + '#options' => [ 'vertical' => $this->t('Vertical'), 'horizontal' => $this->t('Horizontal'), - ), + ], '#default_value' => $this->getSetting('direction'), '#weight' => 1, - ); + ]; return $form; } @@ -110,7 +117,7 @@ public function settingsSummary() { $summary = parent::settingsSummary(); $summary[] = $this->t('Direction: @direction', - array('@direction' => $this->getSetting('direction')) + ['@direction' => $this->getSetting('direction')] ); return $summary; @@ -120,9 +127,9 @@ public function settingsSummary() { * {@inheritdoc} */ public static function defaultContextSettings($context) { - return array( + return [ 'direction' => 'vertical', - ) + parent::defaultContextSettings($context); + ] + parent::defaultContextSettings($context); } /** diff --git a/web/modules/field_group/src/Routing/FieldGroupConverter.php b/web/modules/field_group/src/Routing/FieldGroupConverter.php index 3eb620e65b..9dd4447389 100644 --- a/web/modules/field_group/src/Routing/FieldGroupConverter.php +++ b/web/modules/field_group/src/Routing/FieldGroupConverter.php @@ -2,6 +2,7 @@ namespace Drupal\field_group\Routing; +use Symfony\Component\Routing\Route; use Drupal\Core\ParamConverter\ParamConverterInterface; /** @@ -12,7 +13,7 @@ class FieldGroupConverter implements ParamConverterInterface { /** * {@inheritdoc} */ - public function applies($definition, $name, \Symfony\Component\Routing\Route $route) { + public function applies($definition, $name, Route $route) { return isset($definition['type']) && $definition['type'] == 'field_group'; } @@ -28,5 +29,4 @@ public function convert($value, $definition, $name, array $defaults) { return field_group_load_field_group($identifiers[4], $identifiers[0], $identifiers[1], $identifiers[2], $identifiers[3]); } - } diff --git a/web/modules/field_group/src/Routing/RouteSubscriber.php b/web/modules/field_group/src/Routing/RouteSubscriber.php index 9a7f5397cb..2ca276b2d2 100644 --- a/web/modules/field_group/src/Routing/RouteSubscriber.php +++ b/web/modules/field_group/src/Routing/RouteSubscriber.php @@ -2,7 +2,7 @@ namespace Drupal\field_group\Routing; -use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Routing\RouteSubscriberBase; use Drupal\Core\Routing\RoutingEvents; use Symfony\Component\Routing\Route; @@ -14,20 +14,20 @@ class RouteSubscriber extends RouteSubscriberBase { /** - * The entity type manager + * The entity type manager. * - * @var \Drupal\Core\Entity\EntityManagerInterface + * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ - protected $manager; + protected $entityTypeManager; /** * Constructs a RouteSubscriber object. * - * @param \Drupal\Core\Entity\EntityManagerInterface $manager + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ - public function __construct(EntityManagerInterface $manager) { - $this->manager = $manager; + public function __construct(EntityTypeManagerInterface $entity_type_manager) { + $this->entityTypeManager = $entity_type_manager; } /** @@ -36,8 +36,8 @@ public function __construct(EntityManagerInterface $manager) { protected function alterRoutes(RouteCollection $collection) { // Create fieldgroup routes for every entity. - foreach ($this->manager->getDefinitions() as $entity_type_id => $entity_type) { - $defaults = array(); + foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { + $defaults = []; if ($route_name = $entity_type->get('field_ui_base_route')) { // Try to get the route from the current collection. if (!$entity_route = $collection->get($route_name)) { @@ -51,15 +51,15 @@ protected function alterRoutes(RouteCollection $collection) { $options['_field_ui'] = TRUE; if (($bundle_entity_type = $entity_type->getBundleEntityType()) && $bundle_entity_type !== 'bundle') { - $options['parameters'][$entity_type->getBundleEntityType()] = array( + $options['parameters'][$entity_type->getBundleEntityType()] = [ 'type' => 'entity:' . $entity_type->getBundleEntityType(), - ); + ]; } - $options['parameters']['field_group'] = array( + $options['parameters']['field_group'] = [ 'type' => 'field_group', 'entity_type' => $entity_type->getBundleEntityType(), - ); + ]; $defaults_delete = [ 'entity_type_id' => $entity_type_id, @@ -82,7 +82,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/form-display/{field_group_name}/delete", ['context' => 'form'] + $defaults_delete, - array('_permission' => 'administer ' . $entity_type_id . ' form display'), + ['_permission' => 'administer ' . $entity_type_id . ' form display'], $options ); $collection->add("field_ui.field_group_delete_$entity_type_id.form_display", $route); @@ -90,7 +90,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/form-display/{form_mode_name}/{field_group_name}/delete", ['context' => 'form'] + $defaults_delete, - array('_permission' => 'administer ' . $entity_type_id . ' form display'), + ['_permission' => 'administer ' . $entity_type_id . ' form display'], $options ); $collection->add("field_ui.field_group_delete_$entity_type_id.form_display.form_mode", $route); @@ -98,7 +98,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/display/{field_group_name}/delete", ['context' => 'view'] + $defaults_delete, - array('_permission' => 'administer ' . $entity_type_id . ' display'), + ['_permission' => 'administer ' . $entity_type_id . ' display'], $options ); $collection->add("field_ui.field_group_delete_$entity_type_id.display", $route); @@ -106,7 +106,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/display/{view_mode_name}/{field_group_name}/delete", ['context' => 'view'] + $defaults_delete, - array('_permission' => 'administer ' . $entity_type_id . ' display'), + ['_permission' => 'administer ' . $entity_type_id . ' display'], $options ); $collection->add("field_ui.field_group_delete_$entity_type_id.display.view_mode", $route); @@ -115,7 +115,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/form-display/add-group", ['context' => 'form'] + $defaults_add, - array('_permission' => 'administer ' . $entity_type_id . ' form display'), + ['_permission' => 'administer ' . $entity_type_id . ' form display'], $options ); $collection->add("field_ui.field_group_add_$entity_type_id.form_display", $route); @@ -123,7 +123,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/form-display/{form_mode_name}/add-group", ['context' => 'form'] + $defaults_add, - array('_permission' => 'administer ' . $entity_type_id . ' form display'), + ['_permission' => 'administer ' . $entity_type_id . ' form display'], $options ); $collection->add("field_ui.field_group_add_$entity_type_id.form_display.form_mode", $route); @@ -131,7 +131,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/display/add-group", ['context' => 'view'] + $defaults_add, - array('_permission' => 'administer ' . $entity_type_id . ' display'), + ['_permission' => 'administer ' . $entity_type_id . ' display'], $options ); $collection->add("field_ui.field_group_add_$entity_type_id.display", $route); @@ -139,7 +139,7 @@ protected function alterRoutes(RouteCollection $collection) { $route = new Route( "$path/display/{view_mode_name}/add-group", ['context' => 'view'] + $defaults_add, - array('_permission' => 'administer ' . $entity_type_id . ' display'), + ['_permission' => 'administer ' . $entity_type_id . ' display'], $options ); $collection->add("field_ui.field_group_add_$entity_type_id.display.view_mode", $route); @@ -152,9 +152,9 @@ protected function alterRoutes(RouteCollection $collection) { * {@inheritdoc} */ public static function getSubscribedEvents() { - //$events = parent::getSubscribedEvents(); + // $events = parent::getSubscribedEvents(); // Come after field_ui, config_translation. - $events[RoutingEvents::ALTER] = array('onAlterRoutes', -210); + $events[RoutingEvents::ALTER] = ['onAlterRoutes', -210]; return $events; } diff --git a/web/modules/field_group/templates/field-group-html-element.html.twig b/web/modules/field_group/templates/field-group-html-element.html.twig index 73072fcc0a..2b971773a1 100644 --- a/web/modules/field_group/templates/field-group-html-element.html.twig +++ b/web/modules/field_group/templates/field-group-html-element.html.twig @@ -18,7 +18,7 @@ <{{ wrapper_element }} {{ attributes }}> {% if title %} - <{{ title_element }}{% if collapsible %} class="field-group-toggler"{% endif %}>{{ title }}</{{ title_element }}> + <{{ title_element }}{{ title_attributes }}>{{ title }}</{{ title_element }}> {% endif %} {% if collapsible %} <div class="field-group-wrapper"> @@ -27,4 +27,4 @@ {% if collapsible %} </div> {% endif %} -</{{ wrapper_element }}> \ No newline at end of file +</{{ wrapper_element }}> diff --git a/web/modules/field_group/templates/theme.inc b/web/modules/field_group/templates/theme.inc index 2f0d20a989..048c956d18 100644 --- a/web/modules/field_group/templates/theme.inc +++ b/web/modules/field_group/templates/theme.inc @@ -5,6 +5,8 @@ * Preprocessors for fieldgroup elements. */ +use Drupal\Core\Template\Attribute; + /** * Prepares variables for horizontal tabs templates. * @@ -14,9 +16,8 @@ * An associative array containing: * - element: An associative array containing the properties and children of * the details element. Properties used: #children. - * */ -function template_preprocess_horizontal_tabs(&$variables) { +function template_preprocess_horizontal_tabs(array &$variables) { $element = $variables['element']; $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : ''; } @@ -30,9 +31,8 @@ function template_preprocess_horizontal_tabs(&$variables) { * An associative array containing: * - element: An associative array containing the properties and children of * the accordion element. Properties used: #children. - * */ -function template_preprocess_field_group_accordion(&$variables) { +function template_preprocess_field_group_accordion(array &$variables) { $element = $variables['element']; $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : ''; } @@ -46,9 +46,8 @@ function template_preprocess_field_group_accordion(&$variables) { * An associative array containing: * - element: An associative array containing the properties and children of * the accordion item element. - * */ -function template_preprocess_field_group_accordion_item(&$variables) { +function template_preprocess_field_group_accordion_item(array &$variables) { $element = $variables['element']; @@ -61,7 +60,7 @@ function template_preprocess_field_group_accordion_item(&$variables) { } $variables['open'] = $element['#open']; - $variables['label_attributes'] = new \Drupal\Core\Template\Attribute(); + $variables['label_attributes'] = new Attribute(); $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : ''; } @@ -75,15 +74,15 @@ function template_preprocess_field_group_accordion_item(&$variables) { * An associative array containing: * - element: An associative array containing the properties and children of * the html element. - * */ -function template_preprocess_field_group_html_element(&$variables) { +function template_preprocess_field_group_html_element(array &$variables) { $element = $variables['element']; if (!empty($element['#title']) && !empty($element['#title_element'])) { $variables['title_element'] = $element['#title_element']; $variables['title'] = $element['#title']; + $variables['title_attributes'] = $element['#title_attributes']; } $variables['collapsible'] = (!empty($element['#effect']) && $element['#effect'] !== 'none'); diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml index 4113863e66..cb1a2dd8c1 100644 --- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml +++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml @@ -4,8 +4,9 @@ description: 'Test module for Field Group' package: 'Fields' type: module hidden: TRUE -# Information added by Drupal.org packaging script on 2017-11-10 -version: '8.x-1.0' + +# Information added by Drupal.org packaging script on 2019-05-23 +version: '8.x-3.0-rc1' core: '8.x' project: 'field_group' -datestamp: 1510352889 +datestamp: 1558647188 diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.module b/web/modules/field_group/tests/modules/field_group_test/field_group_test.module index 629ed9bae6..e17f80359a 100644 --- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.module +++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.module @@ -1,20 +1,22 @@ <?php -use Drupal\Core\Access\AccessResult; -use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldItemListInterface; -use Drupal\Core\Session\AccountInterface; - /** * @file * Fieldgroup test module. */ +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Session\AccountInterface; + /** * Implements hook_entity_field_access(). */ -function field_group_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, - AccountInterface $account, FieldItemListInterface $items = NULL) { +function field_group_test_entity_field_access($operation, + FieldDefinitionInterface $field_definition, + AccountInterface $account, + FieldItemListInterface $items = NULL) { // Set access to false for field_no_access. if ($operation == 'view' && $field_definition->getName() == 'field_no_access') { @@ -24,4 +26,3 @@ function field_group_test_entity_field_access($operation, FieldDefinitionInterfa return AccessResult::neutral(); } - diff --git a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php index 5fc5da9ef1..ce2e20d703 100644 --- a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php +++ b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php @@ -53,21 +53,21 @@ public function setUp() { 'administer node fields', 'administer node form display', 'administer node display', - 'bypass node access' + 'bypass node access', ]); $this->drupalLogin($admin_user); // Create content type, with underscores. $type_name = strtolower($this->randomMachineName(8)) . '_test'; - $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name)); + $type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]); $this->type = $type->id(); /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */ $display = \Drupal::entityTypeManager() ->getStorage('entity_view_display') - ->load('node' . '.' . $type_name . '.' . 'default'); + ->load('node.' . $type_name . '.default'); // Create a node. - $node_values = array('type' => $type_name); + $node_values = ['type' => $type_name]; // Create test fields. foreach (['field_test', 'field_test_2', 'field_no_access'] as $field_name) { @@ -89,13 +89,13 @@ public function setUp() { $node_values[$field_name][0]['value'] = mt_rand(1, 127); // Set the field visible on the display object. - $display_options = array( + $display_options = [ 'label' => 'above', 'type' => 'field_test_default', - 'settings' => array( + 'settings' => [ 'test_formatter_setting' => $this->randomMachineName(), - ), - ); + ], + ]; $display->setComponent($field_name, $display_options); } @@ -108,63 +108,64 @@ public function setUp() { * Test field access for field groups. */ public function testFieldAccess() { - $data = array( + $data = [ 'label' => 'Wrapper', - 'children' => array( + 'children' => [ 0 => 'field_no_access', - ), + ], 'format_type' => 'html_element', - 'format_settings' => array( + 'format_settings' => [ 'element' => 'div', 'id' => 'wrapper-id', - ), - ); + ], + ]; $this->createGroup('node', $this->type, 'view', 'default', $data); $this->drupalGet('node/' . $this->node->id()); // Test if group is not shown. - $this->assertNoFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, t('Div that contains fields with no access is not shown.')); + $this->assertEmpty($this->xpath("//div[contains(@id, 'wrapper-id')]"), t('Div that contains fields with no access is not shown.')); } /** * Test the html element formatter. */ public function testHtmlElement() { - $data = array( + $data = [ 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test', 1 => 'body', - ), + ], 'label' => 'Link', 'format_type' => 'html_element', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Link', 'element' => 'div', 'id' => 'wrapper-id', 'classes' => 'test-class', - ), - ); + ], + ]; $group = $this->createGroup('node', $this->type, 'view', 'default', $data); - //$groups = field_group_info_groups('node', 'article', 'view', 'default', TRUE); + // $groups = field_group_info_groups('node', 'article', 'view', 'default', TRUE);. $this->drupalGet('node/' . $this->node->id()); // Test group ids and classes. - $this->assertFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, 'Wrapper id set on wrapper div'); - $this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, 'Test class set on wrapper div, class="' . $group->group_name . ' test-class'); + $this->assertTrue($this->xpath("//div[contains(@id, 'wrapper-id')]"), 'Wrapper id set on wrapper div'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class')]"), 'Test class set on wrapper div, class="' . $group->group_name . ' test-class'); // Test group label. - $this->assertNoRaw('<h3><span>' . $data['label'] . '</span></h3>'); + $this->assertSession()->responseNotContains('<h3><span>' . $data['label'] . '</span></h3>'); // Set show label to true. $group->format_settings['show_label'] = TRUE; $group->format_settings['label_element'] = 'h3'; + $group->format_settings['label_element_classes'] = 'my-label-class'; field_group_group_save($group); $this->drupalGet('node/' . $this->node->id()); - $this->assertRaw('<h3>' . $data['label'] . '</h3>'); + $this->assertSession()->responseContains('<h3 class="my-label-class">' . $data['label'] . '</h3>'); // Change to collapsible with blink effect. $group->format_settings['effect'] = 'blink'; @@ -172,175 +173,175 @@ public function testHtmlElement() { field_group_group_save($group); $this->drupalGet('node/' . $this->node->id()); - $this->assertFieldByXPath("//div[contains(@class, 'speed-fast')]", NULL, 'Speed class is set'); - $this->assertFieldByXPath("//div[contains(@class, 'effect-blink')]", NULL, 'Effect class is set'); + $this->assertTrue($this->xpath("//div[contains(@class, 'speed-fast')]"), 'Speed class is set'); + $this->assertTrue($this->xpath("//div[contains(@class, 'effect-blink')]"), 'Effect class is set'); } /** * Test the fieldset formatter. */ public function testFieldset() { - $data = array( + $data = [ 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test', 1 => 'body', - ), + ], 'label' => 'Test Fieldset', 'format_type' => 'fieldset', - 'format_settings' => array( + 'format_settings' => [ 'id' => 'fieldset-id', 'classes' => 'test-class', 'description' => 'test description', - ), - ); + ], + ]; $this->createGroup('node', $this->type, 'view', 'default', $data); $this->drupalGet('node/' . $this->node->id()); // Test group ids and classes. - $this->assertFieldByXPath("//fieldset[contains(@id, 'fieldset-id')]", NULL, 'Correct id set on the fieldset'); - $this->assertFieldByXPath("//fieldset[contains(@class, 'test-class')]", NULL, 'Test class set on the fieldset'); + $this->assertTrue($this->xpath("//fieldset[contains(@id, 'fieldset-id')]"), 'Correct id set on the fieldset'); + $this->assertTrue($this->xpath("//fieldset[contains(@class, 'test-class')]"), 'Test class set on the fieldset'); } /** * Test the tabs formatter. */ public function testTabs() { - $data = array( + $data = [ 'label' => 'Tab 1', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test', - ), + ], 'format_type' => 'tab', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Tab 1', 'classes' => 'test-class', 'description' => '', 'formatter' => 'open', - ), - ); + ], + ]; $first_tab = $this->createGroup('node', $this->type, 'view', 'default', $data); - $data = array( + $data = [ 'label' => 'Tab 2', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test_2', - ), + ], 'format_type' => 'tab', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Tab 1', 'classes' => 'test-class-2', 'description' => 'description of second tab', 'formatter' => 'closed', - ), - ); + ], + ]; $second_tab = $this->createGroup('node', $this->type, 'view', 'default', $data); - $data = array( + $data = [ 'label' => 'Tabs', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => $first_tab->group_name, 1 => $second_tab->group_name, - ), + ], 'format_type' => 'tabs', - 'format_settings' => array( + 'format_settings' => [ 'direction' => 'vertical', 'label' => 'Tab 1', 'classes' => 'test-class-wrapper', - ), - ); + ], + ]; $tabs_group = $this->createGroup('node', $this->type, 'view', 'default', $data); $this->drupalGet('node/' . $this->node->id()); // Test properties. - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, 'Test class set on tabs wrapper'); - $this->assertFieldByXPath("//details[contains(@class, 'test-class-2')]", NULL, 'Test class set on second tab'); - $this->assertRaw('<div class="details-description">description of second tab</div>'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]"), 'Test class set on tabs wrapper'); + $this->assertTrue($this->xpath("//details[contains(@class, 'test-class-2')]"), 'Test class set on second tab'); + $this->assertSession()->responseContains('<div class="details-description">description of second tab</div>'); // Test if correctly nested. - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class')]", NULL, 'First tab is displayed as child of the wrapper.'); - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class-2')]", NULL, 'Second tab is displayed as child of the wrapper.'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class')]"), 'First tab is displayed as child of the wrapper.'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class-2')]"), 'Second tab is displayed as child of the wrapper.'); // Test if it's a vertical tab. - $this->assertFieldByXPath('//div[@data-vertical-tabs-panes=""]', NULL, 'Tabs are shown vertical.'); + $this->assertTrue($this->xpath('//div[@data-vertical-tabs-panes=""]'), 'Tabs are shown vertical.'); - // Switch to horizontal + // Switch to horizontal. $tabs_group->format_settings['direction'] = 'horizontal'; field_group_group_save($tabs_group); $this->drupalGet('node/' . $this->node->id()); // Test if it's a horizontal tab. - $this->assertFieldByXPath('//div[@data-horizontal-tabs-panes=""]', NULL, 'Tabs are shown horizontal.'); + $this->assertTrue($this->xpath('//div[@data-horizontal-tabs-panes=""]'), 'Tabs are shown horizontal.'); } /** * Test the accordion formatter. */ public function testAccordion() { - $data = array( + $data = [ 'label' => 'Accordion item 1', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test', - ), + ], 'format_type' => 'accordion_item', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Accordion item 1', 'classes' => 'test-class', 'formatter' => 'closed', - ), - ); + ], + ]; $first_item = $this->createGroup('node', $this->type, 'view', 'default', $data); - $data = array( + $data = [ 'label' => 'Accordion item 2', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => 'field_test_2', - ), + ], 'format_type' => 'accordion_item', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Tab 2', 'classes' => 'test-class-2', 'formatter' => 'open', - ), - ); + ], + ]; $second_item = $this->createGroup('node', $this->type, 'view', 'default', $data); - $data = array( + $data = [ 'label' => 'Accordion', 'weight' => '1', - 'children' => array( + 'children' => [ 0 => $first_item->group_name, 1 => $second_item->group_name, - ), + ], 'format_type' => 'accordion', - 'format_settings' => array( + 'format_settings' => [ 'label' => 'Tab 1', 'classes' => 'test-class-wrapper', - 'effect' => 'bounceslide' - ), - ); + 'effect' => 'bounceslide', + ], + ]; $this->createGroup('node', $this->type, 'view', 'default', $data); $this->drupalGet('node/' . $this->node->id()); // Test properties. - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, 'Test class set on tabs wrapper'); - $this->assertFieldByXPath("//div[contains(@class, 'effect-bounceslide')]", NULL, 'Correct effect is set on the accordion'); - $this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, 'Accordion item with test-class is shown'); - $this->assertFieldByXPath("//div[contains(@class, 'test-class-2')]", NULL, 'Accordion item with test-class-2 is shown'); - $this->assertFieldByXPath("//h3[contains(@class, 'field-group-accordion-active')]", NULL, 'Accordion item 2 was set active'); - - // Test if correctly nested - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]", NULL, 'First item is displayed as child of the wrapper.'); - $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]", NULL, 'Second item is displayed as child of the wrapper.'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]"), 'Test class set on tabs wrapper'); + $this->assertTrue($this->xpath("//div[contains(@class, 'effect-bounceslide')]"), 'Correct effect is set on the accordion'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class')]"), 'Accordion item with test-class is shown'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-2')]"), 'Accordion item with test-class-2 is shown'); + $this->assertTrue($this->xpath("//h3[contains(@class, 'field-group-accordion-active')]"), 'Accordion item 2 was set active'); + + // Test if correctly nested. + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]"), 'First item is displayed as child of the wrapper.'); + $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]"), 'Second item is displayed as child of the wrapper.'); } } diff --git a/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php b/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php index c622a10be2..563ec92cd1 100644 --- a/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php +++ b/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\field_group\Functional; -use Drupal\Component\Utility\Unicode; +use Drupal; /** * Provides common functionality for the FieldGroup test classes. @@ -15,7 +15,7 @@ trait FieldGroupTestTrait { * @param string $entity_type * The entity type as string. * @param string $bundle - * The bundle of the enity type + * The bundle of the enity type. * @param string $context * The context for the group. * @param string $mode @@ -29,27 +29,27 @@ trait FieldGroupTestTrait { protected function createGroup($entity_type, $bundle, $context, $mode, array $data) { if (!isset($data['format_settings'])) { - $data['format_settings'] = array(); + $data['format_settings'] = []; } - $data['format_settings'] += _field_group_get_default_formatter_settings($data['format_type'], $context); + $data['format_settings'] += Drupal::service('plugin.manager.field_group.formatters')->getDefaultSettings($data['format_type'], $context); - $group_name = 'group_' . Unicode::strtolower($this->randomMachineName()); + $group_name = 'group_' . mb_strtolower($this->randomMachineName()); - $field_group = (object) array( + $field_group = (object) [ 'group_name' => $group_name, 'entity_type' => $entity_type, 'bundle' => $bundle, 'mode' => $mode, 'context' => $context, - 'children' => isset($data['children']) ? $data['children'] : array(), + 'children' => isset($data['children']) ? $data['children'] : [], 'parent_name' => isset($data['parent']) ? $data['parent'] : '', 'weight' => isset($data['weight']) ? $data['weight'] : 0, 'label' => isset($data['label']) ? $data['label'] : $this->randomString(8), 'format_type' => $data['format_type'], 'format_settings' => $data['format_settings'], 'region' => 'content', - ); + ]; field_group_group_save($field_group); diff --git a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php index 2beae972bf..bcb7600984 100644 --- a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php +++ b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php @@ -21,7 +21,7 @@ class FieldGroupWithoutFieldUiTest extends BrowserTestBase { * Test that local actions show up without field ui enabled. */ public function testLocalActions() { - // Local actions of field_group should not depend on field_ui + // Local actions of field_group should not depend on field_ui. // @see https://www.drupal.org/node/2719569 $this->placeBlock('local_actions_block', ['id' => 'local_actions_block']); $this->drupalGet(Url::fromRoute('user.login')); diff --git a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php index e89ee4600f..f05c56d1c2 100644 --- a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php +++ b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php @@ -2,7 +2,6 @@ namespace Drupal\Tests\field_group\Functional; -use Drupal\Component\Utility\Unicode; use Drupal\Tests\BrowserTestBase; /** @@ -17,7 +16,7 @@ class ManageDisplayTest extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = array('node', 'field_ui', 'field_group'); + public static $modules = ['node', 'field_ui', 'field_group']; /** * Content type id. @@ -58,15 +57,15 @@ public function setUp() { public function testCreateGroup() { // Create random group name. $group_label = $this->randomString(8); - $group_name_input = Unicode::strtolower($this->randomMachineName()); + $group_name_input = mb_strtolower($this->randomMachineName()); $group_name = 'group_' . $group_name_input; $group_formatter = 'details'; // Setup new group. - $group = array( + $group = [ 'group_formatter' => $group_formatter, 'label' => $group_label, - ); + ]; $add_form_display = 'admin/structure/types/manage/' . $this->type . '/form-display/add-group'; $this->drupalPostForm($add_form_display, $group, 'Save and continue'); @@ -79,7 +78,7 @@ public function testCreateGroup() { $this->drupalPostForm($add_form_display, $group, 'Save and continue'); $this->drupalPostForm(NULL, [], 'Create group'); - $this->assertSession()->responseContains(t('New group %label successfully created.', array('%label' => $group_label))); + $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label])); // Test if group is in the $groups array. $this->group = field_group_load_field_group($group_name, 'node', $this->type, 'form', 'default'); @@ -89,7 +88,7 @@ public function testCreateGroup() { $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/add-group', $group, 'Save and continue'); $this->drupalPostForm(NULL, [], 'Create group'); - $this->assertSession()->responseContains(t('New group %label successfully created.', array('%label' => $group_label))); + $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label])); // Test if group is in the $groups array. $loaded_group = field_group_load_field_group($group_name, 'node', $this->type, 'view', 'default'); @@ -100,15 +99,15 @@ public function testCreateGroup() { * Delete a group. */ public function testDeleteGroup() { - $data = array( + $data = [ 'format_type' => 'fieldset', 'label' => 'testing', - ); + ]; $group = $this->createGroup('node', $this->type, 'form', 'default', $data); - $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete', array(), 'Delete'); - $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', array('%label' => $group->label, '%type' => $this->type))); + $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete', [], 'Delete'); + $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type])); // Test that group is not in the $groups array. \Drupal::entityTypeManager() @@ -117,15 +116,15 @@ public function testDeleteGroup() { $loaded_group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default'); $this->assertNull($loaded_group, 'Group not found after deleting'); - $data = array( + $data = [ 'format_type' => 'fieldset', 'label' => 'testing', - ); + ]; $group = $this->createGroup('node', $this->type, 'view', 'default', $data); - $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete', array(), t('Delete')); - $this->assertRaw(t('The group %label has been deleted from the %type content type.', array('%label' => $group->label, '%type' => $this->type))); + $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete', [], t('Delete')); + $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type])); // Test that group is not in the $groups array. \Drupal::entityTypeManager() @@ -139,20 +138,20 @@ public function testDeleteGroup() { * Nest a field underneath a group. */ public function testNestField() { - $data = array( + $data = [ 'format_type' => 'fieldset', - ); + ]; $group = $this->createGroup('node', $this->type, 'form', 'default', $data); - $edit = array( + $edit = [ 'fields[body][parent]' => $group->group_name, - ); + ]; $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display', $edit, 'Save'); - $this->assertRaw('Your settings have been saved.'); + $this->assertSession()->responseContains('Your settings have been saved.'); $group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default'); - $this->assertTrue(in_array('body', $group->children), t('Body is a child of %group', array('%group' => $group->group_name))); + $this->assertTrue(in_array('body', $group->children), t('Body is a child of %group', ['%group' => $group->group_name])); } } diff --git a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php index 75d74ea834..e237c73f14 100644 --- a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php +++ b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php @@ -2,9 +2,8 @@ namespace Drupal\Tests\field_group\FunctionalJavascript; -use Drupal\Component\Utility\Unicode; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\FunctionalJavascriptTests\JavascriptTestBase; +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; use Drupal\node\Entity\NodeType; use Drupal\Tests\field_group\Functional\FieldGroupTestTrait; @@ -13,7 +12,7 @@ * * @group field_group */ -class FieldGroupUiTest extends JavascriptTestBase { +class FieldGroupUiTest extends WebDriverTestBase { use FieldGroupTestTrait; @@ -22,13 +21,18 @@ class FieldGroupUiTest extends JavascriptTestBase { * * @var array */ - public static $modules = array('node', 'field_ui', 'field_group'); + public static $modules = ['node', 'field_ui', 'field_group']; /** + * The current tested node type + * * @var string */ protected $nodeType; + /** + * {@inheritdoc} + */ public function setUp() { parent::setUp(); @@ -44,7 +48,7 @@ public function setUp() { $this->drupalLogin($admin_user); // Create content type, with underscores. - $type_name = Unicode::strtolower($this->randomMachineName(8)) . '_test'; + $type_name = mb_strtolower($this->randomMachineName(8)) . '_test'; $type = NodeType::create([ 'name' => $type_name, 'type' => $type_name, @@ -58,18 +62,18 @@ public function setUp() { */ public function testCreateAndEdit() { foreach (['test_1', 'test_2'] as $name) { - $group = array( + $group = [ 'group_formatter' => 'details', 'label' => 'Test 1', 'group_name' => $name, - ); + ]; // Add new group on the 'Manage form display' page. $this->drupalPostForm('admin/structure/types/manage/' . $this->nodeType . '/form-display/add-group', $group, 'Save and continue'); $this->drupalPostForm(NULL, [], 'Create group'); } - // Update title in group 1 + // Update title in group 1. $page = $this->getSession()->getPage(); $page->pressButton('group_test_1_group_settings_edit'); $this->assertSession()->assertWaitOnAjaxRequest(); @@ -77,14 +81,14 @@ public function testCreateAndEdit() { $page->pressButton('Update'); $this->assertSession()->assertWaitOnAjaxRequest(); - // Update title in group 2 + // Update title in group 2. $page->pressButton('group_test_2_group_settings_edit'); $this->assertSession()->assertWaitOnAjaxRequest(); $page->fillField('fields[group_test_2][settings_edit_form][settings][label]', 'Test 2 - Update'); $page->pressButton('Update'); $this->assertSession()->assertWaitOnAjaxRequest(); - // Open group 1 again + // Open group 1 again. $page->pressButton('group_test_1_group_settings_edit'); $this->assertSession()->assertWaitOnAjaxRequest(); $this->assertSession()->fieldValueEquals('fields[group_test_1][settings_edit_form][settings][label]', 'Test 1 - Update'); -- GitLab