Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-3456 Collapse all button support #1394

Open
wants to merge 17 commits into
base: 4.6
Choose a base branch
from
141 changes: 139 additions & 2 deletions src/bundle/Resources/public/js/scripts/core/collapse.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,123 @@
(function (global, doc) {
(function (global, doc, bootstrap) {
let toggleAllTimeout;
const MULTI_COLLAPSE_BTN_TAG = 'data-multi-collapse-btn-id';
bozatko marked this conversation as resolved.
Show resolved Hide resolved
const COLLAPSE_SECTION_BODY_TAG = 'data-multi-collapse-body';
const MULTI_COLLAPSE_ELEMENT_SELECTOR = '.ibexa-multicollapse--item';
const toggleAllBtns = doc.querySelectorAll(`[${MULTI_COLLAPSE_BTN_TAG}]`);
bozatko marked this conversation as resolved.
Show resolved Hide resolved
const multiCollapsBodies = doc.querySelectorAll(`[${COLLAPSE_SECTION_BODY_TAG}]`);

const initializeClickedStateArray = () => {
bozatko marked this conversation as resolved.
Show resolved Hide resolved
const initToggleState = [];

if (toggleAllBtns.length === 0) return [];

Array.from(toggleAllBtns).forEach((collapseBtn) => {
const tagValue = collapseBtn.getAttribute(MULTI_COLLAPSE_BTN_TAG);
let existingEntry = initToggleState.find((obj) => obj.btnName === tagValue);

if (!existingEntry) {
existingEntry = { btnName: tagValue, collapsedElements: [] };
initToggleState.push(existingEntry);
}
});

return initToggleState;
};
const clickedElementsState = initializeClickedStateArray();
const toggleMultiCollapseButton = (btn, changeToCollapseAll) => {
const expandAll = btn.querySelector('.ibexa-multi-collapse__toggler-expand');
const collapseAll = btn.querySelector('.ibexa-multi-collapse__toggler-collapse');

if (changeToCollapseAll && collapseAll.classList.contains('d-none')) {
collapseAll.classList.toggle('d-none');
expandAll.classList.toggle('d-none');
} else if (!changeToCollapseAll && expandAll.classList.contains('d-none')) {
collapseAll.classList.toggle('d-none');
expandAll.classList.toggle('d-none');
bozatko marked this conversation as resolved.
Show resolved Hide resolved
}
};
const toggleMultiCollapseIfNeeded = (multiCollapseNode, toggleBtn, tabllLength) => {
const allElements = multiCollapseNode.querySelectorAll(MULTI_COLLAPSE_ELEMENT_SELECTOR);

if (tabllLength === allElements.length || tabllLength === 0) {
toggleMultiCollapseButton(toggleBtn, tabllLength === 0);
}
};
const handleCollapseAction = (multiCollapseNode, expandAction) => {
const index = clickedElementsState.findIndex(
(element) => element.btnName === multiCollapseNode.getAttribute(COLLAPSE_SECTION_BODY_TAG),
);

if (expandAction) {
clickedElementsState[index].collapsedElements = [];
}

multiCollapseNode.querySelectorAll('.ibexa-collapse').forEach((collapseNode) => {
const isElementCollapsed = collapseNode.classList.contains('ibexa-collapse--collapsed');

if (expandAction === isElementCollapsed) {
bootstrap.Collapse.getOrCreateInstance(collapseNode.querySelector(MULTI_COLLAPSE_ELEMENT_SELECTOR)).toggle();

if (!expandAction) {
const uniqueName = collapseNode.querySelector('.ibexa-collapse__toggle-btn').getAttribute('data-bs-target');
clickedElementsState[index].collapsedElements.push(uniqueName);
}
}
});
};

doc.querySelectorAll('.ibexa-collapse').forEach((collapseNode) => {
const toggleButton = collapseNode.querySelector('.ibexa-collapse__toggle-btn');
const isCollapsed = toggleButton.classList.contains('collapsed');

collapseNode.classList.toggle('ibexa-collapse--collapsed', isCollapsed);
collapseNode.dataset.collapsed = isCollapsed;

if (toggleAllBtns && toggleAllBtns.length > 0) {
const multicollapseNode = collapseNode.closest(`[${COLLAPSE_SECTION_BODY_TAG}]`);
bozatko marked this conversation as resolved.
Show resolved Hide resolved

if (!!multicollapseNode) {
const uniqueName = toggleButton.getAttribute('data-bs-target');
const currentToggleAllButton = Array.from(toggleAllBtns).find(
(button) => button.getAttribute(MULTI_COLLAPSE_BTN_TAG) === multicollapseNode.getAttribute(COLLAPSE_SECTION_BODY_TAG),
);

bozatko marked this conversation as resolved.
Show resolved Hide resolved
collapseNode.querySelector('.ibexa-collapse__toggle-btn--status').addEventListener('click', (event) => {
event.stopPropagation();

const collapseSectionIndex = clickedElementsState.findIndex(
(collapseSection) => collapseSection.btnName === currentToggleAllButton.getAttribute(MULTI_COLLAPSE_BTN_TAG),
bozatko marked this conversation as resolved.
Show resolved Hide resolved
);
const toggleIndex = clickedElementsState[collapseSectionIndex].collapsedElements.findIndex(
(element) => element === uniqueName,
);

window.clearTimeout(toggleAllTimeout);

toggleAllTimeout = window.setTimeout(() => {
if (toggleIndex !== -1) {
clickedElementsState[collapseSectionIndex].collapsedElements.splice(toggleIndex, 1);

toggleMultiCollapseIfNeeded(
multicollapseNode,
currentToggleAllButton,
clickedElementsState[collapseSectionIndex].collapsedElements.length,
);

return;
}
clickedElementsState[collapseSectionIndex].collapsedElements.push(uniqueName);

toggleMultiCollapseIfNeeded(
multicollapseNode,
currentToggleAllButton,
clickedElementsState[collapseSectionIndex].collapsedElements.length,
);
}, 200);
});
}
}

collapseNode.addEventListener('hide.bs.collapse', (event) => {
event.stopPropagation();
collapseNode.classList.add('ibexa-collapse--collapsed');
Expand All @@ -18,4 +130,29 @@
collapseNode.dataset.collapsed = false;
});
});
})(window, window.document);

if (toggleAllBtns) {
toggleAllBtns.forEach((btn) => {
bozatko marked this conversation as resolved.
Show resolved Hide resolved
btn.addEventListener('click', (event) => {
event.stopPropagation();
bozatko marked this conversation as resolved.
Show resolved Hide resolved

bozatko marked this conversation as resolved.
Show resolved Hide resolved
const collapseAll = btn?.querySelector('.ibexa-multi-collapse__toggler-collapse');
const collapseSelector = btn.getAttribute(MULTI_COLLAPSE_BTN_TAG);
bozatko marked this conversation as resolved.
Show resolved Hide resolved
if (!!collapseSelector) {
const multiCollapseNode = Array.from(multiCollapsBodies).find(
(node) => node.getAttribute(COLLAPSE_SECTION_BODY_TAG) === collapseSelector,
);

window.clearTimeout(toggleAllTimeout);

toggleAllTimeout = window.setTimeout(() => {
const isExpandingAction = collapseAll.classList.contains('d-none');

handleCollapseAction(multiCollapseNode, isExpandingAction);
toggleMultiCollapseButton(btn, isExpandingAction);
}, 200);
}
});
});
}
})(window, window.document, window.bootstrap);
4 changes: 4 additions & 0 deletions src/bundle/Resources/public/scss/_anchor-navigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
&:last-child {
border-bottom: none;
}

&--no-border {
border-bottom: none;
}
}

&__section-group {
Expand Down
37 changes: 37 additions & 0 deletions src/bundle/Resources/public/scss/_multi-collapse.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.ibexa-multi-collapse {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved styles from product-catalog. Based on previous review comment let me know if I still should change class name to ibexa-pc-...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if those styles are moved from PC where will be a base twig template for a multi-collapse feature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed: There is no base twig template due to its too general purpose

&__toggler-expand,
&__toggler-collapse {
pointer-events: none;
}

&__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;
}
}
}
}
1 change: 1 addition & 0 deletions src/bundle/Resources/public/scss/ibexa.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Loading