csdsolutions-csdjs
Version:
Libreria per i progetti di CSD Solutions
589 lines (486 loc) • 19.2 kB
JavaScript
// Utility Functions
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Segment Component
function initializeSegment(element) {
const $element = $CSD(element);
const $buttons = $element.find('.csd-segment-button');
const $indicator = $element.find('.csd-segment-indicator');
const containerStyle = window.getComputedStyle(element);
const segmentPadding = parseFloat(containerStyle.paddingLeft);
function updateIndicatorPosition(selectedButton) {
if (!selectedButton || !$indicator.length) return;
const containerRect = element.getBoundingClientRect();
const $buttonElements = $element.find('.csd-segment-button');
const buttonElements = $buttonElements.elements;
const isFirstButton = buttonElements[0] === selectedButton;
const isLastButton = buttonElements[buttonElements.length - 1] === selectedButton;
$buttonElements.removeClass('before-checked');
const selectedIndex = buttonElements.indexOf(selectedButton);
if (!isFirstButton && selectedIndex > 0) {
$CSD(buttonElements[selectedIndex - 1]).addClass('before-checked');
}
const buttonWidth = selectedButton.getBoundingClientRect().width;
let translateX = 0;
for (let i = 0; i < selectedIndex; i++) {
translateX += buttonElements[i].getBoundingClientRect().width;
}
if (isFirstButton) {
translateX = 0;
} else if (isLastButton) {
translateX = containerRect.width - buttonWidth - (segmentPadding * 2);
} else {
translateX += segmentPadding;
}
requestAnimationFrame(() => {
$indicator[0].style.width = `${buttonWidth}px`;
$indicator[0].style.transform = `translateX(${translateX}px)`;
});
}
function updateIndicator(selectedButton) {
updateIndicatorPosition(selectedButton);
const $icons = $CSD(selectedButton).find('ion-icon');
if ($icons.length > 0) {
setTimeout(() => {
updateIndicatorPosition(selectedButton);
setTimeout(() => updateIndicatorPosition(selectedButton), 300);
}, 50);
}
}
function selectButton(selectedButton) {
if ($CSD(selectedButton).hasClass('active')) return;
$buttons.removeClass('active');
$CSD(selectedButton).addClass('active');
updateIndicator(selectedButton);
const contentId = $CSD(selectedButton).attr('content-id');
if (contentId) {
// Nascondi tutti i contenuti
// Mostra il contenuto corrispondente
const targetContent = document.getElementById(contentId);
if (targetContent) {
const segmentContents = targetContent.closest('.csd-segment-contents');
segmentContents.querySelector('.csd-segment-content.active')?.classList.remove('active');
targetContent.classList.add('active');
}
}
element.dispatchEvent(new CustomEvent('segment-change', {
detail: {
value: $CSD(selectedButton).attr('value'),
contentId: contentId
}
}));
}
const $activeButton = $element.find('.csd-segment-button.active');
if ($activeButton.length) {
updateIndicator($activeButton[0]);
}
$buttons.each(button => {
$CSD(button).on('click', () => {
if (!$CSD(button).prop('disabled')) {
selectButton(button);
}
});
});
const debouncedResize = debounce(() => {
const $activeButton = $element.find('.csd-segment-button.active');
if ($activeButton.length) {
updateIndicator($activeButton[0]);
}
}, 100);
window.addEventListener('resize', debouncedResize);
}
// Tab Component
function initializeTab(element) {
const $element = $CSD(element);
const $tabs = $element.find('.csd-tab');
const $panels = $element.find('.csd-tab-panel');
const $indicator = $element.find('.csd-tab-indicator');
const $tabList = $element.find('.csd-tab-list');
function updateIndicatorPosition(selectedTab) {
if (!selectedTab || !$indicator.length) return;
const tabRect = selectedTab.getBoundingClientRect();
const listRect = $tabList[0].getBoundingClientRect();
const translateX = tabRect.left - listRect.left;
requestAnimationFrame(() => {
$indicator
.css('width', `${tabRect.width}px`)
.css('transform', `translateX(${translateX}px)`);
});
}
function selectTab(selectedTab, index) {
const $selectedTab = $CSD(selectedTab);
if ($selectedTab.hasClass('active')) return;
$tabs.removeClass('active');
$selectedTab.addClass('active');
$panels.each((panelIndex, panel) => {
$CSD(panel).toggleClass('active', panelIndex === index);
});
updateIndicatorPosition(selectedTab);
}
$tabs.each((tab) => {
$CSD(tab).on('click', () => {
const index = $CSD(tab).index();
selectTab(tab, index);
});
});
const $activeTab = $element.find('.csd-tab.active');
if ($activeTab.length) {
updateIndicatorPosition($activeTab[0]);
}
const debouncedResize = debounce(() => {
const $activeTab = $element.find('.csd-tab.active');
if ($activeTab.length) {
updateIndicatorPosition($activeTab[0]);
}
}, 100);
$CSD(window).on('resize', debouncedResize);
}
// Menu Component
function initializeMenu(element) {
const $element = $CSD(element);
const $menuItems = $element.find('.csd-menu-item');
const $subMenuItems = $element.find('.has-submenu');
$menuItems.on('click', function() {
const $this = $CSD(this);
if (!$this.hasClass('has-submenu')) {
$menuItems.removeClass('active');
$this.addClass('active');
}
});
$subMenuItems.on('click', function(e) {
e.preventDefault();
$CSD(this).toggleClass('expanded');
});
}
// Toolbar Component
function initializeToolbar(element) {
// Aggiungi qui la logica specifica per la toolbar se necessaria
}
function initializeDropdown(element) {
if (!element) return;
const $element = $CSD(element);
const $toggle = $element.find('.csd-dropdown-toggle');
const $menu = $element.find('.csd-dropdown-menu, .csd-mega-menu');
if (!$toggle.length || !$menu.length) return;
const isMegaMenu = $menu.hasClass('csd-mega-menu');
$toggle.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
const $openMenus = $CSD('.csd-dropdown-menu.show, .csd-mega-menu.show');
$openMenus.each(function() {
const $openMenu = $CSD(this);
if (!$openMenu.is($menu)) {
$openMenu.removeClass('show')
.closest('.csd-dropdown')
.find('.csd-dropdown-toggle')
.removeClass('active');
}
});
$menu.toggleClass('show');
$toggle.toggleClass('active');
if (isMegaMenu) {
const $menuBar = $element.closest('.csd-menubar');
if ($menuBar.length) {
const dropdownRect = element.getBoundingClientRect();
const menuRect = $menu[0].getBoundingClientRect();
const viewportWidth = window.innerWidth;
const leftOffset = Math.max(0, dropdownRect.left - ((menuRect.width - dropdownRect.width) / 2));
const rightEdge = leftOffset + menuRect.width;
const finalLeftOffset = rightEdge > viewportWidth ? viewportWidth - menuRect.width : leftOffset;
$menu.css('left', `${-finalLeftOffset}px`);
}
}
});
$menu.on('click', function(e) {
e.stopPropagation();
});
}
// Close dropdowns when clicking outside
$CSD(document).on('click', function(e) {
const $target = $CSD(e.target);
if (!$target.closest('.csd-dropdown').length) {
const $openMenus = $CSD('.csd-dropdown-menu.show, .csd-mega-menu.show');
$openMenus.each(function() {
$CSD(this)
.removeClass('show')
.closest('.csd-dropdown')
.find('.csd-dropdown-toggle')
.removeClass('active');
});
}
});
function initializeSubmenu(element) {
if (!element) return;
const $element = $CSD(element);
const $toggle = $element.find('> a');
if (!$toggle.length) return;
$toggle.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
const $parent = $CSD(this).closest('.has-submenu').parent();
if ($parent.length) {
$parent.find('.has-submenu.open').not($element).removeClass('open');
}
$element.toggleClass('open');
});
const $submenuItems = $element.find('.csd-sidebar-submenu .csd-sidebar-item > a');
$submenuItems.on('click', function(e) {
const $this = $CSD(this);
const href = $this.attr('href');
if (!href || href === '#') {
e.preventDefault();
}
e.stopPropagation();
});
}
function initializeNavigation(element) {
// Initialize navigation
}
function closeAllDropdowns() {
$CSD('.csd-dropdown-menu.show, .csd-mega-menu.show').each(function() {
$CSD(this)
.removeClass('show')
.closest('.csd-dropdown')
.find('.csd-dropdown-toggle')
.removeClass('active');
});
}
function closeAllSubmenus() {
$CSD('.has-submenu.open').removeClass('open');
}
// Initialize Sidebar Toggle
function initializeSidebar() {
const $sidebarToggle = $CSD('#sidebarToggle');
const $sidebar = $CSD('.csd-sidebar');
const $sidebarOverlay = $CSD('#sidebarOverlay');
const $sidebarPositionSwitch = $CSD('#sidebarPosition');
const $demoContainer = $sidebar.length ? $sidebar.closest('.demo-container') : null;
if (!$sidebar.length || !$sidebarOverlay.length || !$sidebarToggle.length) return;
if ($sidebarPositionSwitch.length) {
$sidebarPositionSwitch.prop('checked', true);
$sidebarPositionSwitch.on('change', function() {
if ($CSD(this).prop('checked')) {
if ($sidebar.length && $demoContainer.length) {
$sidebar.removeClass('csd-sidebar-fixed');
$demoContainer.append($sidebar);
}
} else {
if ($sidebar.length && $demoContainer.length) {
$sidebar.addClass('csd-sidebar-fixed');
$demoContainer.parent().append($sidebar);
}
}
});
}
if ($sidebarToggle.length && $sidebar.length && $sidebarOverlay.length) {
const $toggleIcon = $sidebarToggle.find('ion-icon');
$sidebarToggle.on('click', function() {
if ($sidebar.hasClass('csd-sidebar-fixed')) {
$sidebar.toggleClass('show');
$sidebarOverlay.toggleClass('active');
} else {
$sidebar.toggleClass('active');
}
const isActive = $sidebar.hasClass('active') || $sidebar.hasClass('show');
$toggleIcon.attr('name', isActive ? 'close-outline' : 'menu-outline');
});
$sidebarOverlay.on('click', function() {
if ($sidebar.hasClass('csd-sidebar-fixed')) {
$sidebar.removeClass('show');
} else {
$sidebar.removeClass('active');
}
$sidebarOverlay.removeClass('active');
$toggleIcon.attr('name', 'menu-outline');
});
}
const $submenuItems = $CSD('.has-submenu');
$submenuItems.each(function() {
const $item = $CSD(this);
const $link = $item.find('a');
if ($link.length) {
$link.on('click', function(e) {
e.preventDefault();
$item.toggleClass('open');
});
}
});
}
function initializeStepper(element) {
if (!element) return;
const $element = $CSD(element);
const $stepper = $element.find('.csd-stepper');
if (!$stepper.length) return;
const $steps = $stepper.find('.csd-step');
const $panels = $element.find('.csd-step-panel');
const $prevBtn = $element.find('.prev-step');
const $nextBtn = $element.find('.next-step');
const isVertical = $stepper.hasClass('vertical');
function updateProgressLine($progress, index) {
const $currentIndicator = $steps.eq(index).find('.csd-step-indicator');
const $nextIndicator = $steps.eq(index + 1).find('.csd-step-indicator');
const stepperRect = $stepper[0].getBoundingClientRect();
if (isVertical) {
const currentRect = $currentIndicator[0].getBoundingClientRect();
const nextRect = $nextIndicator[0].getBoundingClientRect();
$progress.css({
'top': `${currentRect.bottom - stepperRect.top + 6}px`,
'height': `${nextRect.top - currentRect.bottom - 12}px`,
'left': `${currentRect.left - stepperRect.left + currentRect.width / 2}px`
});
} else {
const currentRect = $currentIndicator[0].getBoundingClientRect();
const nextRect = $nextIndicator[0].getBoundingClientRect();
$progress.css({
'left': `${currentRect.right - stepperRect.left + 12}px`,
'width': `${nextRect.left - currentRect.right - 24}px`,
'top': `${currentRect.top - stepperRect.top + currentRect.height / 2}px`
});
}
}
$steps.each(function(step, index) {
if (index < $steps.length - 1) {
const $progress = $CSD('<div>')
.addClass('csd-step-progress')
.attr('data-step', index + 1);
$stepper.append($progress);
updateProgressLine($progress, index);
}
});
let currentStep = 1;
const totalSteps = $steps.length;
function updateProgress() {
const $activeStep = $stepper.find('.csd-step.active');
if (!$activeStep.length) return;
const stepIndex = $activeStep.index();
$stepper.find('.csd-step-progress').each(function(progress, index) {
const $progress = $CSD(progress);
updateProgressLine($progress, index);
$progress.toggleClass('completed', index < stepIndex);
});
}
function goToStep(step) {
currentStep = step;
$steps.each(function(step, index) {
const $s = $CSD(step);
$s.toggleClass('active', index + 1 === currentStep);
$s.toggleClass('completed', index + 1 < currentStep);
});
$panels.each(function(panel, index) {
$CSD(panel).toggleClass('active', index + 1 === step);
});
if ($prevBtn.length) $prevBtn.prop('disabled', currentStep === 1);
if ($nextBtn.length) $nextBtn.prop('disabled', currentStep === totalSteps);
updateProgress();
}
$steps.each(function(step, index) {
const $indicator = $CSD(step).find('.csd-step-indicator');
if ($indicator.length) {
$indicator.on('click', () => goToStep(index + 1));
}
});
if ($prevBtn.length) {
$prevBtn.on('click', () => {
if (currentStep > 1) goToStep(currentStep - 1);
});
}
if ($nextBtn.length) {
$nextBtn.on('click', () => {
if (currentStep < totalSteps) goToStep(currentStep + 1);
});
}
$CSD(window).on('load', () => {
goToStep(1);
$CSD(window).on('resize', updateProgress);
});
}
// Accordion Component
function initializeAccordion(element) {
if (!element) return;
const $element = $CSD(element);
const $accordionItems = $element.find('.csd-accordion-item');
const isMultiple = $element.hasClass('multiple');
$accordionItems.each(function(item) {
const $item = $CSD(item);
const $header = $item.find('.csd-accordion-header');
if ($header.length && !$header.prop('disabled')) {
$header.on('click', function() {
const $currentItem = $CSD(this).closest('.csd-accordion-item');
if (!isMultiple) {
$accordionItems.not($currentItem).removeClass('open');
}
$currentItem.toggleClass('open');
});
}
});
}
// Gestione click globale
$CSD(document).on('click', function(e) {
const $target = $CSD(e.target);
const $dropdownToggle = $target.closest('.csd-dropdown-toggle');
if ($dropdownToggle.length) {
e.preventDefault();
const $dropdown = $dropdownToggle.closest('.csd-dropdown');
const $menu = $dropdown.find('.csd-dropdown-menu');
if ($menu.hasClass('show')) {
$menu.removeClass('show');
$dropdownToggle.removeClass('active');
} else {
closeAllDropdowns();
$menu.addClass('show');
$dropdownToggle.addClass('active');
}
return;
}
const $submenuToggle = $target.closest('.has-submenu > a');
if ($submenuToggle.length) {
e.preventDefault();
const $submenuItem = $submenuToggle.parent();
if ($submenuItem.hasClass('open')) {
$submenuItem.removeClass('open');
} else {
const $siblings = $submenuItem.parent().children();
$siblings.each(function(index, sibling) {
const $sibling = $CSD(sibling);
if (!$sibling.is($submenuItem) && $sibling.hasClass('has-submenu')) {
$sibling.removeClass('open');
}
});
$submenuItem.addClass('open');
}
return;
}
if (!$target.closest('.csd-dropdown').length) {
closeAllDropdowns();
}
});
// Previeni il redirect sui link # che non sono submenu o dropdown
$CSD(document).on('click', 'a[href="#"]', function(e) {
const $target = $CSD(this);
if (!$target.closest('.has-submenu').length &&
!$target.closest('.csd-dropdown-menu').length) {
e.preventDefault();
}
});
export {
initializeDropdown,
initializeSubmenu,
initializeSidebar,
initializeStepper,
initializeAccordion,
initializeSegment,
initializeTab,
initializeMenu,
initializeToolbar,
closeAllSubmenus,
initializeNavigation
};