diff --git a/config/install/toc_api.toc_type.default.yml b/config/install/toc_api.toc_type.default.yml index 705ec78a9673d3aa4980ead230e8a123125db2fd..e4dddc2c715cac5c8132ca504367b941a5689f73 100644 --- a/config/install/toc_api.toc_type.default.yml +++ b/config/install/toc_api.toc_type.default.yml @@ -14,6 +14,8 @@ options: header_id: title header_id_prefix: section header_exclude_xpath: '' + wrapper: div + title_wrapper: h3 top_label: 'Back to top' top_min: 2 top_max: 2 diff --git a/config/install/toc_api.toc_type.full.yml b/config/install/toc_api.toc_type.full.yml index dd671e8a53c4a23bde96b06f23637b75f61bf5a1..9218b8537b23de6e03bfcc52aeb20b1145ce2e47 100644 --- a/config/install/toc_api.toc_type.full.yml +++ b/config/install/toc_api.toc_type.full.yml @@ -14,6 +14,8 @@ options: header_id: title header_id_prefix: section header_exclude_xpath: '' + wrapper: div + title_wrapper: h3 top_label: 'Back to top' top_min: 2 top_max: 2 diff --git a/config/install/toc_api.toc_type.full_numbered.yml b/config/install/toc_api.toc_type.full_numbered.yml index 61961c7f0710aa311d50bd40130d3fd58716b81a..5bfcaced9e78b99b28392645e0c81a517427e01e 100644 --- a/config/install/toc_api.toc_type.full_numbered.yml +++ b/config/install/toc_api.toc_type.full_numbered.yml @@ -14,6 +14,8 @@ options: header_id: title header_id_prefix: section header_exclude_xpath: '' + wrapper: div + title_wrapper: h3 top_label: 'Back to top' top_min: 2 top_max: 2 diff --git a/config/install/toc_api.toc_type.simple.yml b/config/install/toc_api.toc_type.simple.yml index 20bfad37967a5c1dd1a940dd4c9befc2afec32d8..c4f6a318be950961f2ef2e48cb526d901e4b575f 100644 --- a/config/install/toc_api.toc_type.simple.yml +++ b/config/install/toc_api.toc_type.simple.yml @@ -14,6 +14,8 @@ options: header_id: title header_id_prefix: section header_exclude_xpath: '' + wrapper: div + title_wrapper: h3 top_label: 'Back to top' top_min: 2 top_max: 2 diff --git a/config/install/toc_api.toc_type.simple_numbered.yml b/config/install/toc_api.toc_type.simple_numbered.yml index bcccb138e7affd3a3f8671905b0f216a9fec2d20..9ad46c2bb2436e0376c3d7fc395b12452150a934 100644 --- a/config/install/toc_api.toc_type.simple_numbered.yml +++ b/config/install/toc_api.toc_type.simple_numbered.yml @@ -14,6 +14,8 @@ options: header_id: title header_id_prefix: section header_exclude_xpath: '' + wrapper: div + title_wrapper: h3 top_label: 'Back to top' top_min: 2 top_max: 2 diff --git a/config/schema/toc_api.toc_type.schema.yml b/config/schema/toc_api.toc_type.schema.yml index 19bdb585abff3c638d8cdf9f612e99d4107ef499..7500d669daba629f4dba5093336cb1469c798707 100644 --- a/config/schema/toc_api.toc_type.schema.yml +++ b/config/schema/toc_api.toc_type.schema.yml @@ -92,3 +92,9 @@ toc_api.toc_type.*: type: ignore h6: type: ignore + wrapper: + type: string + label: 'Wrapper element' + title_wrapper: + type: string + label: 'Title wrapper' diff --git a/src/TocTypeForm.php b/src/TocTypeForm.php index 9c1012e867387e32b4d0bf0aea5e1fc55622c044..a7ae28441fa781c47272bff14c650b6b2b6aecb7 100644 --- a/src/TocTypeForm.php +++ b/src/TocTypeForm.php @@ -141,6 +141,18 @@ class TocTypeForm extends EntityForm { '#type' => 'textfield', '#default_value' => $options['title'], ]; + $form['options']['general']['title_wrapper'] = [ + '#title' => $this->t('Wrapper element for title'), + '#type' => 'textfield', + '#default_value' => $options['title_wrapper'] ?? 'h3', + '#required' => TRUE, + ]; + $form['options']['general']['wrapper'] = [ + '#title' => $this->t('Wrapper element for table of contents'), + '#type' => 'textfield', + '#default_value' => $options['wrapper'] ?? 'div', + '#required' => TRUE, + ]; // Hide block option since it is up to TOC submodule to decide how to // support it. $form['options']['general']['block'] = [ @@ -335,6 +347,23 @@ class TocTypeForm extends EntityForm { return $form; } + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state): void { + // Validate HTML tag names. + $elements = [ + 'title_wrapper', + 'wrapper', + ]; + foreach ($elements as $element) { + $tag_name = $form_state->getValue(['general', $element]); + if (!preg_match('/^[a-zA-Z0-9-]+$/', $tag_name)) { + $form_state->setErrorByName('general][' . $element, $this->t('Invalid HTML tag name.')); + } + } + } + /** * {@inheritdoc} */ diff --git a/templates/toc-tree.html.twig b/templates/toc-tree.html.twig index 692ae77d2d2194668f196aeef899f02757f18970..e582d62423087f9c06382d6c39f685b4aacef703 100644 --- a/templates/toc-tree.html.twig +++ b/templates/toc-tree.html.twig @@ -6,6 +6,7 @@ * Returns HTML for a nested list representation of a Table of contents.. * * Available variables: + * - options: An array of configuration options. * - tree: A nested list of header items. Each header item contains: * - list_tag: HTML tag for the list. * - list_attributes: HTML attributes for the list. @@ -22,17 +23,18 @@ @see http://twig.sensiolabs.org/doc/tags/macro.html #} {% import _self as toc_api_tree %} -{% set classes = ['toc', 'toc-tree'] %} -<div{{ attributes.addClass(classes) }}> +{% set wrapper = options.wrapper ?? 'div' %} +<{{ wrapper }}{{ attributes }}> {% if tree.title and not options.block %} - <h3>{{ tree.title }}</h3> + {% set title_wrapper = options.title_wrapper ?? 'h3' %} + <{{ title_wrapper }}>{{ tree.title }}</{{ title_wrapper }}> {% endif %} {{ toc_api_tree.tree_links(tree) }} -</div> +</{{ wrapper }}> {% macro tree_links(item) %} {% import _self as toc_api_tree %} diff --git a/toc_api.module b/toc_api.module index cdd60e1d214d76dccba0888edd4b219cad7296a7..012f1ea9da6ce7d7cadb9992dcca2d2d83e88d27 100755 --- a/toc_api.module +++ b/toc_api.module @@ -118,6 +118,11 @@ function template_preprocess_toc_tree(&$variables) { $variables['options'] = $toc->getOptions(); + // Add default classes. + $variables['attributes']['class'] = (array) $variables['attributes']['class']; + $variables['attributes']['class'][] = 'toc'; + $variables['attributes']['class'][] = 'toc-tree'; + $variables['attributes'] = new Attribute($variables['attributes']); $variables['#attached']['library'][] = 'toc_api/toc.tree';