PageSourceSearch

https://www.trombi.com/js/public/responsive/citiesOfCountry.js?202609211111

js trombi.com collected 2026-09-24 20:39:42 UTC 6,487 bytes, 164 lines download raw bytes

1// sf-alpha.js (robust, scoped, mit Auto-Open & sanfter Animation)
2(function () {
3    function norm(v) { return (v || '').toString().trim().toUpperCase(); }
4
5    function letterFromChip(chip) {
6        return norm(chip && (chip.dataset.letter || chip.textContent));
7    }
8    function letterFromPanel(panel) {
9        if (panel && panel.dataset.letter) return norm(panel.dataset.letter);
10        var id = (panel && panel.id) || '';
11        var m = id.match(/([A-Za-zÀ-ÖØ-öø-ÿÄÖÜß])$/);
12        return m ? norm(m[1]) : '';
13    }
14
15    function focusChip(chips, idx) {
16        if (!chips.length) return;
17        var len = chips.length;
18        var i = ((idx % len) + len) % len; // wrap
19        var chip = chips[i];
20        chips.forEach(function (c, j) { c.tabIndex = (j === i ? 0 : -1); });
21        chip.focus();
22        return chip;
23    }
24
25    function initAlpha(tablist) {
26        var section = tablist.closest('section.sf-alpha') || tablist.closest('.sf-alpha');
27        var panelsRoot = section ? section.querySelector('.sf-alpha-panels') : null;
28        if (!panelsRoot) return;
29
30        var chips  = Array.prototype.slice.call(tablist.querySelectorAll('.sf-chip[role="tab"]'));
31        var panels = Array.prototype.slice.call(panelsRoot.querySelectorAll('.sf-alpha-panel[role="tabpanel"]'));
32
33        if (!chips.length || !panels.length) return;
34
35        var chipBy = Object.create(null);
36        chips.forEach(function (c) { chipBy[letterFromChip(c)] = c; });
37
38        var panelBy = Object.create(null);
39        panels.forEach(function (p) { panelBy[letterFromPanel(p)] = p; });
40
41        function updateChipStates(activeLetter) {
42            chips.forEach(function (c) {
43                var isActive = letterFromChip(c) === activeLetter;
44                c.classList.toggle('is-active', isActive);
45                c.setAttribute('aria-selected', isActive ? 'true' : 'false');
46                c.tabIndex = isActive ? 0 : -1;
47            });
48        }
49
50        function hidePanel(p) {
51            if (!p || p.hasAttribute('hidden')) return;
52            p.style.transition = 'none';
53            p.style.opacity = '0';
54            p.style.transform = 'translateY(6px)';
55            p.setAttribute('hidden', 'hidden');
56            p.style.removeProperty('transition');
57            p.style.removeProperty('opacity');
58            p.style.removeProperty('transform');
59        }
60
61        function showPanel(p) {
62            if (!p) return;
63            p.removeAttribute('hidden');    // sichtbar für Layout
64            p.style.opacity = '0';          // sanfte Animation
65            p.style.transform = 'translateY(6px)';
66            requestAnimationFrame(function () {
67                p.style.transition = 'opacity 180ms ease, transform 180ms ease';
68                p.style.opacity = '1';
69                p.style.transform = 'none';
70                setTimeout(function () {
71                    p.style.removeProperty('transition');
72                    p.style.removeProperty('opacity');
73                    p.style.removeProperty('transform');
74                }, 220);
75            });
76        }
77
78        function setActiveLetter(letter) {
79            letter = norm(letter);
80            var target = panelBy[letter];
81            if (!target) return;
82
83            updateChipStates(letter);
84
85            panels.forEach(function (p) {
86                if (p === target) {
87                    p.classList.add('is-active');
88                    showPanel(p);
89                } else {
90                    p.classList.remove('is-active');
91                    hidePanel(p);
92                }
93            });
94        }
95
96        tablist.addEventListener('click', function (e) {
97            var chip = e.target.closest('.sf-chip[role="tab"]');
98            if (!chip || !tablist.contains(chip)) return;
99            var letter = letterFromChip(chip);
100            if (panelBy[letter]) {
101                e.preventDefault();
102                setActiveLetter(letter);
103            }
104        }, true);
105
106        tablist.addEventListener('keydown', function (e) {
107            var key = e.key;
108            var current = document.activeElement && document.activeElement.closest('.sf-chip[role="tab"]');
109            if (!current || !tablist.contains(current)) return;
110
111            var idx = chips.indexOf(current);
112            var handled = false;
113
114            if (key === 'ArrowLeft') { focusChip(chips, idx - 1); handled = true; }
115            else if (key === 'ArrowRight') { focusChip(chips, idx + 1); handled = true; }
116            else if (key === 'Home') { focusChip(chips, 0); handled = true; }
117            else if (key === 'End') { focusChip(chips, chips.length - 1); handled = true; }
118            else if (key === 'Enter' || key === ' ') { setActiveLetter(letterFromChip(current)); handled = true; }
119
120            else if (key === 'Tab' && !e.shiftKey) {
121                var activePanel = panels.find(function (p) { return p.classList.contains('is-active') && !p.hasAttribute('hidden'); });
122                if (activePanel) {
123                    var firstLink = activePanel.querySelector('.sf-alpha__link, a[href], button, [tabindex]:not([tabindex="-1"])');
124                    if (firstLink) {
125                        e.preventDefault();
126                        firstLink.focus();
127                        return;
128                    }
129                }
130            }
131
132            if (handled) {
133                e.preventDefault();
134                if (key === 'ArrowLeft' || key === 'ArrowRight' || key === 'Home' || key === 'End') {
135                    var focused = document.activeElement && document.activeElement.closest('.sf-chip[role="tab"]');
136                    if (focused) setActiveLetter(letterFromChip(focused));
137                }
138            }
139        });
140
141        var initial = '';
142        if (section) {
143            initial = norm(section.getAttribute('data-selected-letter'));
144        }
145
146        if (!initial || initial === 'ALL' || !panelBy[initial]) {
147            chips.forEach(function (c, i) { c.tabIndex = (i === 0 ? 0 : -1); c.setAttribute('aria-selected', 'false'); });
148        } else {
149            setActiveLetter(initial);
150        }
151    }
152
153    function boot() {
154        var tablists = document.querySelectorAll('.sf-chip-group[role="tablist"]');
155        if (!tablists.length) return;
156        tablists.forEach(initAlpha);
157    }
158
159    if (document.readyState === 'loading') {
160        document.addEventListener('DOMContentLoaded', boot);
161    } else {
162        boot();
163    }
164})();

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.