PageSourceSearch

https://w4u.in/assets/ai-assistant/bw-content-slider.js?v=1790323539

js w4u.in collected 2026-10-01 15:55:41 UTC 15,446 bytes, 430 lines download raw bytes

1/**
2 * BigWelt content sliders — scroll-snap carousels with prev/next arrows.
3 * Uses document-level delegation so arrows keep working after page reload / editor save
4 * (saved HTML must not rely on data-bw-slider-init alone).
5 */
6(function (global) {
7    'use strict';
8
9    function isEditorMode() {
10        if (global.BW_IS_CONTENTBOX_EDITOR || global.BW_IS_AIBOX_EDITOR) {
11            return true;
12        }
13        if (global.BwIsContentboxEditor) {
14            return global.BwIsContentboxEditor();
15        }
16        if (global.BwContentboxClickfix && typeof global.BwContentboxClickfix.isEditorMode === 'function') {
17            return global.BwContentboxClickfix.isEditorMode();
18        }
19        if (document.body && document.body.classList.contains('bw-page-editor')) {
20            return true;
21        }
22        return false;
23    }
24
25    function qsa(sel, root) {
26        return Array.prototype.slice.call((root || document).querySelectorAll(sel));
27    }
28
29    function qs(sel, root) {
30        return (root || document).querySelector(sel);
31    }
32
33    function findTrack(wrap) {
34        if (!wrap) {
35            return null;
36        }
37        return qs('.bw-content-slider-track', wrap)
38            || qs('#imageSlider', wrap)
39            || qs('[data-bw-slider-track]', wrap)
40            || qsa('[style*="scroll-snap"]', wrap).filter(function (el) {
41                return el.children && el.children.length > 0;
42            })[0];
43    }
44
45    function findWrap(el) {
46        if (!el || !el.closest) {
47            return null;
48        }
49        return el.closest('.bw-content-slider-wrap, #sliderContainer, [data-bw-slider]');
50    }
51
52    function findWrapFromTrack(track) {
53        if (!track || !track.parentElement) {
54            return null;
55        }
56        var p = track.parentElement;
57        if (p.id === 'sliderContainer' || p.classList.contains('bw-content-slider-wrap') || p.getAttribute('data-bw-slider')) {
58            return p;
59        }
60        return findWrap(track);
61    }
62
63    function isInsideSlider(el) {
64        return !!(el && el.closest && el.closest('.bw-content-slider-wrap, #sliderContainer, [data-bw-slider]'));
65    }
66
67    function isPrevButton(btn) {
68        if (!btn || !isInsideSlider(btn)) {
69            return false;
70        }
71        if (btn.classList.contains('bw-slider-prev') || btn.getAttribute('data-bw-slider-prev') !== null) {
72            return true;
73        }
74        /* Only chevron/angle icons — fa-arrow-* is used on page CTAs and must not hijack clicks */
75        return !!qs('.fa-chevron-left, .fa-angle-left', btn);
76    }
77
78    function isNextButton(btn) {
79        if (!btn || !isInsideSlider(btn)) {
80            return false;
81        }
82        if (btn.classList.contains('bw-slider-next') || btn.getAttribute('data-bw-slider-next') !== null) {
83            return true;
84        }
85        return !!qs('.fa-chevron-right, .fa-angle-right', btn);
86    }
87
88    function resolveArrowButton(target) {
89        if (!target || !target.closest) {
90            return null;
91        }
92        var wrap = findWrap(target);
93        if (!wrap) {
94            return null;
95        }
96        var btn = target.closest('.bw-slider-prev, .bw-slider-next, [data-bw-slider-prev], [data-bw-slider-next]');
97        if (btn && wrap.contains(btn)) {
98            return btn;
99        }
100        var icon = target.closest('.fa-chevron-left, .fa-chevron-right, .fa-angle-left, .fa-angle-right');
101        if (icon) {
102            btn = icon.closest('button, a, [role="button"]');
103            if (btn && wrap.contains(btn)) {
104                return btn;
105            }
106        }
107        return null;
108    }
109
110    function clickIsOnArrowButton(target, btn) {
111        if (!target || !btn) {
112            return false;
113        }
114        return target === btn || (btn.contains && btn.contains(target));
115    }
116
117    function labelArrowButtons(wrap) {
118        var prev = qs('.bw-slider-prev', wrap);
119        var next = qs('.bw-slider-next', wrap);
120        qsa('button, a, [role="button"]', wrap).forEach(function (btn) {
121            if (!prev && isPrevButton(btn)) {
122                prev = btn;
123                btn.classList.add('bw-slider-prev');
124            }
125            if (!next && isNextButton(btn)) {
126                next = btn;
127                btn.classList.add('bw-slider-next');
128            }
129        });
130        return { prev: prev, next: next };
131    }
132
133    function hideDots(wrap) {
134        wrap.classList.add('bw-slider-no-dots');
135        qsa('.bw-slider-dots, .slick-dots, ul.slick-dots, .slider-dots, [class*="slider-
135dots"]', wrap).forEach(function (el) {
136            el.style.display = 'none';
137        });
138    }
139
140    function slideStep(track) {
141        if (!track) {
142            return 300;
143        }
144        var slide = track.querySelector(':scope > *') || track.children[0];
145        if (!slide) {
146            return track.clientWidth || 300;
147        }
148        var w = slide.getBoundingClientRect().width;
149        if (w > 0) {
150            return w;
151        }
152        var style = window.getComputedStyle(slide);
153        var flex = style.flex || style.flexBasis || '';
154        if (flex.indexOf('100%') !== -1 || (slide.style.flex && slide.style.flex.indexOf('100%') !== -1)) {
155            return track.clientWidth || 300;
156        }
157        return track.clientWidth || slide.offsetWidth || 300;
158    }
159
160    function scrollTrack(track, direction) {
161        if (!track) {
162            return;
163        }
164        var step = slideStep(track);
165        var delta = direction < 0 ? -step : step;
166        var target = track.scrollLeft + delta;
167        if (typeof track.scrollTo === 'function') {
168            try {
169                track.scrollTo({ left: target, behavior: 'smooth' });
170                return;
171            } catch (err) {
172                /* fall through */
173            }
174        }
175        track.scrollLeft = target;
176    }
177
178    function handleArrowActivate(e) {
179        if (isEditorMode()) {
180            return;
181        }
182        var btn = resolveArrowButton(e.target);
183        if (!btn || !clickIsOnArrowButton(e.target, btn)) {
184            return;
185        }
186        var wrap = findWrap(btn);
187        if (!wrap) {
188            return;
189        }
190        var track = findTrack(wrap);
191        if (!track) {
192            return;
193        }
194        var prev = isPrevButton(btn);
195        var next = isNextButton(btn);
196        if (!prev && !next) {
197            return;
198        }
199
200        e.preventDefault();
201        e.stopPropagation();
202        if (typeof e.stopImmediatePropagation === 'function') {
203            e.stopImmediatePropagation();
204        }
205
206        scrollTrack(track, prev ? -1 : 1);
207    }
208
209    function collectWraps(root) {
210        root = root || document;
211        var seen = [];
212        var add = function (el) {
213            if (!el || seen.indexOf(el) !== -1) {
214                return;
215            }
216            // Tracks/slides must not be treated as wraps (LLM sometimes duplicates classes).
217            if (el.classList && (el.classList.contains('bw-content-slider-track') || el.classList.contains('bw-slide'))) {
218                return;
219            }
220            seen.push(el);
221        };
222
223        qsa('#sliderContainer, .bw-content-slider-wrap, [data-bw-slider]', root).forEach(add);
224        qsa('#imageSlider, .bw-content-slider-track', root).forEach(function (track) {
225            add(findWrapFromTrack(track));
226        });
227
228        return seen;
229    }
230
231    function normalizeSlider(wrap) {
232        if (!wrap) {
233            return;
234        }
235        // Repair class pollution before wiring.
236        if (wrap.classList.contains('bw-content-slider-track')) {
237            wrap.classList.remove('bw-content-slider-track');
238        }
239        wrap.removeAttribute('data-bw-slider-init');
240        wrap.classList.add('bw-content-slider-wrap');
241
242        var track = findTrack(wrap);
243        if (!track) {
244            return;
245        }
246        track.classList.add('bw-content-slider-track');
247        track.classList.remove('bw-content-slider-wrap', 'bw-slider-no-dots', 'bw-slide');
248        track.removeAttribute('data-bw-slider');
249        track.removeAttribute('data-bw-hide-dots');
250
251        if (!track.style.overflowX) {
252            track.style.overflowX = 'auto';
253        }
254        if (!track.style.display) {
255            track.style.display = 'flex';
256        }
257        if (!track.style.scrollSnapType) {
258            track.style.scrollSnapType = 'x mandatory';
259        }
260        if (!track.style.scrollBehavior) {
261            track.style.scrollBehavior = 'smooth';
262        }
263
264        Array.prototype.slice.call(track.children).forEach(function (slide) {
265            if (!slide || slide.nodeType !== 1) {
266                return;
267            }
268            if (slide.classList.contains('bw-slider-prev') || slide.classList.contains('bw-slider-next')) {
269                // Arrows must never live inside the flex track (they become full-width white bars).
270                wrap.appendChild(slide);
271                return;
272            }
273            slide.classList.remove('bw-content-slider-wrap', 'bw-content-slider-track', 'bw-slider-no-dots');
274            slide.classList.add('bw-slide');
275            slide.removeAttribute('data-bw-slider');
276            if (!slide.style.flex) {
277                slide.style.flex = '0 0 100%';
278            }
279            if (!slide.style.minWidth) {
280                slide.style.minWidth = '100%';
281            }
282            if (!slide.style.scrollSnapAlign) {
283                slide.style.scrollSnapAlign = 'start';
284            }
285            if (!slide.style.boxSizing) {
286                slide.style.boxSizing = 'border-box';
287            }
288        });
289
290        // Deduplicate arrows — keep one prev and one next (prefer styled).
291        var prevAll = qsa('.bw-slider-prev, [data-bw-slider-prev]', wrap);
292        var nextAll = qsa('.bw-slider-next, [data-bw-slider-next]', wrap);
293        qsa('button, a, [role="button"]', wrap).forEach(function (btn) {
294            if (isPrevButton(btn) && prevAll.indexOf(btn) === -1) {
295                prevAll.push(btn);
296            }
297            if (isNextButton(btn) && nextAll.indexOf(btn) === -1) {
298                nextAll.push(btn);
299            }
300        });
301        function scoreArrow(btn) {
302            var s = (btn.getAttribute('style') || '');
303            var n = 0;
304            if (/background/i.test(s)) n += 2;
305            if (/rgba|#/i.test(s)) n += 2;
306            if (/width/i.test(s)) n += 1;
307            return n;
308        }
309        function keepBest(list, cls) {
310            if (!list.length) return null;
311            list.sort(function (a, b) { return scoreArrow(b) - scoreArrow(a); });
312            var keep = list[0];
313            list.slice(1).forEach(function (el) {
314                if (el && el.parentNode) el.parentNode.removeChild(el);
315            });
316            keep.classList.add(cls);
317            if (keep.parentNode !== wrap) {
318                wrap.appendChild(keep);
319            }
320            return keep;
321        }
322        var arrows = {
323            prev: keepBest(prevAll, 'bw-slider-prev'),
324            next: keepBest(nextAll, 'bw-slider-next')
325        };
326        if (!arrows.prev || !arrows.next) {
327            var labeled = labelArrowButtons(wrap);
328            if (!arrows.prev) arrows.prev = labeled.prev;
329            if (!arrows.next) arrows.next = labeled.next;
330        }
331        if (arrows.prev) {
332            arrows.prev.setAttribute('type', 'button');
333            arrows.prev.setAttribute('aria-label', 'Previous slide');
334            arrows.prev.style.pointerEvents = 'auto';
335            arrows.prev.style.setProperty('position', 'absolute', 'important');
336            arrows.prev.style.setProperty('top', '50%', 'important');
337            arrows.prev.style.setProperty('bottom', 'auto', 'important');
338            arrows.prev.style.setProperty('left', '16px', 'important');
339            arrows.prev.style.setProperty('right', 'auto', 'important');
340            arrows.prev.style.setProperty('transform', 'translateY(-50%)', 'important');
341            arrows.prev.style.setProperty('z-index', '30', 'important');
342            arrows.prev.style.setProperty('float', 'none', 'important');
343            arrows.prev.style.setProperty('margin', '0', 'important');
344            arrows.prev.style.setProperty('flex', '0 0 auto', 'important');
345            arrows.prev.style.setProperty('min-width', '44px', 'important');
346            arrows.prev.style.setProperty('max-width', '64px', 'important');
347        }
348        if (arrows.next) {
349            arrows.next.setAttribute('type', 'button');
350            arrows.next.setAttribute('aria-label', 'Next slide');
351            arrows.next.style.pointerEvents = 'auto';
352            arrows.next.style.setProperty('position', 'absolute', 'important');
353            arrows.next.style.setProperty('top', '50%', 'important');
354            arrows.next.style.setProperty('bottom', 'auto', 'important');
355            arrows.next.style.setProperty('right', '16px', 'important');
356            arrows.next.style.setProperty('left', 'auto', 'important');
357            arrows.next.style.setProperty('transform', 'translateY(-50%)', 'important');
358            arrows.next.style.setProperty('z-index', '30', 'important');
359            arrows.next.style.setProperty('float', 'none', 'important');
360            arrows.next.style.setProperty('margin', '0', 'important');
361            arrows.next.style.setProperty('flex', '0 0 auto', 'important');
362            arrows.next.style.setProperty('min-width', '44px', 'important');
363            arrows.next.style.setProperty('max-width', '64px', 'important');
364        }
365
366        if (wrap.getAttribute('data-bw-hide-dots') === '1' || wrap.classList.contains('bw-slider-no-dots')) {
367            hideDots(wrap);
368        }
369    }
370
371    function scan(root) {
372        collectWraps(root).forEach(normalizeSlider);
373    }
374
375    var arrowDocs = typeof WeakSet !== 'undefined' ? new WeakSet() : null;
376    var arrowBoundLegacy = false;
377
378    function bindArrowDelegation(doc) {
379        doc = doc || document;
380        if (arrowDocs) {
381            if (arrowDocs.has(doc)) {
382                return;
383            }
384            arrowDocs.add(doc);
385        } else if (doc === document) {
386            if (arrowBoundLegacy) {
387                return;
388            }
389            arrowBoundLegacy = true;
390        }
391        doc.addEventListener('click', handleArrowActivate, true);
392    }
393
394    function boot(root) {
395        root = root || document;
396        var doc = (root.nodeType === 9) ? root : (root.ownerDocument || document);
397        var scope = (root.nodeType === 9) ? (root.body || root) : root;
398        bindArrowDelegation(doc);
399        scan(scope);
400        if (typeof MutationObserver === 'undefined' || !scope) {
401            return;
402        }
403        var t = null;
404        var obs = new MutationObserver(function () {
405            if (t) {
406                clearTimeout(t);
407            }
408            t = setTimeout(function () {
409                scan(scope);
410            }, 120);
411        });
412        obs.observe(scope, { childList: true, subtree: true });
413    }
414
415    bindArrowDelegation(document);
416
417    if (document.readyState === 'loading') {
418        document.addEventListener('DOMContentLoaded', function () { boot
418(document); });
419    } else {
420        boot(document);
421    }
422
423    global.BwContentSlider = {
424        scan: scan,
425        init: normalizeSlider,
426        boot: boot,
427        scrollTrack: scrollTrack,
428        findTrack: findTrack
429    };
430})(typeof window !== 'undefined' ? window : this);

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.