diff --git a/lam/lib/html.inc b/lam/lib/html.inc index be4ba4f73..39f2ab6da 100644 --- a/lam/lib/html.inc +++ b/lam/lib/html.inc @@ -3654,6 +3654,7 @@ class htmlAccordion extends htmlElement { private $id; private $elements; private $openInitial; + private $saveState; /** * Constructor. @@ -3680,23 +3681,21 @@ class htmlAccordion extends htmlElement { */ function generateHTML($module, $input, $values, $restricted, $scope) { $result = array(); - $active = 'false'; if ($this->openInitial !== false) { - $active = $this->openInitial; + $this->addDataAttribute('openinitial', $this->openInitial); } - echo '
'; + $cssClasses = $this->getCSSClasses(); + $cssClasses[] = 'lam-accordion-container'; + if ($this->saveState) { + $this->addDataAttribute('savestate', 'true'); + } + echo '
getDataAttributesAsString() . '>'; $contentIndex = 0; foreach ($this->elements as $label => $content) { - $activeClassButton = ''; - $activeClassContent = ''; - if ($contentIndex === $active) { - $activeClassButton = 'lam-accordion-button-active'; - $activeClassContent = 'lam-accordion-content-active'; - } - echo ''; - echo '
'; + echo '
'; echo '
'; $result = array_merge($result, $content->generateHTML($module, $input, $values, $restricted, $scope)); echo '
'; @@ -3704,11 +3703,20 @@ class htmlAccordion extends htmlElement { $contentIndex++; } $hiddenIndexId = $this->id . "_index"; - echo ''; + echo ''; echo '
'; return $result; } + /** + * Saves the state of open/closed items over page reloads. + * + * @param bool $saveState save state + */ + public function saveState(bool $saveState = true): void { + $this->saveState = $saveState; + } + } /** diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index 2e7894c9d..52428e9b2 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -3148,9 +3148,34 @@ window.lam.accordion.init = function() { return false; }); }); - const accordionContentAreas = document.getElementsByClassName('lam-accordion-content-active'); - Array.from(accordionContentAreas).forEach(function (contentArea) { - contentArea.style.maxHeight = contentArea.scrollHeight + 'px'; + const accordions = document.getElementsByClassName('lam-accordion-container'); + Array.from(accordions).forEach(function (accordion) { + const isSaveState = accordion.dataset.savestate && (accordion.dataset.savestate === 'true'); + let openInitial = false; + const storageKey = 'lam_accordionStore_' + accordion.id; + if (isSaveState && window.localStorage.getItem(storageKey)) { + // load value from local storage + openInitial = window.localStorage.getItem(storageKey); + } + else if (accordion.dataset.openinitial) { + openInitial = accordion.dataset.openinitial; + } + if (openInitial !== false) { + accordion.querySelectorAll('.lam-accordion-button').forEach(item => { + const buttonIndex = item.dataset.index; + if (openInitial === buttonIndex) { + item.classList.add('lam-accordion-button-active'); + } + }); + accordion.querySelectorAll('.lam-accordion-content').forEach(item => { + const contentIndex = item.dataset.index; + if (openInitial === contentIndex) { + item.style.maxHeight = null; + item.classList.add('lam-accordion-content-active') + item.style.maxHeight = item.scrollHeight + 'px'; + } + }); + } }); } @@ -3175,16 +3200,21 @@ window.lam.accordion.onClick = function(event, button) { content.classList.add('lam-accordion-content-active') } const indexActive = button.dataset.index; - const parent = button.parentElement; + const accordion = button.parentElement; + const isSaveState = accordion.dataset.savestate && (accordion.dataset.savestate === 'true'); + if (isSaveState) { + const storageKey = 'lam_accordionStore_' + accordion.id; + window.localStorage.setItem(storageKey, indexActive); + } // deactivate other buttons - parent.querySelectorAll('.lam-accordion-button').forEach(item => { + accordion.querySelectorAll('.lam-accordion-button').forEach(item => { const buttonIndex = item.dataset.index; if (indexActive !== buttonIndex) { item.classList.remove('lam-accordion-button-active'); } }); // close other content areas - parent.querySelectorAll('.lam-accordion-content').forEach(item => { + accordion.querySelectorAll('.lam-accordion-content').forEach(item => { const contentIndex = item.dataset.index; if (indexActive !== contentIndex) { item.style.maxHeight = null; diff --git a/lam/tests/design/designExamples.php b/lam/tests/design/designExamples.php index 47ac32ae1..e0f4a2576 100644 --- a/lam/tests/design/designExamples.php +++ b/lam/tests/design/designExamples.php @@ -289,6 +289,20 @@ $row->add(new htmlSpacer(null, '5rem')); +$accordionElementsSaveState = []; +for ($i = 0; $i < 5; $i++) { + $accordionElementsSaveStateContent = new htmlResponsiveRow(); + $accordionElementsSaveStateContent->add(new htmlResponsiveInputField('Input 1', 'accSi1' . $i)); + $accordionElementsSaveStateContent->add(new htmlResponsiveInputField('Input 2', 'accSi2' . $i)); + $accordionElementsSaveStateContent->add(new htmlResponsiveInputTextarea('accSi3' . $i, '', 20, 3, 'Text area')); + $accordionElementsSaveState['Accordion with saved state ' . $i] = $accordionElementsSaveStateContent; +} +$saveStateAccordion = new htmlAccordion('acc_save', $accordionElementsSaveState, 2); +$saveStateAccordion->saveState(); +$row->add($saveStateAccordion); + +$row->add(new htmlSpacer(null, '5rem')); + $row->add(new htmlSubTitle('Sortable list')); $sortableList1 = new htmlSortableList([