diff --git a/src/bundle/Resources/config/bazinga_js_translation.yaml b/src/bundle/Resources/config/bazinga_js_translation.yaml
index ad62c5d39e..830fa2dbab 100644
--- a/src/bundle/Resources/config/bazinga_js_translation.yaml
+++ b/src/bundle/Resources/config/bazinga_js_translation.yaml
@@ -12,5 +12,6 @@ active_domains:
- 'ibexa_user_invitation'
- 'ibexa_content_type'
- 'ibexa_dropdown'
+ - 'ibexa_collapse'
- 'ibexa_popup_menu'
- 'messages'
diff --git a/src/bundle/Resources/public/js/scripts/core/collapse.js b/src/bundle/Resources/public/js/scripts/core/collapse.js
index 77da449ee4..d7fce01003 100644
--- a/src/bundle/Resources/public/js/scripts/core/collapse.js
+++ b/src/bundle/Resources/public/js/scripts/core/collapse.js
@@ -1,4 +1,16 @@
-(function (global, doc) {
+(function (global, doc, bootstrap, Translator) {
+ let toggleAllTimeout;
+ const TOGGLE_TIMEOUT = 200;
+ const toggleAllBtns = [...doc.querySelectorAll(`[data-multi-collapse-btn-id]`)];
+ const toggleMultiCollapseBtn = (btn, changeToCollapseAll) => {
+ const displayedText = changeToCollapseAll
+ ? Translator.trans(/*@Desc("Collapse all sections")*/ 'collapse.collapse_all', {}, 'ibexa_collapse')
+ : Translator.trans(/*@Desc("Expand all sections")*/ 'collapse.expand_all', {}, 'ibexa_collapse');
+
+ btn.innerText = displayedText;
+ btn.classList.toggle('ibexa-multi-collapse__btn--expand-all-label', !changeToCollapseAll);
+ };
+
doc.querySelectorAll('.ibexa-collapse').forEach((collapseNode) => {
const toggleButton = collapseNode.querySelector('.ibexa-collapse__toggle-btn');
const isCollapsed = toggleButton.classList.contains('collapsed');
@@ -6,16 +18,82 @@
collapseNode.classList.toggle('ibexa-collapse--collapsed', isCollapsed);
collapseNode.dataset.collapsed = isCollapsed;
+ const multiCollapseNode = collapseNode.closest(`[data-multi-collapse-body]`);
+
collapseNode.addEventListener('hide.bs.collapse', (event) => {
event.stopPropagation();
+
collapseNode.classList.add('ibexa-collapse--collapsed');
collapseNode.dataset.collapsed = true;
});
collapseNode.addEventListener('show.bs.collapse', (event) => {
event.stopPropagation();
+
collapseNode.classList.remove('ibexa-collapse--collapsed');
collapseNode.dataset.collapsed = false;
});
+
+ if (!multiCollapseNode || !toggleAllBtns.length) {
+ return;
+ }
+
+ const currentToggleAllBtn = doc.querySelector(`[data-multi-collapse-btn-id="${multiCollapseNode.dataset.multiCollapseBody}"]`);
+ const attachClickToggleHandler = (section) => {
+ section.addEventListener('click', () => {
+ const currentCollapsibleBtns = [...multiCollapseNode.querySelectorAll('[data-bs-toggle]')];
+
+ global.clearTimeout(toggleAllTimeout);
+
+ toggleAllTimeout = global.setTimeout(() => {
+ const collapsedCount = currentCollapsibleBtns.filter((btn) => btn.classList.contains('collapsed')).length;
+ const shouldBeToggled = collapsedCount === currentCollapsibleBtns.length || collapsedCount === 0;
+
+ if (shouldBeToggled) {
+ toggleMultiCollapseBtn(currentToggleAllBtn, collapsedCount === 0);
+ }
+ }, TOGGLE_TIMEOUT);
+ });
+ };
+
+ collapseNode.querySelectorAll('[data-bs-toggle]').forEach(attachClickToggleHandler);
});
-})(window, window.document);
+
+ const handleCollapseAction = (multiCollapseNode, isExpandAction) => {
+ multiCollapseNode.querySelectorAll('.ibexa-collapse').forEach((collapseNode) => {
+ const isElementCollapsed = collapseNode.classList.contains('ibexa-collapse--collapsed');
+ const shouldBeToggled = isExpandAction === isElementCollapsed;
+
+ if (shouldBeToggled) {
+ const element = bootstrap.Collapse.getOrCreateInstance(collapseNode.querySelector('.ibexa-multi-collapse__single-item'));
+
+ if (isExpandAction) {
+ element.show();
+ } else {
+ element.hide();
+ }
+ }
+ });
+ };
+ const attachAllElementsToggler = (btn) => {
+ btn.addEventListener('click', () => {
+ const collapseId = btn.dataset.multiCollapseBtnId;
+
+ if (!collapseId) {
+ return;
+ }
+
+ const multiCollapseBodyNode = doc.querySelector(`[data-multi-collapse-body="${collapseId}"]`);
+
+ global.clearTimeout(toggleAllTimeout);
+
+ toggleAllTimeout = global.setTimeout(() => {
+ const isExpandingAction = btn.classList.contains('ibexa-multi-collapse__btn--expand-all-label');
+
+ handleCollapseAction(multiCollapseBodyNode, isExpandingAction);
+ toggleMultiCollapseBtn(btn, isExpandingAction);
+ }, TOGGLE_TIMEOUT);
+ });
+ };
+ toggleAllBtns.forEach(attachAllElementsToggler);
+})(window, window.document, window.bootstrap, window.Translator);
diff --git a/src/bundle/Resources/public/scss/_anchor-navigation.scss b/src/bundle/Resources/public/scss/_anchor-navigation.scss
index 2d06541482..a2325f0e6d 100644
--- a/src/bundle/Resources/public/scss/_anchor-navigation.scss
+++ b/src/bundle/Resources/public/scss/_anchor-navigation.scss
@@ -18,6 +18,10 @@
&:last-child {
border-bottom: none;
}
+
+ &--no-border {
+ border-bottom: none;
+ }
}
&__section-group {
diff --git a/src/bundle/Resources/public/scss/_multi-collapse.scss b/src/bundle/Resources/public/scss/_multi-collapse.scss
new file mode 100644
index 0000000000..bf49d0c4b1
--- /dev/null
+++ b/src/bundle/Resources/public/scss/_multi-collapse.scss
@@ -0,0 +1,32 @@
+.ibexa-multi-collapse {
+ &__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ &__content {
+ width: 100%;
+ margin: calculateRem(16px) 0;
+ }
+
+ &__input {
+ margin-top: calculateRem(16px);
+ }
+
+ &__group {
+ .ibexa-collapse {
+ &__header {
+ display: flex;
+ border-bottom: calculateRem(1px) solid $ibexa-color-light;
+ }
+
+ &__toggle-btn:not(.ibexa-collapse__toggle-btn--status) {
+ font-size: $ibexa-text-font-size-large;
+ font-weight: bold;
+ margin-right: auto;
+ padding-left: 0;
+ }
+ }
+ }
+}
diff --git a/src/bundle/Resources/public/scss/ibexa.scss b/src/bundle/Resources/public/scss/ibexa.scss
index 7a5e84f112..bb74981f5f 100644
--- a/src/bundle/Resources/public/scss/ibexa.scss
+++ b/src/bundle/Resources/public/scss/ibexa.scss
@@ -102,6 +102,7 @@
@import 'autosave';
@import 'side-menu';
@import 'collapse';
+@import 'multi-collapse';
@import 'tag-view-select';
@import 'grid-view';
@import 'grid-view-item';
diff --git a/src/bundle/Resources/translations/ibexa_collapse.en.xliff b/src/bundle/Resources/translations/ibexa_collapse.en.xliff
new file mode 100644
index 0000000000..96aa765a96
--- /dev/null
+++ b/src/bundle/Resources/translations/ibexa_collapse.en.xliff
@@ -0,0 +1,21 @@
+
+