PageSourceSearch

https://www.guiarepsol.com/etc.clientlibs/repsol-guia/components/c…-v2.min.3415661772957dbfe772a4aa6dee5ff8.js

js guiarepsol.com collected 2026-10-02 04:19:24 UTC 7,477 bytes, 232 lines download raw bytes

1// This class encapsulates the functionality of the header submenu component
2// It handles initialization, item capitalization, active states, and slick carousel behavior.
3// It also manages the visibility of navigation buttons based on the width of the submenu items.
4class SubMenu {
5	/**
6	 * Initializes the SubMenu instance with the provided DOM component.
7	 * @param {HTMLElement} component - The root element of the submenu component.
8	 */
9	constructor(component) {
10		this.component = component;
11		this.listPage = this.component.querySelector('.list-page');
12		this.blockPages = this.component.querySelector('.block-pages');
13		this.init();
14	}
15
16	/**
17	 * Initializes all the core functionality of the submenu.
18	 * Sets up the submenu layout, styling, active states, and slick carousel.
19	 */
20	init() {
21		this.loadComponent();
22		this.itemSectionToUpper();
23		this.itemSubsectionsActive();
24		this.displaying();
25		this.calculateWidthToScroll();
26
27		// Recalculate layout on window resize
28		window.addEventListener('resize', () => {
29			this.calculateWidthToScroll();
30		});
31	}
32
33	/**
34	 * Capitalizes the first letter of each principal-item link text.
35	 */
36	itemSectionToUpper() {
37		const links = this.component.querySelectorAll('.principal-item a');
38		links.forEach(link => {
39			const text = link.textContent.trim();
40			if (text.length > 0) {
41				const capitalized = text.charAt(0).toUpperCase() + text.slice(1);
42				link.textContent = capitalized;
43			}
44		});
45	}
46
47	/**
48	 * Highlights the active submenu item based on the current page URL.
49	 * Adds 'subitem-active' class and disables the link.
50	 */
51	itemSubsectionsActive() {
52		const currentPath = window.location.pathname.replace(/\.html$/, "").replace(/\/$/, "");
53		const links = this.component.querySelectorAll('.list-page .item.rp-body-16');
54
55		links.forEach(link => {
56			const titleUrl = link.dataset.titleurl;
57			if (titleUrl) {
58				const normalized = titleUrl.replace(/\.html$/, "").replace(/\/$/, "");
59				// Activate link if it matches current path
60				if (normalized === currentPath) {
61					link.classList.add('subitem-active');
62					link.setAttribute('href', '#'); // prevent navigation since it's the current page
63				}
64			}
65		});
66	}
67
68	/**
69	 * Hides the entire submenu component if there are no submenu items.
70	 */
71	displaying() {
72		const items = this.component.querySelectorAll('.item');
73		// No items to display, hide the component completely
74		if (items.length <= 0) {
75			this.component.style.display = 'none';
76		}
77	}
78
79	/**
80	 * Calculates and sets the minimum width for the submenu based on item widths.
81	 * Also handles the visibility of navigation buttons.
82	 */
83	loadComponent() {
84		const items = this.component.querySelectorAll('.item');
85		if (items.length <= 0) { return; }
86		let widthItems = 0;
87
88		// Force a large minWidth temporarily to avoid layout issues during calculation
89		if (window.innerWidth > 1023) {
90			this.listPage.style.minWidth = '10000px';
91		}
92
93		this.listPage.classList.add('load');
94
95		// Sum width of all items including spacing
96		items.forEach(item => {
97			widthItems += Math.ceil(item.getBoundingClientRect().width + 16);
98		});
99
100		// Set the actual width after calculating all items
101		if (window.innerWidth > 1023) {
102			this.listPage.style.minWidth = `${widthItems}px`;
103		}
104
105		// Reset transform for fresh start
106		this.listPage.style.transform = 'translateX(0)';
107		this.listPage.dataset.currentTab = 0;
108
109		const widthContainer = this.blockPages.getBoundingClientRect().width;
110		const showNext = widthContainer < widthItems;
111
112		// Update navigation buttons visibility
113		this.setButton(false, showNext);
114	}
115
116	/**
117	 * Toggles the visibility state of the previous and next navigation buttons.
118	 * @param {boolean} showPrev - Whether to show the previous button.
119	 * @param {boolean} showNext - Whether to show the next button.
120	 */
121	setButton(showPrev, showNext) {
122		const btnPrev = this.component.querySelector('.tab-prev');
123		const btnNext = this.component.querySelector('.tab-next');
124
125		if (btnPrev) btnPrev.classList.toggle('btn-disabled', !showPrev);
126		if (btnNext) btnNext.classList.toggle('btn-disabled', !showNext);
127	}
128
129	/**
130	 * Calculates the total width of the submenu items and decides when to hide/show navigation buttons.
131	 * Adjusts button visibility based on the container width.
132	 */
133	calculateWidthToScroll() {
134		setTimeout(() => {
135			if (!this.blockPages) { return; } // Exit if blockPages is not found
136			const items = this.component.querySelectorAll('.list-page a.item');
137			const buttons = this.blockPages.querySelectorAll('button[type="button"]');
138			const containerWidth = this.blockPages.getBoundingClientRect().width;
139
140			// Calculate total width of items including margins
141			const totalWidth = Array.from(items).reduce((sum, el) => sum + el.getBoundingClientRect().width + 24, 0);
142
143			if (window.innerWidth < 640) {
144				buttons.forEach(btn => btn.style.display = 'none');
145			} else {
146				buttons.forEach(btn => btn.style.display = 'block');
147			}
148
149			if (totalWidth < containerWidth - 30) {
150				// If items fit in container, hide arrows
151				buttons.forEach(btn => btn.classList.add('slick-hidden'));
152			} else {
153				// Otherwise, show at least the next button
154				this.component.querySelector('.tab-prev')?.classList.add('slick-hidden');
155				this.component.querySelector('.tab-next')?.classList.remove('slick-hidden');
156			}
157
158			if (totalWidth > containerWidth) {
159				this.horizontalScrollSub();
160			} else {
161				buttons.forEach(btn => btn.style.display = 'none');
162			}
163
164		}, 100);
165	}
166
167	/**
168	 * Initializes Slick Carousel on the submenu list and handles slide navigation behavior.
169	 * Also manages the visibility of next/previous buttons on slide change.
170	 */
171	horizontalScrollSub() {
172		const $listPage = $(this.listPage);
173
174		if (!$listPage.hasClass('slick-initialized')) {
175			// Initialize slick carousel
176			$listPage.slick({
177				dots: false,
178				infinite: false,
179				speed: 300,
180				swipeToSlide: true,
181				touchMove: true,
182				slidesToShow: 1,
183				slidesToScroll: 1,
184				centerMode: false,
185				variableWidth: true,
186				cssEase: 'linear',
187				prevArrow: $(this.component).find('.tab-prev.icon-rp-Arrow_left'),
188				nextArrow: $(this.component).find('.tab-next.icon-rp-Arrow_right')
189			});
190
191			// Handle visibility of buttons after slide change
192			$listPage.on('afterChange', (event, slick, currentSlide) => {
193				const itemMax = slick.slideCount - 1;
194				let itemToHide = itemMax - 4;
195
196				if( itemToHide === -1 ) {
197					itemToHide = itemMax - 1;
198				}
199
200				const btnPrev = $(this.component).find('.tab-prev.icon-rp-Arrow_left');
201				const btnNext = $(this.component).find('.tab-next.icon-rp-Arrow_right');
202
203				// Hide next button near the end
204				if (currentSlide >= itemToHide) {
205					btnNext.addClass('d-none');
206					btnPrev.removeClass('d-none');
207
208				} else if (currentSlide < 1) {
209					// Hide previous button at the start
210					btnPrev.addClass('d-none');
211
212				} else {
213					// Show both buttons in the middle slides
214					btnPrev.removeClass('d-none');
215					btnNext.removeClass('d-none');
216				}
217			});
218
219			// Start with prev button hidden
220			$(this.component).find('.tab-prev.icon-rp-Arrow_left').addClass('d-none');
221		}
222	}
223}
224
225document.addEventListener('DOMContentLoaded', () => {
226	const subMenuComponents = document.querySelectorAll('.submenu-component .submenu-guia-component');
227	// No submenu components found, exit early
228	if( subMenuComponents.length === 0 ) { return; }
229	subMenuComponents.forEach(subMenuComponent => {
230		new SubMenu(subMenuComponent);
231	});
232});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.