PageSourceSearch

https://weinportugalshop.de/modules/sedestral/views/js/sedestral_v201.js

js weinportugalshop.de collected 2026-10-04 02:15:06 UTC 12,104 bytes, 302 lines download raw bytes

1/*
2* 2025 Sedestral
3*
4* NOTICE OF LICENSE
5*
6* This source file is subject to the Academic Free License (AFL 3.0)
7* that is bundled with this package in the file LICENSE.txt.
8* It is also available through the world-wide-web at this URL:
9* http://opensource.org/licenses/afl-3.0.php
10* If you did not receive a copy of the license and are unable to
11* obtain it through the world-wide-web, please send an email
12* to [email protected] so we can send you a copy immediately.
13*
14* DISCLAIMER
15*
16* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
17* versions in the future. If you wish to customize PrestaShop for your
18* needs please refer to http://www.prestashop.com for more information.
19*
20* @author    Sedestral <[email protected]>
21* @copyright 2025 Sedestral
22* @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
23* International Registered Trademark & Property of Sedestral
24*
25*/
26document.addEventListener('DOMContentLoaded', () => {
27    try {
28        const activeLink = document.querySelector('.sedestral.blog-menu .active');
29        if (activeLink) {
30            activeLink.scrollIntoView({
31                behavior: 'smooth',
32                block: 'center'
33            });
34        }
35        document.querySelectorAll('.sedestral.blog-menu a').forEach(link => {
36            link.addEventListener('click', () => {
37                link.scrollIntoView({
38                    behavior: 'smooth',
39                    block: 'center'
40                });
41            });
42        });
43    } catch (e) {
44        console.error('Error in Sedestral script:', e);
45    }
46
47    try {
48        const HEADER_OFFSET = 80;
49        const TOP_ZONE = 0.25;
50
51        const links = Array.from(document.querySelectorAll('.sedestral.toc-list a'));
52        const sections = links
53            .map(l => document.querySelector(l.getAttribute('href')))
54            .filter(Boolean);
55
56        if (links.length > 0 && sections.length > 0) {
57            let pending = null;
58
59            const bottomMargin = Math.round((1 - TOP_ZONE) * 100);
60            const rootMarginValue = '-' + HEADER_OFFSET + 'px 0px -' + bottomMargin + '% 0px';
61
62            const observer = new IntersectionObserver(entries => {
63                entries.forEach(entry => {
64                    if (pending && entry.target !== pending) return;
65                    if (!entry.isIntersecting) return;
66
67                    const top = entry.boundingClientRect.top;
68                    if (top < HEADER_OFFSET) return;
69                    if (top > window.innerHeight * TOP_ZONE) return;
70
71                    links.forEach(l => l.parentElement.classList.remove('active'));
72                    const idx = sections.indexOf(entry.target);
73                    if (idx > -1) links[idx].parentElement.classList.add('active');
74
75                    if (pending && entry.target === pending) {
76                        pending = null;
77                    }
78                });
79            }, {
80                rootMargin: rootMarginValue,
81                threshold: 0
82            });
83
84            sections.forEach(s => observer.observe(s));
85
86            links.forEach(link => {
87                link.addEventListener('click', e => {
88                    e.preventDefault();
89
90                    const target = document.querySelector(link.getAttribute('href'));
91                    if (!target) return;
92
93                    pending = target;
94                    links.forEach(l => l.parentElement.classList.remove('active'));
95                    link.parentElement.classList.add('active');
96
97                    const y = target.getBoundingClientRect().top + window.pageYOffset - HEADER_OFFSET;
98                    window.scrollTo({ top: y, behavior: 'smooth' });
99                });
100            });
101        }
102    } catch (e) {
103        console.error('Error in Sedestral script:', e);
104    }
105
106    try {
107        document.querySelectorAll('.sedestral.faq-question').forEach(btn => {
108            btn.addEventListener('click', () => {
109                const item = btn.parentElement;
110                const open = item.classList.toggle('open');
111
112                document.querySelectorAll('.sedestral.faq-item.open').forEach(i => {
113                    if (i !== item) i.classList.remove('open');
114                });
115
116                btn.setAttribute('aria-expanded', open ? 'true' : 'false');
117            });
118
119            const wrapper = btn.nextElementSibling;
120            const id = 'faq-' + Math.random().toString(36).substr(2,5);
121            wrapper.id = id;
122            btn.setAttribute('aria-controls', id);
123            btn.setAttribute('aria-expanded', 'false');
124        });
125    } catch (e) {
126        console.error('Error in Sedestral script:', e);
127    }
128
129    // Category description collapse (See more / See less)
130    try {
131        if (typeof sedestralCategoryCollapse !== 'undefined' && sedestralCategoryCollapse.enabled) {
132            var maxHeight = sedestralCategoryCollapse.maxHeight || 150;
133            var seeMoreText = sedestralCategoryCollapse.seeMoreText || 'See more';
134            var seeLessText = sedestralCategoryCollapse.seeLessText || 'See less';
135
136            function applyCollapse(categoryDesc) {
137                var originalHeight = categoryDesc.scrollHeight;
138                if (originalHeight <= maxHeight + 30) return;
139
140                var wrapper = document.createElement('div');
141                wrapper.className = 'sedestral see-more-wrapper';
142
143                var contentWrapper = document.createElement('div');
144                contentWrapper.className = 'sedestral see-more-content collapsed';
145                contentWrapper.style.maxHeight = maxHeight + 'px';
146
147                categoryDesc.parentNode.insertBefore(wrapper, categoryDesc);
148                contentWrapper.appendChild(categoryDesc);
149                wrapper.appendChild(contentWrapper);
150
151                var toggleBtn = document.createElement('button');
152                toggleBtn.type = 'button';
153                toggleBtn.className = 'sedestral see-more-toggle';
154                toggleBtn.textContent = seeMoreText;
155                wrapper.appendChild(toggleBtn);
156
157                var isExpanded = false;
158                toggleBtn.addEventListener('click', function() {
159                    isExpanded = !isExpanded;
160
161                    if (isExpanded) {
162                        contentWrapper.classList.remove('collapsed');
163                        contentWrapper.style.maxHeight = originalHeight + 'px';
164                        contentWrapper.style.overflow = 'visible';
165                        toggleBtn.textContent = seeLessText;
166                        setTimeout(function() {
167                            if (isExpanded) {
168                                contentWrapper.style.maxHeight = 'none';
169                            }
170                        }, 450);
171                    } else {
172                        contentWrapper.style.maxHeight = contentWrapper.scrollHeight + 'px';
173                        contentWrapper.style.overflow = 'hidden';
174                        contentWrapper.offsetHeight;
175                        contentWrapper.classList.add('collapsed');
176                        contentWrapper.style.maxHeight = maxHeight + 'px';
177                        toggleBtn.textContent = seeMoreText;
178
179                        var wrapperTop = wrapper.getBoundingClientRect().top + window.pageYOffset - 100;
180                        if (window.pageYOffset > wrapperTop) {
181                            window.scrollTo({ top: wrapperTop, behavior: 'smooth' });
182                        }
183                    }
184                });
185            }
186
187            // Main category description (compatible with PS 1.6 to 9.x and most themes)
188            var selectors = [
189                '#category-description',
190                '#category_description',
191                '.category-description',
192                '.cat_desc',
193                '.block-category .category-description',
194                '[data-category-description]',
195                '.category-top-column .category-description',
196                '#center_column .category-description',
197                '#main .category-description'
198            ];
199
200            var categoryDesc = null;
201            for (var i = 0; i < selectors.length; i++) {
202                categoryDesc = document.querySelector(selectors[i]);
203                if (categoryDesc && categoryDesc.textContent.trim().length > 0) {
204                    break;
205                }
206                categoryDesc = null;
207            }
208
209            if (categoryDesc) {
210                applyCollapse(categoryDesc);
211            }
212
213            // Additional category description (opt-in, bottom SEO block)
214            if (sedestralCategoryCollapse.additionalEnabled) {
215                document.querySelectorAll('.category-additional-description').forEach(function(el) {
216                    if (el === categoryDesc) return;
217                    if (el.textContent.trim().length === 0) return;
218                    applyCollapse(el);
219                });
220            }
221        }
222    } catch (e) {
223        console.error('Error in Sedestral category collapse:', e);
224    }
225
226    // Products carousel - responsive
227    try {
228        document.querySelectorAll('.sedestral.products-carousel').forEach(carousel => {
229            const wrapper = carousel.querySelector('.sedestral.products-wrapper');
230            const track = carousel.querySelector('.sedestral.products-track');
231            const items = carousel.querySelectorAll('.sedestral.product-item');
232            const prevBtn = carousel.querySelector('.sedestral.carousel-prev');
233            const nextBtn = carousel.querySelector('.sedestral.carousel-next');
234
235            if (items.length === 0 || !wrapper) return;
236
237            let currentIndex = 0;
238            const gap = 16;
239
240            function getPerView() {
241                var wrapperWidth = wrapper.offsetWidth;
242                var itemWidth = items[0].offsetWidth;
243                if (itemWidth === 0) return 4;
244                return Math.max(1, Math.floor((wrapperWidth + gap) / (itemWidth + gap)));
245            }
246
247            function updateCarousel() {
248                var perView = getPerView();
249                var maxIndex = Math.max(0, items.length - perView);
250
251                if (currentIndex > maxIndex) {
252                    currentIndex = maxIndex;
253                }
254
255                var itemWidth = items[0].offsetWidth;
256                var offset = currentIndex * (itemWidth + gap);
257                track.style.transform = 'translateX(-' + offset + 'px)';
258
259                prevBtn.disabled = currentIndex === 0;
260                nextBtn.disabled = currentIndex >= maxIndex;
261                prevBtn.style.opacity = currentIndex === 0 ? '0.5' : '1';
262                nextBtn.style.opacity = currentIndex >= maxIndex ? '0.5' : '1';
263
264                // Hide buttons if all items visible
265                if (items.length <= perView) {
266                    prevBtn.style.display = 'none';
267                    nextBtn.style.display = 'none';
268                } else {
269                    prevBtn.style.display = '';
270                    nextBtn.style.display = '';
271                }
272            }
273
274            prevBtn.addEventListener('click', function() {
275                if (currentIndex > 0) {
276                    currentIndex--;
277                    updateCarousel();
278                }
279            });
280
281            nextBtn.addEventListener('click', function() {
282                var perView = getPerView();
283                var maxIndex = Math.max(0, items.length - perView);
284                if (currentIndex < maxIndex) {
285                    currentIndex++;
286                    updateCarousel();
287                }
288            });
289
290            updateCarousel();
291
292            // Update on resize
293            var resizeTimeout;
294            window.addEventListener('resize', function() {
295                clearTimeout(resizeTimeout);
296                resizeTimeout = setTimeout(updateCarousel, 100);
297            });
298        });
299    } catch (e) {
300        console.error('Error in Sedestral products carousel:', e);
301    }
302});

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.