diff --git a/config/install/user.role.az_content_admin.yml b/config/install/user.role.az_content_admin.yml
index 28d2f44328..7b021cbd54 100644
--- a/config/install/user.role.az_content_admin.yml
+++ b/config/install/user.role.az_content_admin.yml
@@ -16,6 +16,7 @@ permissions:
- 'administer blocks'
- 'administer book outlines'
- 'administer easy breadcrumb'
+ - 'administer az_finder settings'
- 'administer flaggings'
- 'administer flags'
- 'administer languages'
diff --git a/modules/custom/az_demo/config/install/views.view.az_finder.yml b/modules/custom/az_demo/config/install/views.view.az_finder.yml
index 6572cd42ee..08a7cfdc45 100644
--- a/modules/custom/az_demo/config/install/views.view.az_finder.yml
+++ b/modules/custom/az_demo/config/install/views.view.az_finder.yml
@@ -580,15 +580,20 @@ display:
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_event_category_target_id:
plugin_id: az_finder_tid_widget
advanced:
sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
reset_button_position: top
reset_button_counter: true
orientation: vertical
@@ -859,27 +864,34 @@ display:
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_byline_value:
plugin_id: default
advanced:
placeholder_text: ''
collapsible: true
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_published_value:
plugin_id: bef_datepicker
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_news_tags_target_id:
plugin_id: az_finder_tid_widget
advanced:
sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
reset_button_position: top
reset_button_counter: true
orientation: vertical
@@ -1263,15 +1275,20 @@ display:
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_page_category_target_id:
plugin_id: az_finder_tid_widget
advanced:
- sort_options: true
+ sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
reset_button_position: top
reset_button_counter: true
orientation: vertical
@@ -1548,23 +1565,32 @@ display:
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
field_az_person_category_target_id:
plugin_id: az_finder_tid_widget
advanced:
sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
field_az_person_category_sec_target_id:
plugin_id: az_finder_tid_widget
advanced:
sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
reset_button_position: top
reset_button_counter: true
orientation: vertical
diff --git a/modules/custom/az_finder/az_finder.info.yml b/modules/custom/az_finder/az_finder.info.yml
index 2f328ea3b2..861608f908 100644
--- a/modules/custom/az_finder/az_finder.info.yml
+++ b/modules/custom/az_finder/az_finder.info.yml
@@ -5,3 +5,4 @@ core_version_requirement: ^9 || ^10
package: 'The University of Arizona - Experimental'
dependencies:
- better_exposed_filters:better_exposed_filters
+configure: az_finder.settings
diff --git a/modules/custom/az_finder/az_finder.links.task.yml b/modules/custom/az_finder/az_finder.links.task.yml
new file mode 100644
index 0000000000..6a14041863
--- /dev/null
+++ b/modules/custom/az_finder/az_finder.links.task.yml
@@ -0,0 +1,5 @@
+az_finder.settings_tab:
+ title: 'AZ Finder'
+ route_name: az_finder.settings
+ base_route: az_core.az_settings
+ weight: 0
diff --git a/modules/custom/az_finder/az_finder.permissions.yml b/modules/custom/az_finder/az_finder.permissions.yml
new file mode 100644
index 0000000000..9105301c77
--- /dev/null
+++ b/modules/custom/az_finder/az_finder.permissions.yml
@@ -0,0 +1,3 @@
+administer az_finder settings:
+ title: 'Administer Quickstart Finder Settings'
+ description: 'Allows users to manage Quickstart Finder settings.'
diff --git a/modules/custom/az_finder/az_finder.routing.yml b/modules/custom/az_finder/az_finder.routing.yml
new file mode 100644
index 0000000000..c532be736b
--- /dev/null
+++ b/modules/custom/az_finder/az_finder.routing.yml
@@ -0,0 +1,7 @@
+az_finder.settings:
+ path: '/admin/config/az-quickstart/settings/az-finder'
+ defaults:
+ _form: '\Drupal\az_finder\Form\AZFinderSettingsForm'
+ _title: 'AZ Finder Settings'
+ requirements:
+ _permission: 'administer az_finder settings'
diff --git a/modules/custom/az_finder/az_finder.services.yml b/modules/custom/az_finder/az_finder.services.yml
index 1c1d021ed5..01e9347a70 100644
--- a/modules/custom/az_finder/az_finder.services.yml
+++ b/modules/custom/az_finder/az_finder.services.yml
@@ -2,4 +2,21 @@ services:
_defaults:
autoconfigure: true
az_finder.icons:
- class: Drupal\az_finder\AZFinderIcons
+ class: Drupal\az_finder\Service\AZFinderIcons
+ az_finder.view_options:
+ class: Drupal\az_finder\Service\AZFinderViewOptions
+ arguments:
+ - '@cache.default'
+ - '@entity_type.manager'
+ az_finder.vocabulary:
+ class: Drupal\az_finder\Service\AZFinderVocabulary
+ arguments:
+ - '@entity_type.manager'
+ - '@string_translation'
+ az_finder.overrides:
+ class: Drupal\az_finder\Service\AZFinderOverrides
+ arguments:
+ - '@config.factory'
+ logger.channel.az_finder:
+ parent: logger.channel_base
+ arguments: ['az_finder']
diff --git a/modules/custom/az_finder/config/install/az_finder.settings.yml b/modules/custom/az_finder/config/install/az_finder.settings.yml
new file mode 100644
index 0000000000..2eec6d7d34
--- /dev/null
+++ b/modules/custom/az_finder/config/install/az_finder.settings.yml
@@ -0,0 +1,2 @@
+tid_widget:
+ default_state: 'expand'
diff --git a/modules/custom/az_finder/config/quickstart/views.view.az_page_by_category.yml b/modules/custom/az_finder/config/quickstart/views.view.az_page_by_category.yml
index 4d6e1fa4f2..029f13a6ba 100644
--- a/modules/custom/az_finder/config/quickstart/views.view.az_page_by_category.yml
+++ b/modules/custom/az_finder/config/quickstart/views.view.az_page_by_category.yml
@@ -97,6 +97,7 @@ display:
type: full
options:
offset: 0
+ pagination_heading_level: h4
items_per_page: 50
total_pages: null
id: 0
@@ -143,15 +144,20 @@ display:
advanced:
placeholder_text: ''
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
tid:
plugin_id: az_finder_tid_widget
advanced:
sort_options: false
+ placeholder_text: ''
rewrite:
filter_rewrite_values: ''
+ filter_rewrite_values_key: false
collapsible: false
+ collapsible_disable_automatic_open: false
is_secondary: false
+ default_states: { }
reset_button_position: top
reset_button_counter: true
orientation: vertical
@@ -407,6 +413,55 @@ display:
display_plugin: page
position: 2
display_options:
+ exposed_form:
+ type: az_better_exposed_filters
+ options:
+ submit_button: Apply
+ reset_button: true
+ reset_button_label: 'Reset filters'
+ exposed_sorts_label: 'Sort by'
+ expose_sort_order: true
+ sort_asc_label: Asc
+ sort_desc_label: Desc
+ text_input_required: 'Select any filter and click on Apply to see results'
+ text_input_required_format: az_standard
+ bef:
+ general:
+ autosubmit: true
+ autosubmit_exclude_textfield: false
+ autosubmit_textfield_delay: 500
+ autosubmit_hide: true
+ input_required: false
+ allow_secondary: false
+ secondary_label: 'Advanced options'
+ secondary_open: false
+ reset_button_always_show: false
+ filter:
+ title:
+ plugin_id: default
+ advanced:
+ placeholder_text: ''
+ collapsible: false
+ collapsible_disable_automatic_open: false
+ is_secondary: false
+ tid:
+ plugin_id: az_finder_tid_widget
+ advanced:
+ sort_options: false
+ placeholder_text: ''
+ rewrite:
+ filter_rewrite_values: ''
+ filter_rewrite_values_key: false
+ collapsible: false
+ collapsible_disable_automatic_open: false
+ is_secondary: false
+ default_states: { }
+ reset_button_position: top
+ reset_button_counter: true
+ orientation: vertical
+ skip_link: true
+ skip_link_text: 'Skip to search and filter'
+ skip_link_id: search-filter
style:
type: views_bootstrap_grid
options:
@@ -425,6 +480,7 @@ display:
relationship: none
view_mode: az_card
defaults:
+ exposed_form: false
style: false
style_options: false
row: false
@@ -450,6 +506,55 @@ display:
display_plugin: page
position: 1
display_options:
+ exposed_form:
+ type: az_better_exposed_filters
+ options:
+ submit_button: Apply
+ reset_button: true
+ reset_button_label: 'Reset filters'
+ exposed_sorts_label: 'Sort by'
+ expose_sort_order: true
+ sort_asc_label: Asc
+ sort_desc_label: Desc
+ text_input_required: 'Select any filter and click on Apply to see results'
+ text_input_required_format: az_standard
+ bef:
+ general:
+ autosubmit: true
+ autosubmit_exclude_textfield: false
+ autosubmit_textfield_delay: 500
+ autosubmit_hide: true
+ input_required: false
+ allow_secondary: false
+ secondary_label: 'Advanced options'
+ secondary_open: false
+ reset_button_always_show: false
+ filter:
+ title:
+ plugin_id: default
+ advanced:
+ placeholder_text: ''
+ collapsible: false
+ collapsible_disable_automatic_open: false
+ is_secondary: false
+ tid:
+ plugin_id: az_finder_tid_widget
+ advanced:
+ sort_options: false
+ placeholder_text: ''
+ rewrite:
+ filter_rewrite_values: ''
+ filter_rewrite_values_key: false
+ collapsible: false
+ collapsible_disable_automatic_open: false
+ is_secondary: false
+ default_states: { }
+ reset_button_position: top
+ reset_button_counter: true
+ orientation: vertical
+ skip_link: true
+ skip_link_text: 'Skip to search and filter'
+ skip_link_id: search-filter
style:
type: default
options:
@@ -463,6 +568,7 @@ display:
view_mode: az_row
defaults:
css_class: false
+ exposed_form: false
style: false
style_options: false
row: false
diff --git a/modules/custom/az_finder/config/schema/az_finder.schema.yml b/modules/custom/az_finder/config/schema/az_finder.schema.yml
new file mode 100644
index 0000000000..66debc9c3c
--- /dev/null
+++ b/modules/custom/az_finder/config/schema/az_finder.schema.yml
@@ -0,0 +1,69 @@
+az_finder.settings:
+ type: config_object
+ label: 'AZ Finder Settings'
+ mapping:
+ tid_widget:
+ type: mapping
+ label: 'Global Default Settings'
+ mapping:
+ default_state:
+ type: string
+ label: 'Global Default State for Exposed Filters'
+ constraints:
+ Choice:
+ - 'expand'
+ - 'collapse'
+
+az_finder.tid_widget.[view_id].[display_id]:
+ type: config_object
+ label: 'AZ Finder Override for a specific View Display'
+ mapping:
+ vocabularies:
+ type: sequence
+ label: 'Vocabulary settings for this view display'
+ sequence:
+ type: mapping
+ mapping:
+ vocabulary_id:
+ type: string
+ label: 'Vocabulary ID'
+ terms:
+ type: sequence
+ label: 'Settings for each term in the vocabulary'
+ sequence:
+ type: mapping
+ mapping:
+ term_id:
+ type: string
+ label: 'Term ID'
+ default_state:
+ type: string
+ label: 'Setting for each term'
+ constraints:
+ Required: false
+ Choice:
+ - 'expand'
+ - 'collapse'
+
+views.exposed_form.az_better_exposed_filters:
+ type: views.exposed_form.bef
+ label: 'Quickstart Exposed Filters'
+ mapping:
+ reset_button_position:
+ type: string
+ label: 'Reset Button Position'
+ reset_button_counter:
+ type: boolean
+ label: 'Show Active Filter Counter'
+ orientation:
+ type: string
+ label: 'Orientation'
+ skip_link:
+ type: boolean
+ label: 'Add Skip Link'
+ skip_link_text:
+ type: string
+ label: 'Skip Link Text'
+ skip_link_id:
+ type: string
+ label: 'Skip Link ID'
diff --git a/modules/custom/az_finder/config/schema/views.exposed_form.az_better_exposed_filters.yml b/modules/custom/az_finder/config/schema/views.exposed_form.az_better_exposed_filters.yml
deleted file mode 100644
index 0a306bfb5c..0000000000
--- a/modules/custom/az_finder/config/schema/views.exposed_form.az_better_exposed_filters.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-views.exposed_form.az_better_exposed_filters:
- type: views.exposed_form.bef
- label: 'Quickstart Exposed Filters'
- mapping:
- reset_button_position:
- type: string
- label: 'Reset Button Position'
- reset_button_counter:
- type: boolean
- label: 'Show Active Filter Counter'
- orientation:
- type: string
- label: 'Orientation'
- skip_link:
- type: boolean
- label: 'Add Skip Link'
- skip_link_text:
- type: string
- label: 'Skip Link Text'
- skip_link_id:
- type: string
- label: 'Skip Link ID'
diff --git a/modules/custom/az_finder/css/taxonomy-index-tid-widget.css b/modules/custom/az_finder/css/taxonomy-index-tid-widget.css
index 9ed766ec74..2c7f7c8d14 100644
--- a/modules/custom/az_finder/css/taxonomy-index-tid-widget.css
+++ b/modules/custom/az_finder/css/taxonomy-index-tid-widget.css
@@ -97,4 +97,4 @@
.js-bef-filter-count {
margin-left: 5px;
-}
\ No newline at end of file
+}
diff --git a/modules/custom/az_finder/src/Form/AZFinderSettingsForm.php b/modules/custom/az_finder/src/Form/AZFinderSettingsForm.php
new file mode 100644
index 0000000000..57ac589ee3
--- /dev/null
+++ b/modules/custom/az_finder/src/Form/AZFinderSettingsForm.php
@@ -0,0 +1,394 @@
+typedConfigManager = $typed_config_manager;
+ $this->azFinderViewOptions = $az_finder_view_options;
+ $this->azFinderVocabulary = $az_finder_vocabulary;
+ $this->azFinderOverrides = $az_finder_overrides;
+ $this->entityTypeManager = $entity_type_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('config.factory'),
+ $container->get('config.typed'),
+ $container->get('az_finder.view_options'),
+ $container->get('az_finder.vocabulary'),
+ $container->get('az_finder.overrides'),
+ $container->get('entity_type.manager')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormId() {
+ return 'az_finder_settings';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getEditableConfigNames() {
+ return ['az_finder.settings'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, FormStateInterface $form_state): array {
+ $form['#tree'] = TRUE;
+
+ // Page description.
+ $form['description'] = [
+ '#type' => 'item',
+ '#markup' => $this->t('
+
Manage the settings you would like to use with exposed AZ Finder forms.
+ For more information about the Quickstart Finder, please visit the Quickstart website.
+ '),
+ ];
+
+ // How these settings work section.
+ $form['how_it_works'] = [
+ '#type' => 'details',
+ '#title' => $this->t('How do these settings work?'),
+ '#open' => FALSE,
+ '#description' => $this->t('
+ The default settings are applied to all taxonomy vocabularies as a starting point.
+ Each Finder view display can have custom overrides to expand or collapse specific sections by default.
+ '),
+ ];
+
+ // Filter Widget Settings section.
+ $form['az_finder_tid_widget'] = [
+ '#type' => 'details',
+ '#title' => $this->t('Filter Widget Settings'),
+ '#open' => TRUE,
+ ];
+
+ // Default state select field.
+ $form['az_finder_tid_widget']['default_state'] = [
+ '#type' => 'select',
+ '#title' => $this->t('Default Display of Parent Terms'),
+ '#description' => $this->t('Choose how taxonomy terms with children should behave by default everywhere.
These settings are not context aware, so if you choose collapsed, your term must be using a collapsible element for this to work.'),
+ '#weight' => -2,
+ '#options' => [
+ 'expand' => $this->t('Expanded'),
+ 'collapse' => $this->t('Collapsed'),
+ ],
+ '#config_target' => 'az_finder.settings:tid_widget.default_state',
+ ];
+
+ // Fetch existing overrides from the AZFinderOverrides service.
+ $config_overrides = $this->azFinderOverrides->getExistingOverrides();
+
+ // Get current overrides from form state.
+ $session_overrides = $form_state->getValue(['az_finder_tid_widget', 'overrides']) ?? [];
+
+ // Normalize session overrides structure if needed.
+ $normalized_session_overrides = [];
+ foreach ($session_overrides as $key => $override) {
+ // Filter out non-override form elements.
+ if (empty($override['view_id'])) {
+ continue;
+ }
+ $normalized_session_overrides[$key] = $override;
+ }
+
+ // Combine overrides. Session overrides will not overwrite existing ones.
+ $overrides = $config_overrides + $normalized_session_overrides;
+
+ $form['az_finder_tid_widget']['overrides'] = [
+ '#type' => 'container',
+ '#prefix' => '',
+ '#suffix' => '
',
+ ];
+
+ $form['az_finder_tid_widget']['overrides']['select_view_display_container'] = [
+ '#type' => 'container',
+ 'select_view_display' => [
+ '#type' => 'select',
+ '#title' => $this->t('Add an Override'),
+ '#description' => $this->t('Select a particular filter widget to override the default display for each taxonomy term.'),
+ '#weight' => -1,
+ '#options' => $this->azFinderViewOptions->getViewOptions(),
+ '#empty_option' => $this->t('- Select -'),
+ '#attributes' => [
+ 'id' => 'js-az-select-view-display',
+ ],
+ ],
+ 'override' => [
+ '#type' => 'submit',
+ '#value' => $this->t('Add Override'),
+ '#ajax' => [
+ 'callback' => '::ajaxAddOverride',
+ 'wrapper' => 'js-overrides-container',
+ 'effect' => 'fade',
+ ],
+ '#submit' => ['::submitOverride'],
+ '#attributes' => [
+ 'class' => [
+ 'button',
+ 'button--primary',
+ 'button--small',
+ ],
+ ],
+ '#states' => [
+ 'disabled' => [
+ ':input[name="az_finder_tid_widget[overrides][select_view_display_container][select_view_display]"]' => ['value' => ''],
+ ],
+ ],
+ ],
+ ];
+
+ // Add tooltip if we have overrides.
+ if (!empty($overrides)) {
+ $form['az_finder_tid_widget']['overrides']['configure_overrides'] = [
+ '#type' => 'item',
+ '#title' => $this->t('Configure Added Overrides'),
+ ];
+ }
+ // Add override sections.
+ foreach ($overrides as $override) {
+ $this->addOverrideSection($form, $form_state, $override);
+ }
+
+ // Save combined overrides to the form state.
+ $form_state->setValue(['az_finder_tid_widget', 'overrides'], $overrides);
+ return parent::buildForm($form, $form_state);
+ }
+
+ /**
+ * Separate submit handler for the override button.
+ *
+ * @param array $form
+ * The form array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state object.
+ */
+ public function submitOverride(array &$form, FormStateInterface $form_state) {
+ // Retrieve selected view and display.
+ $selected_view_display = $form_state->getValue([
+ 'az_finder_tid_widget',
+ 'overrides',
+ 'select_view_display_container',
+ 'select_view_display',
+ ]);
+ [$view_id, $display_id] = explode(':', $selected_view_display);
+
+ // Prepare the configuration key.
+ $config_name = "az_finder.tid_widget.$view_id.$display_id";
+
+ // Initialize or load existing configuration.
+ $config = $this->configFactory->getEditable($config_name);
+
+ // Save the configuration.
+ $config->save();
+
+ // Create the override for form state.
+ $override = [
+ 'view_id' => $view_id,
+ 'display_id' => $display_id,
+ ];
+
+ // Ensure the overrides array is present in the form state.
+ $overrides = $form_state->getValue(['az_finder_tid_widget', 'overrides']) ?? [];
+ // Update the overrides with the new override.
+ $overrides["$view_id:$display_id"] = $override;
+ $form_state->setValue(['az_finder_tid_widget', 'overrides'], $overrides);
+ $form_state->setRebuild(TRUE);
+
+ // Optionally, provide feedback or perform additional actions.
+ $this->messenger()->addMessage($this->t('Override created for @view_display.', [
+ '@view_display' => $form_state->getCompleteForm()['az_finder_tid_widget']['overrides']['select_view_display_container']['select_view_display']['#options'][$selected_view_display],
+ ]));
+ }
+
+ /**
+ * Ajax callback for the override button.
+ *
+ * @param array $form
+ * The form array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state object.
+ *
+ * @return array
+ * The updated overrides container.
+ */
+ public function ajaxAddOverride(array &$form, FormStateInterface $form_state): array {
+ // Return the updated overrides container.
+ return $form['az_finder_tid_widget']['overrides'];
+ }
+
+ /**
+ * Add an override section to the form.
+ *
+ * @param array $form
+ * The form array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state object.
+ * @param array $override
+ * The override data.
+ *
+ * @return ?array
+ * Return the override section or null.
+ */
+ public function addOverrideSection(array &$form, FormStateInterface $form_state, array $override): ?array {
+ $key = "{$override['view_id']}:{$override['display_id']}";
+ $view_id = $override['view_id'];
+ $display_id = $override['display_id'];
+ if ($key !== ':' && !isset($form['az_finder_tid_widget']['overrides'][$key])) {
+ $form['az_finder_tid_widget']['overrides'][$key] = [
+ '#type' => 'details',
+ '#title' => $this->t("Override Settings for :view_label (:display_title)", [
+ ":view_label" => $override['view_label'],
+ ":display_title" => $override['display_title'],
+ ]),
+ '#open' => FALSE,
+ '#description' => $this->t('Overrides are grouped by taxonomy vocabulary. Each vocabulary can have its own settings for how filter widgets behave when they have child terms.'),
+ '#tree' => TRUE,
+ ];
+ $form['az_finder_tid_widget']['overrides'][$key]['delete'] = [
+ '#type' => 'submit',
+ '#value' => $this->t('Delete'),
+ '#ajax' => [
+ 'callback' => '::ajaxDeleteOverride',
+ 'wrapper' => 'js-overrides-container',
+ 'effect' => 'fade',
+ ],
+ '#name' => 'delete-' . $key,
+ '#submit' => ['::submitDeleteOverride'],
+ '#attributes' => [
+ 'class' => ['button--small'],
+ ],
+ ];
+
+ $config_name = "az_finder.tid_widget.{$view_id}.{$display_id}";
+ $config = $this->config($config_name);
+ $vocabulary_ids = $this->azFinderVocabulary->getVocabularyIdsForFilter($view_id, $display_id, 'taxonomy_index_tid');
+
+ foreach ($vocabulary_ids as $vocabulary_id) {
+ $this->azFinderVocabulary->addTermsTable(
+ $form['az_finder_tid_widget']['overrides'][$key]['vocabularies'][$vocabulary_id],
+ $vocabulary_id,
+ $view_id,
+ $display_id
+ );
+ }
+ }
+
+ $overrides = $form_state->getValue(['az_finder_tid_widget', 'overrides']) ?? [];
+ $form_state->setValue(['az_finder_tid_widget', 'overrides'], $overrides);
+ return $form['az_finder_tid_widget']['overrides'][$key];
+ }
+
+ /**
+ * Ajax callback for the delete button.
+ */
+ public function ajaxDeleteOverride(array &$form, FormStateInterface $form_state) {
+ // Return the updated overrides container.
+ return $form['az_finder_tid_widget']['overrides'];
+ }
+
+ /**
+ * Separate submit handler for the delete button.
+ *
+ * @param array $form
+ * The form array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state object.
+ */
+ public function submitDeleteOverride(array &$form, FormStateInterface $form_state) {
+ $triggering_element = $form_state->getTriggeringElement();
+ $button_name = $triggering_element['#name'];
+ $key = str_replace('delete-', '', $button_name);
+ [$view_id, $display_id] = explode(':', $key);
+ $config_name = "az_finder.tid_widget.$view_id.$display_id";
+ $config = $this->config($config_name);
+ if ($config) {
+ $editable_config = $this->configFactory->getEditable($config_name);
+ $editable_config->delete();
+ }
+ // Update the overrides in form state.
+ $overrides = $form_state->getValue(['az_finder_tid_widget', 'overrides']) ?? [];
+ unset($overrides[$key]);
+ $form_state->setValue(['az_finder_tid_widget', 'overrides'], $overrides);
+ $form_state->setRebuild(TRUE);
+ }
+
+}
diff --git a/modules/custom/az_finder/src/Plugin/better_exposed_filters/filter/AZFinderTaxonomyIndexTidWidget.php b/modules/custom/az_finder/src/Plugin/better_exposed_filters/filter/AZFinderTaxonomyIndexTidWidget.php
index f195912624..2827f32138 100644
--- a/modules/custom/az_finder/src/Plugin/better_exposed_filters/filter/AZFinderTaxonomyIndexTidWidget.php
+++ b/modules/custom/az_finder/src/Plugin/better_exposed_filters/filter/AZFinderTaxonomyIndexTidWidget.php
@@ -4,9 +4,10 @@
namespace Drupal\az_finder\Plugin\better_exposed_filters\filter;
-use Drupal\az_finder\AZFinderIcons;
+use Drupal\az_finder\Service\AZFinderIcons;
use Drupal\better_exposed_filters\BetterExposedFiltersHelper;
use Drupal\better_exposed_filters\Plugin\better_exposed_filters\filter\FilterWidgetBase;
+use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -16,6 +17,7 @@
use Drupal\Core\Template\Attribute;
use Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid;
use Drupal\views\ViewExecutable;
+use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -54,10 +56,31 @@ class AZFinderTaxonomyIndexTidWidget extends FilterWidgetBase implements Contain
/**
* The AZFinderIcons service.
*
- * @var \Drupal\az_finder\AZFinderIcons
+ * @var \Drupal\az_finder\Service\AZFinderIcons
*/
protected $azFinderIcons;
+ /**
+ * The config factory service.
+ *
+ * @var \Drupal\Core\Config\ConfigFactoryInterface
+ */
+ protected $configFactory;
+
+ /**
+ * The logger service.
+ *
+ * @var \Psr\Log\LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * The override settings.
+ *
+ * @var array
+ */
+ protected static $overrides = [];
+
/**
* Constructs a new AzFinderWidget object.
*
@@ -71,8 +94,12 @@ class AZFinderTaxonomyIndexTidWidget extends FilterWidgetBase implements Contain
* The renderer service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
- * @param \Drupal\az_finder\AZFinderIcons $az_finder_icons
+ * @param \Drupal\az_finder\Service\AZFinderIcons $az_finder_icons
* The AZFinderIcons service.
+ * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+ * The config factory service.
+ * @param \Psr\Log\LoggerInterface $logger
+ * The logger service.
*/
public function __construct(
array $configuration,
@@ -81,12 +108,16 @@ public function __construct(
RendererInterface $renderer,
EntityTypeManagerInterface $entity_type_manager,
AZFinderIcons $az_finder_icons,
+ ConfigFactoryInterface $config_factory,
+ LoggerInterface $logger,
) {
$configuration += $this->defaultConfiguration();
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->renderer = $renderer;
$this->entityTypeManager = $entity_type_manager;
$this->azFinderIcons = $az_finder_icons;
+ $this->configFactory = $config_factory;
+ $this->logger = $logger;
}
/**
@@ -104,10 +135,21 @@ public static function create(
$plugin_definition,
$container->get('renderer'),
$container->get('entity_type.manager'),
- $container->get('az_finder.icons')
+ $container->get('az_finder.icons'),
+ $container->get('config.factory'),
+ $container->get('logger.channel.az_finder')
);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function defaultConfiguration() {
+ return [
+ 'default_states' => [],
+ ] + parent::defaultConfiguration();
+ }
+
/**
* {@inheritdoc}
*/
@@ -192,10 +234,10 @@ public function exposedFormAlter(array &$form, FormStateInterface $form_state):
}
/**
- * Returns the field ID for the filter.
+ * Returns the field ID for a views filter.
*
- * @param object $filter
- * The filter object.
+ * @param \Drupal\views\Plugin\views\filter\FilterPluginBase $filter
+ * A views filter plugin object.
*
* @return string
* The field ID.
@@ -227,12 +269,10 @@ protected function setFormOptions(array &$form, $field_id): array {
/**
* {@inheritdoc}
*/
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $filter */
- $filter = $this->handler;
-
+ public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$form = parent::buildConfigurationForm($form, $form_state);
$form['help'] = ['#markup' => $this->t('This widget allows you to use the Finder widget for hierarchical taxonomy terms.')];
+ unset($form['advanced']);
return $form;
}
@@ -249,40 +289,79 @@ public static function isApplicable($filter = NULL, array $filter_options = [])
* Preprocesses variables for the az-finder-widget template.
*
* @param array &$variables
- * An associative array containing the element being processed.
+ * An associative array containing the element being processed (passed by
+ * reference).
*/
- public function preprocessAzFinderTaxonomyIndexTidWidget(array &$variables) {
+ public function preprocessAzFinderTaxonomyIndexTidWidget(array &$variables): void {
$element = $variables['element'];
$variables += [
'wrapper_attributes' => new Attribute(),
'children' => Element::children($element),
'attributes' => ['name' => $element['#name']],
];
- if (!empty($element['#hierarchy'])) {
- $variables['is_nested'] = TRUE;
- }
-
$variables['is_nested'] = TRUE;
$variables['depth'] = [];
$element = $variables['element'];
- // Example logic to structure elements (simplified for illustration).
- foreach ($variables['children'] as $child) {
+ // Retrieve view_id and display_id from the element's #context.
+ $view_id = $element['#context']['#view_id'];
+ $display_id = $element['#context']['#display_id'];
+
+ // Load the view entity and get the display options.
+ $view_storage = $this->entityTypeManager->getStorage('view');
+ $view = $view_storage->load($view_id);
+ if ($view) {
+ $display_options = $view->get('display')[$display_id]['display_options'] ?? [];
+ // Check if 'filters' is set in display-specific options.
+ if (empty($display_options['filters']) && isset($view->get('display')['default']['display_options']['filters'])) {
+ $default_filters = $view->get('display')['default']['display_options']['filters'];
+ $display_options['filters'] = $default_filters;
+ }
+ }
+ else {
+ $this->logger->error('Unable to load view: @view_id', ['@view_id' => $view_id]);
+ return;
+ }
+
+ // Get the handler options for taxonomy reference fields.
+ $vid = NULL;
+ if (isset($display_options['filters'])) {
+ foreach ($display_options['filters'] as $filter) {
+ if ($filter['plugin_id'] === 'taxonomy_index_tid') {
+ $vid = $filter['vid'];
+ break;
+ }
+ }
+ }
+ if (!$vid) {
+ $this->logger->error('Unable to find vocabulary ID (vid) in handler options.');
+ return;
+ }
+ // Load override settings.
+ $overrides = $this->getOverrideConfigurations($view_id, $display_id);
+ $state_overrides = [];
+ // Create a flat array of the overrides by term id.
+ foreach ($overrides as $vid => $override) {
+ $state_overrides += $override['state_overrides'] ?? [];
+ }
+ $variables['overrides'] = $state_overrides;
+ // Load global default settings.
+ $global_settings = $this->configFactory->get('az_finder.settings');
+ $global_default_state = $global_settings->get('tid_widget.default_state') ?? '';
+ foreach ($variables['children'] as $child) {
if ($child === 'All') {
// Special handling for "All" option.
$variables['depth'][$child] = 0;
continue;
}
- // $entity_type = $child_element['#entity_type'];
+
$entity_type = 'taxonomy_term';
- $entity_id = $child;
+ $entity_id = is_numeric($child) ? $child : str_replace('tid:', '', $child);
+ $state = $state_overrides[$entity_id] ?? $global_default_state;
+ $variables['element'][$child]['#state'] = $state;
$entity_storage = $this->entityTypeManager->getStorage($entity_type);
$children = method_exists($entity_storage, 'loadChildren') ? $entity_storage->loadChildren($entity_id) : [];
- if (empty($children) && $entity_type !== 'taxonomy_term') {
- continue;
- }
-
$original_title = $element[$child]['#title'];
if (empty($original_title)) {
continue;
@@ -291,44 +370,77 @@ public function preprocessAzFinderTaxonomyIndexTidWidget(array &$variables) {
$list_title = [
'#type' => 'html_tag',
];
+
// Determine if the child has sub-elements (actual children).
// Calculate depth based on hyphens in the title as a proxy for hierarchy.
$depth = strlen($original_title) - strlen($cleaned_title);
$list_title['#value'] = $cleaned_title;
- // Decide which icon to use based on depth.
+
+ // Decide which icon to use based on depth and state.
$icons = $this->azFinderIcons->generateSvgIcons();
$level_0_collapse_icon = $icons['level_0_collapse'];
+ $level_0_expand_icon = $icons['level_0_expand'];
$level_1_collapse_icon = $icons['level_1_collapse'];
- if (!empty($level_0_collapse_icon) && !empty($level_1_collapse_icon)) {
- $collapse_icon = $depth === 0 ? $level_0_collapse_icon : $level_1_collapse_icon;
+ $level_1_expand_icon = $icons['level_1_expand'];
+ if ($depth === 0) {
+ // Use level 0 icons.
+ $collapse_icon = $level_0_collapse_icon;
+ $expand_icon = $level_0_expand_icon;
}
else {
- $collapse_icon = $icons['level_0_collapse'];
+ // Use level 1 icons.
+ $collapse_icon = $level_1_collapse_icon;
+ $expand_icon = $level_1_expand_icon;
+ }
+
+ // Select the icon based on the state if it is expand or collapse.
+ if ($state === 'expand') {
+ // Use collapse icon when expanded.
+ $icon = $collapse_icon;
+ }
+ elseif ($state === 'collapse') {
+ // Use expand icon when collapsed.
+ $icon = $expand_icon;
}
+ else {
+ // Do not set an icon for other states.
+ $icon = NULL;
+ }
+
$variables['depth'][$child] = $depth;
$list_title['#value'] = $cleaned_title;
$variables['element'][$child]['#title'] = $list_title['#value'];
if (!empty($children)) {
$list_title_link = [
+ '#state' => $state,
'#type' => 'html_tag',
'#tag' => 'a',
'#attributes' => [
'class' => [],
],
];
+
$collapse_id = 'collapse-az-finder-' . $entity_id;
$list_title_link['#attributes']['data-toggle'] = 'collapse';
$list_title_link['#attributes']['href'] = '#' . $collapse_id;
$list_title_link['#attributes']['class'][] = 'd-block';
$list_title_link['#attributes']['role'] = 'button';
- $list_title_link['#attributes']['aria-expanded'] = 'true';
+ if ($state === 'expand') {
+ $list_title_link['#attributes']['aria-expanded'] = 'true';
+ }
+ else {
+ $list_title_link['#attributes']['aria-expanded'] = 'false';
+ $list_title_link['#attributes']['class'][] = 'collapsed';
+ }
$list_title_link['#attributes']['aria-controls'] = $collapse_id;
$list_title_link['#attributes']['data-collapse-id'] = $collapse_id;
$list_title_link['#attributes']['class'][] = 'collapser';
$list_title_link['#attributes']['class'][] = 'level-' . $depth;
$list_title_link['#attributes']['class'][] = 'text-decoration-none';
- $list_title['icon'] = $collapse_icon;
+ if ($icon !== NULL) {
+ $list_title['icon'] = $icon;
+ }
if ($depth === 0) {
$list_title_link['#attributes']['class'][] = 'js-svg-replace-level-0';
$list_title['#tag'] = 'h3';
@@ -349,30 +461,28 @@ public function preprocessAzFinderTaxonomyIndexTidWidget(array &$variables) {
$list_title['#attributes']['class'][] = 'align-items-center';
}
$list_title_link['value'] = $list_title;
-
// Apply the modified list title to the element.
$variables['element'][$child] = $list_title_link;
}
}
-
}
/**
- * Calculates depth for a given option label.
+ * Calculate the depth of the option.
*
* @param mixed $option
- * The option, which can be a string label or an object with properties.
+ * The option to calculate the depth for.
*
* @return int
- * The calculated depth.
+ * The depth of the option.
*/
protected function calculateDepth($option): int {
// Initialize depth.
$depth = 0;
// Ensure $option is a string before processing.
- $optionLabel = is_object($option) ? (property_exists($option, 'label') ? $option->label : '') : $option;
+ $label = is_object($option) ? (property_exists($option, 'label') ? $option->label : '') : $option;
// Use a loop or string function to count leading hyphens in the label.
- while (isset($optionLabel[$depth]) && $optionLabel[$depth] === '-') {
+ while (isset($label[$depth]) && $label[$depth] === '-') {
$depth++;
}
@@ -402,4 +512,44 @@ protected function getAccessibleActionTitle($action, $depth): ?string {
return ucfirst($action) . " level $level";
}
+ /**
+ * {@inheritdoc}
+ */
+ public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+ parent::submitConfigurationForm($form, $form_state);
+
+ $default_states = [];
+ $values = $form_state->getValue('default_states');
+ foreach ($values as $tid => $state) {
+ $default_states[$tid] = $state;
+ }
+
+ $this->configuration['default_states'] = $default_states;
+ }
+
+ /**
+ * Get override configurations.
+ */
+ public function getOverrideConfigurations($view_id, $display_id) {
+ $config_key = "$view_id.$display_id";
+ if (!isset(self::$overrides[$config_key])) {
+ $config_name = "az_finder.tid_widget.$view_id.$display_id";
+ $config = $this->configFactory->getEditable($config_name) ?? NULL;
+ $overrides = [];
+ if ($config) {
+ $vocabularies = $config->get('vocabularies') ?? [];
+ foreach ($vocabularies as $vocabulary_id => $vocabulary) {
+ $terms = $vocabulary['terms'];
+ foreach ($terms as $term_id => $override) {
+ if (!empty($override['default_state'])) {
+ $overrides[$vocabulary_id]['state_overrides'][$term_id] = $override['default_state'];
+ }
+ }
+ }
+ }
+ self::$overrides[$config_key] = $overrides;
+ }
+ return self::$overrides[$config_key];
+ }
+
}
diff --git a/modules/custom/az_finder/src/AZFinderIcons.php b/modules/custom/az_finder/src/Service/AZFinderIcons.php
similarity index 98%
rename from modules/custom/az_finder/src/AZFinderIcons.php
rename to modules/custom/az_finder/src/Service/AZFinderIcons.php
index 82ebbc62da..99d181921f 100644
--- a/modules/custom/az_finder/src/AZFinderIcons.php
+++ b/modules/custom/az_finder/src/Service/AZFinderIcons.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Drupal\az_finder;
+namespace Drupal\az_finder\Service;
/**
* Provides SVG icons for the Quickstart Finder module.
diff --git a/modules/custom/az_finder/src/Service/AZFinderOverrides.php b/modules/custom/az_finder/src/Service/AZFinderOverrides.php
new file mode 100644
index 0000000000..56ec82b1d2
--- /dev/null
+++ b/modules/custom/az_finder/src/Service/AZFinderOverrides.php
@@ -0,0 +1,64 @@
+configFactory = $config_factory;
+ }
+
+ /**
+ * Get existing overrides.
+ */
+ public function getExistingOverrides() {
+ $config_names = $this->configFactory->listAll('az_finder.tid_widget.');
+ $overrides = [];
+
+ foreach ($config_names as $config_name) {
+ $view_id_display_id = substr($config_name, strlen('az_finder.tid_widget.'));
+ [$view_id, $display_id] = explode('.', $view_id_display_id);
+
+ // Get the specific display config.
+ $view_config = $this->configFactory->get('views.view.' . $view_id);
+ $display_options = $view_config->get('display.' . $display_id . '.display_options') ?? [];
+
+ // Check if 'filters' is set in display-specific options.
+ if (empty($display_options['filters']) && isset($view_config->get('display')['default']['display_options']['filters'])) {
+ $default_filters = $view_config->get('display')['default']['display_options']['filters'];
+ $display_options['filters'] = $default_filters;
+ }
+
+ $overrides[$view_id . ':' . $display_id] = [
+ 'view_id' => $view_id,
+ 'display_id' => $display_id,
+ 'view_label' => $view_config->get('label') ?? '',
+ 'display_title' => $view_config->get('display.' . $display_id . '.display_title') ?? '',
+ 'vocabularies' => $display_options['filters']['vocabularies'] ?? [],
+ ];
+ }
+
+ return $overrides;
+ }
+
+}
diff --git a/modules/custom/az_finder/src/Service/AZFinderViewOptions.php b/modules/custom/az_finder/src/Service/AZFinderViewOptions.php
new file mode 100644
index 0000000000..9470e80d9a
--- /dev/null
+++ b/modules/custom/az_finder/src/Service/AZFinderViewOptions.php
@@ -0,0 +1,89 @@
+cacheBackend = $cache_backend;
+ $this->entityTypeManager = $entity_type_manager;
+ }
+
+ /**
+ * Get the view options for a plugin.
+ */
+ public function getViewOptions(string $plugin_id = 'az_finder_tid_widget', bool $force_refresh = FALSE): array {
+ $cache_id = 'az_finder:view_options:' . $plugin_id;
+ if (!$force_refresh) {
+ $cached_data = $this->cacheBackend->get($cache_id);
+ if ($cached_data) {
+ return $cached_data->data;
+ }
+ }
+
+ $viewOptions = $this->getViewsUsingPlugin($plugin_id);
+ $this->cacheBackend->set($cache_id, $viewOptions, CacheBackendInterface::CACHE_PERMANENT, ['az_finder:view_options']);
+ return $viewOptions;
+ }
+
+ /**
+ * Get the views using a specific plugin id.
+ */
+ private function getViewsUsingPlugin(string $plugin_id): array {
+ $options = ['' => '- Select -'];
+ $views = $this->entityTypeManager->getStorage('view')->loadMultiple();
+
+ foreach ($views as $view) {
+ // Get the view executable.
+ $view_exec = $view->getExecutable();
+ $displays = $view->get('display') ?: [];
+ foreach ($displays as $display_id => $display) {
+ // Initialize the view with the selected display.
+ $view_exec->initDisplay();
+ $view_exec->setDisplay($display_id);
+ // Load the display handler so we have access to the overridden options.
+ $display_handler = $view_exec->getDisplay();
+ if ($display_handler->isDefaultDisplay()) {
+ // Don't display master displays as override options.
+ continue;
+ }
+ $exposed_form_options = $display_handler->getOption('exposed_form') ?? [];
+ $filters = $exposed_form_options['options']['bef']['filter'] ?? [];
+ foreach ($filters as $filter_id => $filter_settings) {
+ if (isset($filter_settings['plugin_id']) && $filter_settings['plugin_id'] === $plugin_id) {
+ $options[$view->id() . ':' . $display_id] = $view->label() . ' (' . $displays[$display_id]['display_title'] . ')';
+ break;
+ }
+ }
+ }
+ }
+
+ return $options;
+ }
+
+}
diff --git a/modules/custom/az_finder/src/Service/AZFinderVocabulary.php b/modules/custom/az_finder/src/Service/AZFinderVocabulary.php
new file mode 100644
index 0000000000..b520f8eb82
--- /dev/null
+++ b/modules/custom/az_finder/src/Service/AZFinderVocabulary.php
@@ -0,0 +1,103 @@
+entityTypeManager = $entity_type_manager;
+ $this->stringTranslation = $string_translation;
+ }
+
+ /**
+ * Get the vocabulary IDs for a filter.
+ */
+ public function getVocabularyIdsForFilter($view_id, $display_id, $filter_id) {
+ $vocabulary_ids = [];
+ $view = $this->entityTypeManager->getStorage('view')->load($view_id);
+ if ($view) {
+ $display = $view->getDisplay($display_id);
+ $filters = $display['display_options']['filters'] ?? [];
+
+ // Check if 'filters' is set in display-specific options.
+ if (empty($filters) && isset($view->get('display')['default']['display_options']['filters'])) {
+ $default_filters = $view->get('display')['default']['display_options']['filters'];
+ $filters = array_merge($filters, $default_filters);
+ }
+ foreach ($filters as $filter) {
+ if (($filter['exposed'] ?? FALSE) !== TRUE) {
+ continue;
+ }
+ if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'taxonomy_index_tid') {
+ $vocabulary_ids[] = $filter['vid'];
+ }
+ }
+ }
+ return $vocabulary_ids;
+ }
+
+ /**
+ * Add a section to the form for configuring vocabulary terms.
+ *
+ * @param array $form_section
+ * The form section to add the terms table to.
+ * @param int $vocabulary_id
+ * The vocabulary ID.
+ * @param string $view_id
+ * The view ID.
+ * @param string $display_id
+ * The display ID.
+ */
+ public function addTermsTable(&$form_section, $vocabulary_id, $view_id, $display_id) {
+ $terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadTree($vocabulary_id);
+ $config_id = "az_finder.tid_widget.$view_id.$display_id";
+ $vocabulary_config_path = "$config_id:vocabularies.$vocabulary_id";
+ $vocabulary_label = $this->entityTypeManager->getStorage('taxonomy_vocabulary')->load($vocabulary_id)->label();
+
+ $form_section['terms_table'] = [
+ '#type' => 'table',
+ '#header' => [
+ $this->t('Terms in :vocabulary vocabulary', [':vocabulary' => $vocabulary_label]),
+ $this->t('Override'),
+ ],
+ '#empty' => $this->t('No terms found.'),
+ ];
+
+ foreach ($terms as $term) {
+ $form_section['terms_table'][$term->tid]['term_name'] = [
+ '#markup' => str_repeat('-', $term->depth) . $term->name,
+ ];
+ $form_section['terms_table'][$term->tid]['override'] = [
+ '#type' => 'select',
+ '#options' => [
+ '' => $this->t('Default'),
+ 'expand' => $this->t('Expanded'),
+ 'collapse' => $this->t('Collapsed'),
+ ],
+ '#config_target' => "$vocabulary_config_path.terms.{$term->tid}.default_state",
+ ];
+ }
+ }
+
+}
diff --git a/modules/custom/az_finder/templates/az-finder-nested-elements.html.twig b/modules/custom/az_finder/templates/az-finder-nested-elements.html.twig
index aba754dad4..ca1f938c6d 100644
--- a/modules/custom/az_finder/templates/az-finder-nested-elements.html.twig
+++ b/modules/custom/az_finder/templates/az-finder-nested-elements.html.twig
@@ -21,7 +21,7 @@
{% if delta %}
{% for i in 1..delta %}
{% if new_nesting_level > current_nesting_level %}
-
+
{% endif %}
diff --git a/modules/custom/az_finder/templates/az-finder-widget.html.twig b/modules/custom/az_finder/templates/az-finder-widget.html.twig
index 24f62b4c1c..520e296552 100644
--- a/modules/custom/az_finder/templates/az-finder-widget.html.twig
+++ b/modules/custom/az_finder/templates/az-finder-widget.html.twig
@@ -10,6 +10,7 @@
- depth: If is_nested is TRUE, this holds an array in the form of
child_id => nesting_level which defines the depth a given element should
appear in the nested list.
+ - state: The state of the element.
#}
{% set classes = [
@@ -27,10 +28,14 @@
{% set new_nesting_level = attribute(depth, child) %}
{% set vars = {
collapse_id: vars.collapse_id ?? item['#attributes']['data-collapse-id'],
+ is_expanded: vars.is_expanded ?? item['#attributes']['aria-expanded'],
+ state: vars.state ?? item['#state'],
} %}
{% include '@az_finder/az-finder-nested-elements.html.twig' with vars %}
{% set vars = {
collapse_id: item['#attributes']['data-collapse-id'] ?? vars.collapse_id,
+ is_expanded: item['#attributes']['aria-expanded'] ?? vars.is_expanded,
+ state: item['#state'] ?? vars.state,
} %}
{% set current_nesting_level = new_nesting_level %}
{% else %}
diff --git a/modules/custom/az_finder/tests/AZFinderIconsTest.php b/modules/custom/az_finder/tests/AZFinderIconsTest.php
index d75ebb2048..9a46a66379 100644
--- a/modules/custom/az_finder/tests/AZFinderIconsTest.php
+++ b/modules/custom/az_finder/tests/AZFinderIconsTest.php
@@ -4,7 +4,7 @@
namespace Drupal\Tests\az_finder\Unit;
-use Drupal\az_finder\AZFinderIcons;
+use Drupal\az_finder\Service\AZFinderIcons;
use PHPUnit\Framework\TestCase;
/**