Skip to content

Commit

Permalink
IBX-3654: Left menu and sections in edit form cleanup (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabowskiM authored Sep 16, 2022
1 parent e4db151 commit 671e34d
Show file tree
Hide file tree
Showing 21 changed files with 359 additions and 416 deletions.
1 change: 0 additions & 1 deletion src/bundle/Resources/encore/ibexa.js.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const layout = [
path.resolve(__dirname, '../public/js/scripts/autogenerate.identifier.js'),
path.resolve(__dirname, '../public/js/scripts/admin.back.to.top.js'),
path.resolve(__dirname, '../public/js/scripts/admin.middle.ellipsis.js'),
path.resolve(__dirname, '../public/js/scripts/admin.anchor.sections.navigation'),
path.resolve(__dirname, '../public/js/scripts/widgets/flatpickr.js'),
];
const fieldTypes = [];
Expand Down
247 changes: 199 additions & 48 deletions src/bundle/Resources/public/js/scripts/admin.anchor.navigation.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,223 @@
(function (global, doc) {
if (doc.querySelector('.ibexa-navigation-menu')) {
(function (global, doc, ibexa) {
const navigationMenu = doc.querySelector('.ibexa-anchor-navigation-menu');

if (!navigationMenu) {
return;
}

const EDIT_CONTENT_TOP_PADDING = 42;
const header = doc.querySelector('.ibexa-edit-header');
const headerContainer = header.querySelector('.ibexa-edit-header__container');
const SECTION_ADJUST_MARGIN_TOP = 20;
const formContainerNode = doc.querySelector('.ibexa-edit-content');
const allSections = [...doc.querySelectorAll('.ibexa-anchor-navigation-sections__section, .ibexa-edit-content__secondary-section')];
const isVerticalScrollVisible = () => {
const { scrollHeight, offsetHeight } = formContainerNode;
const getSectionGroupActiveItems = () => {
const sectionGroupNode = formContainerNode.querySelector('.ibexa-anchor-navigation__section-group') ?? formContainerNode;
const sections = sectionGroupNode.querySelectorAll('.ibexa-anchor-navigation__section');

return [...sections];
};
let currentlyVisibleSections = getSectionGroupActiveItems();
const attachSectionGroupsMenuListEvents = () => {
const items = doc.querySelectorAll(
'.ibexa-anchor-navigation-menu__section-groups--list .ibexa-anchor-navigation-menu__section-groups-item',
);

return scrollHeight > offsetHeight;
items.forEach((item) => item.addEventListener('click', onSelectSectionGroupsMenuList, false));
};
const removeStartingHashChar = (sectionId) => {
if (sectionId && sectionId[0] === '#') {
return sectionId.slice(1);
const attachSectionGroupsMenuDropdownEvents = () => {
const sourceSelect = doc.querySelector(
'.ibexa-anchor-navigation-menu__section-groups--dropdown .ibexa-dropdown__source .ibexa-input',
);

if (!sourceSelect) {
return;
}

return sectionId;
sourceSelect.addEventListener('change', onSelectSectionGroupsMenuDropdown, false);
};
const showSection = (sectionId) => {
doc.querySelectorAll('.ibexa-anchor-navigation-menu__item-btn').forEach((btn) => {
const { anchorTargetSectionId } = btn.dataset;
const onSelectSectionGroupsMenuList = (event) => {
const { targetId } = event.currentTarget.dataset;
const sectionsMenuNode = doc.querySelector(`.ibexa-anchor-navigation-menu__sections[data-id="${targetId}"]`);
const sectionGroupsMenuItems = doc.querySelectorAll(
'.ibexa-anchor-navigation-menu__section-groups--list .ibexa-anchor-navigation-menu__section-groups-item',
);

btn.classList.toggle(
'ibexa-anchor-navigation-menu__item-btn--active',
removeStartingHashChar(anchorTargetSectionId) === removeStartingHashChar(sectionId),
);
sectionGroupsMenuItems.forEach((item) => {
item.classList.toggle('ibexa-anchor-navigation-menu__section-groups-item--active', item.isSameNode(event.currentTarget));
});
showSectionGroup(targetId);
showSectionsMenu(sectionsMenuNode);
};
const navigateTo = (event) => {
const { anchorTargetSectionId } = event.currentTarget.dataset;
const targetSection = [
...doc.querySelectorAll('.ibexa-anchor-navigation-sections__section, .ibexa-edit-content__secondary-section'),
].find((section) => {
const sectionId = section.dataset.id || section.dataset.anchorSectionId;
const onSelectSectionGroupsMenuDropdown = (event) => {
const targetId = event.currentTarget.value;
const sectionsMenuNode = doc.querySelector(`.ibexa-anchor-navigation-menu__sections[data-id="${targetId}"]`);

return removeStartingHashChar(sectionId) === removeStartingHashChar(anchorTargetSectionId);
showSectionGroup(targetId);
showSectionsMenu(sectionsMenuNode);
};
const showSectionsMenu = (node) => {
const items = doc.querySelectorAll('.ibexa-anchor-navigation-menu__sections');

items.forEach((item) => item.classList.toggle('ibexa-anchor-navigation-menu__sections--active', item.isSameNode(node)));
};
const showSectionGroup = (id) => {
const sectionGroupItems = formContainerNode.querySelectorAll('.ibexa-anchor-navigation__section-group');

sectionGroupItems.forEach((item) => {
item.classList.toggle('ibexa-anchor-navigation__section-group--active', item.dataset.id === id);
});

if (isVerticalScrollVisible()) {
formContainerNode.scrollTo({
top: targetSection.offsetTop + EDIT_CONTENT_TOP_PADDING,
behavior: 'smooth',
});
} else {
showSection(anchorTargetSectionId);
currentlyVisibleSections = getSectionGroupActiveItems();

fitSections();
};
const attachSectionsMenuEvents = () => {
const items = doc.querySelectorAll('.ibexa-anchor-navigation-menu .ibexa-anchor-navigation-menu__sections-item-btn');

items.forEach((item) => item.addEventListener('click', onSelectSectionsMenu, false));
};
const onSelectSectionsMenu = (event) => {
const { targetId } = event.currentTarget.dataset;

navigateTo(targetId);
};
const navigateTo = (targetId) => {
const sectionNode = formContainerNode.querySelector(`.ibexa-anchor-navigation__section[data-id="${targetId}"]`);

formContainerNode.scrollTo({
top: sectionNode.offsetTop,
behavior: 'smooth',
});
};
const getFirstSection = (sectionGroup) => {
return sectionGroup.querySelector('.ibexa-anchor-navigation__section');
};
const getLastSection = (sectionGroup) => {
const sections = [...sectionGroup.querySelectorAll('.ibexa-anchor-navigation__section')];

return sections[sections.length - 1];
};
const fitSections = () => {
const sectionGroup =
formContainerNode.querySelector('.ibexa-anchor-navigation__section-group--active') ??
formContainerNode.querySelector('.ibexa-anchor-navigation-sections');

if (!sectionGroup) {
return;
}

const contentColumn = doc.querySelector('.ibexa-main-container__content-column');
const firstSection = getFirstSection(sectionGroup);
const lastSection = getLastSection(sectionGroup);

if (!firstSection) {
return;
}

const contentContainer = lastSection.closest('.ibexa-edit-content__container');

contentContainer.style.paddingBottom = '0px';

if (!firstSection.isSameNode(lastSection) && lastSection.offsetHeight) {
const heightFromLastSection = contentContainer.offsetHeight + contentContainer.offsetTop - lastSection.offsetTop;
const contentColumnBodyHeight = contentColumn.offsetHeight - headerContainer.offsetHeight;
const heightDiff = contentColumnBodyHeight - heightFromLastSection;

if (heightDiff > 0) {
contentContainer.style.paddingBottom = `${heightDiff}px`;
}
}
};
const attachScrollContainerEvents = () => {
const allSections = [...formContainerNode.querySelectorAll('.ibexa-anchor-navigation__section')];
let previousFirstVisibleSection = null;

if (formContainerNode && allSections.length) {
formContainerNode.addEventListener('scroll', () => {
let firstVisibleSection = currentlyVisibleSections.find((section) => {
const { top, height } = section.getBoundingClientRect();
const headerBottomContainerHeight = header.offsetHeight - headerContainer.offsetHeight;

doc.querySelectorAll('.ibexa-anchor-navigation-menu__item-btn').forEach((btn) => {
btn.addEventListener('click', navigateTo, false);
});
return top + height >= headerContainer.offsetHeight + headerBottomContainerHeight + SECTION_ADJUST_MARGIN_TOP;
});

if (formContainerNode && allSections.length) {
formContainerNode.addEventListener('scroll', () => {
const position = formContainerNode.scrollTop;
const activeSection = allSections.find((section) => {
const start = section.offsetTop;
const end = section.offsetHeight + section.offsetTop;
if (!firstVisibleSection) {
firstVisibleSection = currentlyVisibleSections.at(-1);
}

return position >= start && position < end;
if (previousFirstVisibleSection === firstVisibleSection) {
return;
}

previousFirstVisibleSection = firstVisibleSection;

const targetId = firstVisibleSection.dataset.id;
const secondaryMenuNode = doc.querySelector(
`.ibexa-anchor-navigation-menu__sections--active .ibexa-anchor-navigation-menu__sections-item-btn[data-target-id="${targetId}"]`,
);

setActiveSecondaryMenu(secondaryMenuNode);
});
}
};
const setActiveSecondaryMenu = (node) => {
const secondaryMenuItems = doc.querySelectorAll(
'.ibexa-anchor-navigation-menu__sections--active .ibexa-anchor-navigation-menu__sections-item-btn',
);

if (activeSection) {
const activeSectionId = activeSection.dataset.id ?? activeSection.dataset.anchorSectionId;
secondaryMenuItems.forEach((item) => {
item.classList.toggle('ibexa-anchor-navigation-menu__sections-item-btn--active', item.isSameNode(node));
});
};
const attachListenForIsInvalidClass = () => {
const classChangedCallback = (mutationList) => {
mutationList.forEach((mutation) => {
const { oldValue, target } = mutation;
const hadIsInvalidClass = oldValue.includes('.is-invalid');
const hasIsInvalidClass = target.classList.contains('is-invalid');

showSection(activeSectionId);
}
if (hadIsInvalidClass !== hasIsInvalidClass) {
const sectionGroup = target.closest('.ibexa-anchor-navigation__section-group');

if (!sectionGroup) {
return;
}

const { id } = sectionGroup.dataset;
const hasGroupError = !!sectionGroup.querySelector('.is-invalid');
const correspondingMenuItem =
doc.querySelector(`.ibexa-anchor-navigation-menu__section-groups-item[data-target-id="${id}"]`) ??
doc.querySelector(`.ibexa-anchor-navigation-menu .ibexa-dropdown__item[data-value="${id}"]`);
const errorIconNode = correspondingMenuItem.querySelector('.ibexa-anchor-navigation-menu__item-error');
const dropdownWidget = doc.querySelector('.ibexa-anchor-navigation-menu .ibexa-dropdown');

errorIconNode.classList.toggle('ibexa-anchor-navigation-menu__item-error--hidden', !hasGroupError);

if (dropdownWidget) {
const hasError = !!dropdownWidget.querySelector(
'.ibexa-anchor-navigation-menu__item-error:not(ibexa-anchor-navigation-menu__item-error--hidden)',
);
const errorDropdownContainer = doc.querySelector('.ibexa-anchor-navigation-menu__error');

errorDropdownContainer.classList.toggle('ibexa-anchor-navigation-menu__error--hidden', !hasError);
}
}
});
};
const observer = new MutationObserver(classChangedCallback);

observer.observe(formContainerNode, {
subtree: true,
attributes: true,
attributeFilter: ['class'],
attributeOldValue: true,
});
}
})(window, window.document);
};

attachSectionGroupsMenuListEvents();
attachSectionGroupsMenuDropdownEvents();
attachSectionsMenuEvents();
attachScrollContainerEvents();
attachListenForIsInvalidClass();
fitSections();
ibexa.helpers.tooltips.parse(navigationMenu);
})(window, window.document, window.ibexa);
Loading

0 comments on commit 671e34d

Please sign in to comment.