From 1caeb8814221196cbace0139f5f6913c8f516527 Mon Sep 17 00:00:00 2001
From: Lee Mills <8024370+millnut@users.noreply.github.com>
Date: Fri, 7 Feb 2025 16:36:35 +0000
Subject: [PATCH 1/8] feat: refactor accordion to details and summary
---
.../css/localgov-accordion.css | 25 +-
.../js/localgov-accordion.js | 498 +++++++++---------
...ragraph--localgov-accordion-pane.html.twig | 26 +-
.../paragraph--localgov-accordion.html.twig | 2 +-
4 files changed, 265 insertions(+), 286 deletions(-)
diff --git a/modules/localgov_subsites_paragraphs/css/localgov-accordion.css b/modules/localgov_subsites_paragraphs/css/localgov-accordion.css
index b56b0b6..677e3a6 100644
--- a/modules/localgov_subsites_paragraphs/css/localgov-accordion.css
+++ b/modules/localgov_subsites_paragraphs/css/localgov-accordion.css
@@ -3,29 +3,6 @@
* Basic styling for Accordion paragraph.
*/
-.accordion-pane__title button {
- width: 100%;
- text-align: left;
-}
-
-.accordion-pane__title button[hidden] {
- display: none;
-}
-
-.accordion--initialised .accordion-pane__content {
- display: none;
-}
-
-.accordion--initialised .accordion-pane__content--open {
- display: block;
-}
-
-/* initial hide of icon within the button, retain pointer events setting if used */
-.accordion-icon {
- display: none;
- pointer-events: none;
-}
-
.accordion-toggle-all {
margin-bottom: var(--vertical-rhythm-spacing);
-}
+}
diff --git a/modules/localgov_subsites_paragraphs/js/localgov-accordion.js b/modules/localgov_subsites_paragraphs/js/localgov-accordion.js
index 9021a2c..ea61da1 100644
--- a/modules/localgov_subsites_paragraphs/js/localgov-accordion.js
+++ b/modules/localgov_subsites_paragraphs/js/localgov-accordion.js
@@ -3,255 +3,255 @@
* Localgov Accordion behaviour.
*/
-(Drupal => {
- Drupal.behaviors.localgovAccordion = {
- /**
- * Attach accordion behaviour.
- *
- * @param {object} context
- * DOM object.
- */
- attach(context) {
- const accordions = context.querySelectorAll('.accordion');
-
- for (let i = 0; i < accordions.length; i++) {
- this.init(accordions[i], i);
- }
- },
-
- /**
- * Initialise accordion.
- *
- * @param {HTMLElement} accordion
- * Accordion element.
- * @param {number} index
- * Accordion element index.
- */
- init: function init(accordion, index) {
- /**
- * Expands one accordion pane, setting aria-expanded on button.
- *
- * @param {HTMLElement} button
- * The button associated with the pane to expand.
- * @param {HTMLElement} pane
- * The pane to expand.
- */
- function expandPane(button, pane) {
- button.setAttribute('aria-expanded', 'true');
- pane.classList.add(openClass);
- }
-
- /**
- * Collapses one accordion pane, setting aria-expanded on button.
- *
- * @param {HTMLElement} button
- * The button associated with the pane to collapse.
- * @param {HTMLElement} pane
- * The pane to collapse.
- */
- function collapsePane(button, pane) {
- button.setAttribute('aria-expanded', 'false');
- pane.classList.remove(openClass);
- }
-
- /**
- * Toggles all accordion panes open or closed.
- *
- * Used both as an event listener callback, and called directly.
- */
- function toggleAll() {
- const labelEl = showHideButton.querySelector('.accordion-text');
- const nextState = showHideButton.getAttribute('aria-expanded') !== 'true';
-
- showHideButtonLabel.textContent = showHideButton.dataset[nextState ? 'hideAll' : 'showAll'];
- showHideButton.setAttribute('aria-expanded', nextState);
-
- for (let i = 0; i < numberOfPanes; i++) {
- const currentButton = accordionPanes[i].querySelector('[aria-controls]');
- const currentPane = accordionPanes[i].querySelector('.accordion-pane__content');
-
- if (nextState) {
- expandPane(currentButton, currentPane);
-
- } else {
- collapsePane(currentButton, currentPane);
- }
- }
- }
-
- /**
- * Gets the state of the accordion: all expanded, all collapsed, or mixed.
- *
- * @return {number}
- * Returns a numeric value according to state:
- *
- * - all expanded: 1
- * - all collapsed: 0
- * - mixed: -1
- */
- function getAccordionState() {
- const expandedPanes = accordion.querySelectorAll(`.${openClass}`).length;
- return expandedPanes
- ? (expandedPanes === numberOfPanes ? 1 : -1)
- : 0;
- }
-
- const accordionPanes = accordion.querySelectorAll('.accordion-pane');
- const numberOfPanes = accordionPanes.length;
- const initClass = 'accordion--initialised';
- const openClass = 'accordion-pane__content--open';
- const breakpoint = accordion.dataset.accordionTabsSwitch || null;
- const mq = window.matchMedia(`(max-width: '${breakpoint}')`);
- const displayShowHide = accordion.hasAttribute('data-accordion-display-show-hide');
- const allowMultiple = displayShowHide || accordion.hasAttribute('data-accordion-allow-multiple');
- let showHideButton;
- let showHideButtonLabel;
-
- const create = function create() {
- // Only initialise accordion if it hasn't already been done.
- if (accordion.classList.contains(initClass)) {
- return;
- }
-
- for (let i = 0; i < numberOfPanes; i++) {
- const pane = accordionPanes[i];
- const content = pane.querySelectorAll('.accordion-pane__content');
- const title = pane.querySelectorAll('.accordion-pane__title');
- const button = title[0].querySelector('button');
- const heading = title[0].querySelector('.accordion-pane__heading');
- const id = `accordion-content-${index}-${i}`;
-
- // Add id attribute to all pane content elements.
- content[0].setAttribute('id', id);
-
- // Hide default Heading text
- if (heading) {
- heading.hidden = true;
- };
+// (Drupal => {
+// Drupal.behaviors.localgovAccordion = {
+// /**
+// * Attach accordion behaviour.
+// *
+// * @param {object} context
+// * DOM object.
+// */
+// attach(context) {
+// const accordions = context.querySelectorAll('.accordion');
+
+// for (let i = 0; i < accordions.length; i++) {
+// this.init(accordions[i], i);
+// }
+// },
+
+// /**
+// * Initialise accordion.
+// *
+// * @param {HTMLElement} accordion
+// * Accordion element.
+// * @param {number} index
+// * Accordion element index.
+// */
+// init: function init(accordion, index) {
+// /**
+// * Expands one accordion pane, setting aria-expanded on button.
+// *
+// * @param {HTMLElement} button
+// * The button associated with the pane to expand.
+// * @param {HTMLElement} pane
+// * The pane to expand.
+// */
+// function expandPane(button, pane) {
+// button.setAttribute('aria-expanded', 'true');
+// pane.classList.add(openClass);
+// }
+
+// /**
+// * Collapses one accordion pane, setting aria-expanded on button.
+// *
+// * @param {HTMLElement} button
+// * The button associated with the pane to collapse.
+// * @param {HTMLElement} pane
+// * The pane to collapse.
+// */
+// function collapsePane(button, pane) {
+// button.setAttribute('aria-expanded', 'false');
+// pane.classList.remove(openClass);
+// }
+
+// /**
+// * Toggles all accordion panes open or closed.
+// *
+// * Used both as an event listener callback, and called directly.
+// */
+// function toggleAll() {
+// const labelEl = showHideButton.querySelector('.accordion-text');
+// const nextState = showHideButton.getAttribute('aria-expanded') !== 'true';
+
+// showHideButtonLabel.textContent = showHideButton.dataset[nextState ? 'hideAll' : 'showAll'];
+// showHideButton.setAttribute('aria-expanded', nextState);
+
+// for (let i = 0; i < numberOfPanes; i++) {
+// const currentButton = accordionPanes[i].querySelector('[aria-controls]');
+// const currentPane = accordionPanes[i].querySelector('.accordion-pane__content');
+
+// if (nextState) {
+// expandPane(currentButton, currentPane);
+
+// } else {
+// collapsePane(currentButton, currentPane);
+// }
+// }
+// }
+
+// /**
+// * Gets the state of the accordion: all expanded, all collapsed, or mixed.
+// *
+// * @return {number}
+// * Returns a numeric value according to state:
+// *
+// * - all expanded: 1
+// * - all collapsed: 0
+// * - mixed: -1
+// */
+// function getAccordionState() {
+// const expandedPanes = accordion.querySelectorAll(`.${openClass}`).length;
+// return expandedPanes
+// ? (expandedPanes === numberOfPanes ? 1 : -1)
+// : 0;
+// }
+
+// const accordionPanes = accordion.querySelectorAll('.accordion-pane');
+// const numberOfPanes = accordionPanes.length;
+// const initClass = 'accordion--initialised';
+// const openClass = 'accordion-pane__content--open';
+// const breakpoint = accordion.dataset.accordionTabsSwitch || null;
+// const mq = window.matchMedia(`(max-width: '${breakpoint}')`);
+// const displayShowHide = accordion.hasAttribute('data-accordion-display-show-hide');
+// const allowMultiple = displayShowHide || accordion.hasAttribute('data-accordion-allow-multiple');
+// let showHideButton;
+// let showHideButtonLabel;
+
+// const create = function create() {
+// // Only initialise accordion if it hasn't already been done.
+// if (accordion.classList.contains(initClass)) {
+// return;
+// }
+
+// for (let i = 0; i < numberOfPanes; i++) {
+// const pane = accordionPanes[i];
+// const content = pane.querySelectorAll('.accordion-pane__content');
+// const title = pane.querySelectorAll('.accordion-pane__title');
+// const button = title[0].querySelector('button');
+// const heading = title[0].querySelector('.accordion-pane__heading');
+// const id = `accordion-content-${index}-${i}`;
+
+// // Add id attribute to all pane content elements.
+// content[0].setAttribute('id', id);
+
+// // Hide default Heading text
+// if (heading) {
+// heading.hidden = true;
+// };
- if (button) {
- // Add aria-controls id to button and un-hide
- button.setAttribute('aria-controls', id);
- button.hidden = false;
+// if (button) {
+// // Add aria-controls id to button and un-hide
+// button.setAttribute('aria-controls', id);
+// button.hidden = false;
- // Add click event listener to the show/hide button.
- button.addEventListener('click', e => {
- const targetPaneId = e.target.getAttribute('aria-controls');
- const targetPane = accordion.querySelectorAll(`#${targetPaneId}`);
- const openPane = accordion.querySelectorAll(`.${openClass}`);
-
- // Check the current state of the button and the content it controls.
- if (e.target.getAttribute('aria-expanded') === 'false') {
- // Close currently open pane.
- if (openPane.length && !allowMultiple) {
- const openPaneId = openPane[0].getAttribute('id');
- const openPaneButton = accordion.querySelectorAll(
- `[aria-controls="${openPaneId}"]`,
- );
-
- collapsePane(openPaneButton[0], openPane[0]);
- }
-
- // Show new pane.
- expandPane(e.target, targetPane[0]);
- } else {
- // If target pane is currently open, close it.
- collapsePane(e.target, targetPane[0]);
- }
-
- if (showHideButton) {
- const accordionState = getAccordionState();
- const toggleState = showHideButton.getAttribute('aria-expanded') === 'true';
-
- if (
- (accordionState === 1 && !toggleState) ||
- (!accordionState && toggleState)
- ) {
- toggleAll();
- }
- }
- });
- };
-
- if (button) {
- if (displayShowHide) {
- showHideButton = accordion.querySelector('.accordion-toggle-all');
- showHideButton.hidden = false;
- showHideButton.addEventListener('click', toggleAll);
- showHideButtonLabel = showHideButton.querySelector('.accordion-text');
- }
-
- // Add init class.
- accordion.classList.add(initClass);
- };
-
- }
- };
-
- const destroy = () => {
- for (let i = 0; i < numberOfPanes; i++) {
- // Remove id attributes from buttons in accordion pane titles.
- const button = accordion
- .querySelectorAll('.accordion-pane__title')[i]
- .querySelector('button')
- .removeAttribute('id');
+// // Add click event listener to the show/hide button.
+// button.addEventListener('click', e => {
+// const targetPaneId = e.target.getAttribute('aria-controls');
+// const targetPane = accordion.querySelectorAll(`#${targetPaneId}`);
+// const openPane = accordion.querySelectorAll(`.${openClass}`);
+
+// // Check the current state of the button and the content it controls.
+// if (e.target.getAttribute('aria-expanded') === 'false') {
+// // Close currently open pane.
+// if (openPane.length && !allowMultiple) {
+// const openPaneId = openPane[0].getAttribute('id');
+// const openPaneButton = accordion.querySelectorAll(
+// `[aria-controls="${openPaneId}"]`,
+// );
+
+// collapsePane(openPaneButton[0], openPane[0]);
+// }
+
+// // Show new pane.
+// expandPane(e.target, targetPane[0]);
+// } else {
+// // If target pane is currently open, close it.
+// collapsePane(e.target, targetPane[0]);
+// }
+
+// if (showHideButton) {
+// const accordionState = getAccordionState();
+// const toggleState = showHideButton.getAttribute('aria-expanded') === 'true';
+
+// if (
+// (accordionState === 1 && !toggleState) ||
+// (!accordionState && toggleState)
+// ) {
+// toggleAll();
+// }
+// }
+// });
+// };
+
+// if (button) {
+// if (displayShowHide) {
+// showHideButton = accordion.querySelector('.accordion-toggle-all');
+// showHideButton.hidden = false;
+// showHideButton.addEventListener('click', toggleAll);
+// showHideButtonLabel = showHideButton.querySelector('.accordion-text');
+// }
+
+// // Add init class.
+// accordion.classList.add(initClass);
+// };
+
+// }
+// };
+
+// const destroy = () => {
+// for (let i = 0; i < numberOfPanes; i++) {
+// // Remove id attributes from buttons in accordion pane titles.
+// const button = accordion
+// .querySelectorAll('.accordion-pane__title')[i]
+// .querySelector('button')
+// .removeAttribute('id');
- // Hide buttons in accordion pane titles.
- if (button) {
- button.hidden = true;
- }
-
- // Un-hide default heading text
- const heading = accordion
- .querySelectorAll('.accordion-pane__title')[i]
- .querySelector('.accordion-pane__heading');
-
- if (heading) {
- heading.hidden = false;
- }
-
- // Remove id attributes from pane content elements.
- accordionPanes[i]
- .querySelectorAll('.accordion-pane__content')[0]
- .removeAttribute('id');
-
- // Remove open class from accordion pane's content elements.
- if (
- accordionPanes[i]
- .querySelectorAll('.accordion-pane__content')[0]
- .classList.contains(openClass)
- ) {
- accordionPanes[i]
- .querySelectorAll('.accordion-pane__content')[0]
- .classList.remove(openClass);
- }
- }
-
- if (displayShowHide) {
- showHideButton.hidden = true;
- showHideButton.removeEventListener('click', toggleAll);
- }
-
- // Remove accordion init class.
- accordion.classList.remove(initClass);
- };
-
- const breakpointCheck = function breakpointCheck() {
- if (mq.matches || breakpoint === null) {
- create();
- } else {
- destroy();
- }
- };
-
- // Trigger create/destroy functions at different screen widths
- // based on the value of data-accordion-tabs-switch attribute.
- if (window.matchMedia) {
- mq.addEventListener("change", () => {
- breakpointCheck();
- });
- breakpointCheck();
- }
- },
- };
-})(Drupal);
+// // Hide buttons in accordion pane titles.
+// if (button) {
+// button.hidden = true;
+// }
+
+// // Un-hide default heading text
+// const heading = accordion
+// .querySelectorAll('.accordion-pane__title')[i]
+// .querySelector('.accordion-pane__heading');
+
+// if (heading) {
+// heading.hidden = false;
+// }
+
+// // Remove id attributes from pane content elements.
+// accordionPanes[i]
+// .querySelectorAll('.accordion-pane__content')[0]
+// .removeAttribute('id');
+
+// // Remove open class from accordion pane's content elements.
+// if (
+// accordionPanes[i]
+// .querySelectorAll('.accordion-pane__content')[0]
+// .classList.contains(openClass)
+// ) {
+// accordionPanes[i]
+// .querySelectorAll('.accordion-pane__content')[0]
+// .classList.remove(openClass);
+// }
+// }
+
+// if (displayShowHide) {
+// showHideButton.hidden = true;
+// showHideButton.removeEventListener('click', toggleAll);
+// }
+
+// // Remove accordion init class.
+// accordion.classList.remove(initClass);
+// };
+
+// const breakpointCheck = function breakpointCheck() {
+// if (mq.matches || breakpoint === null) {
+// create();
+// } else {
+// destroy();
+// }
+// };
+
+// // Trigger create/destroy functions at different screen widths
+// // based on the value of data-accordion-tabs-switch attribute.
+// if (window.matchMedia) {
+// mq.addEventListener("change", () => {
+// breakpointCheck();
+// });
+// breakpointCheck();
+// }
+// },
+// };
+// })(Drupal);
diff --git a/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion-pane.html.twig b/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion-pane.html.twig
index d0a622b..3d6e75f 100644
--- a/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion-pane.html.twig
+++ b/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion-pane.html.twig
@@ -48,21 +48,23 @@
'accordion-pane'
]
%}
+
+{% set accordion = paragraph.getParentEntity() %}
+{% set group_accordion = accordion.localgov_allow_multiple_open.value == 1 and accordion.localgov_display_show_hide_all.value != 1 %}
+
{% block paragraph %}
{% block content %}
-
- <{{ heading_level }}>
- {{ heading_text }}
-
- {{ heading_level }}>
-
-
- {{ content.localgov_body_text }}
-
+
+
+ <{{ heading_level }}>
+ {{ heading_text }}
+ {{ heading_level }}>
+
+
+ {{ content.localgov_body_text }}
+
+
{% endblock %}
{% endblock paragraph %}
diff --git a/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion.html.twig b/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion.html.twig
index 32308bc..f215609 100644
--- a/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion.html.twig
+++ b/modules/localgov_subsites_paragraphs/templates/paragraph--localgov-accordion.html.twig
@@ -64,7 +64,7 @@
{% if paragraph.localgov_display_show_hide_all.value == 1 %}
{% set show_all = 'Show all sections'|t %}
{% set hide_all = 'Hide all sections'|t %}
-