PageSourceSearch

https://scaladays.org/wp-content/plugins/programmme-sync/assets/js/programmesync_frontend.js

js scaladays.org collected 2026-10-02 10:06:16 UTC 8,848 bytes, 225 lines download raw bytes

1// Filter panels open as a modal dialog, so they stay usable after scrolling.
2// Shared by the generic .ps-toggle-filters wiring below and the [programme]
3// shortcode's own toolbar script.
4window.psFilterModal = (function() {
5    let backdrop = null;
6    let activePanel = null;
7    let activeButton = null;
8
9    function ensureCloseButton(panel) {
10        const header = panel.querySelector('.filter-header');
11        if (!header || header.querySelector('.ps-modal-close')) {
12            return;
13        }
14        const button = document.createElement('button');
15        button.type = 'button';
16        button.className = 'ps-modal-close';
17        button.setAttribute('aria-label', 'Close');
18        button.innerHTML = '×';
19        button.addEventListener('click', close);
20        header.appendChild(button);
21    }
22
23    function onKeydown(event) {
24        if (event.key === 'Escape') {
25            close();
26        }
27    }
28
29    function open(panel, button) {
30        close();
31        activePanel = panel;
32        activeButton = button || null;
33        ensureCloseButton(panel);
34        backdrop = document.createElement('div');
35        backdrop.className = 'ps-modal-backdrop';
36        backdrop.addEventListener('click', close);
37        document.body.appendChild(backdrop);
38        panel.removeAttribute('hidden');
39        panel.classList.add('ps-modal-open');
40        panel.setAttribute('role', 'dialog');
41        panel.setAttribute('aria-modal', 'true');
42        document.body.classList.add('ps-modal-active');
43        document.addEventListener('keydown', onKeydown);
44        if (activeButton) {
45            activeButton.setAttribute('aria-expanded', 'true');
46        }
47    }
48
49    function close() {
50        if (!activePanel) {
51            return;
52        }
53        activePanel.classList.remove('ps-modal-open');
54        activePanel.setAttribute('hidden', '');
55        activePanel.removeAttribute('role');
56        activePanel.removeAttribute('aria-modal');
57        if (activeButton) {
58            activeButton.setAttribute('aria-expanded', 'false');
59        }
60        if (backdrop) {
61            backdrop.remove();
62            backdrop = null;
63        }
64        document.body.classList.remove('ps-modal-active');
65        document.removeEventListener('keydown', onKeydown);
66        activePanel = null;
67        activeButton = null;
68    }
69
70    function toggle(panel, button) {
71        if (activePanel === panel) {
72            close();
73        } else {
74            open(panel, button);
75        }
76    }
77
78    return { open: open, close: close, toggle: toggle };
79})();
80
81document.addEventListener('DOMContentLoaded', function() {
82    const ytCheckers = document.querySelectorAll('.yt-checker');
83    ytCheckers.forEach(function(checker) {
84        checker.addEventListener('click', function() {
85            const youtubeLink = checker.getAttribute('data-youtube-link');
86            if (youtubeLink) {
87                const iframe = document.createElement('iframe');
88                iframe.setAttribute('src', youtubeLink.replace('watch?v=', 'embed/'));
89                iframe.setAttribute('frameborder', '0');
90                iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture');
91                iframe.setAttribute('allowfullscreen', 'true');
92                iframe.style.width = '100%';
93                iframe.style.height = '100%';
94                checker.innerHTML = '';
95                checker.appendChild(iframe);
96                checker.style.position = 'relative';
97                checker.style.paddingBottom = '56.25%';
98                checker.style.height = '0';
99                iframe.style.position = 'absolute';
100                iframe.style.top = '0';
101                iframe.style.left = '0';
102                iframe.style.width = '100%';
103                iframe.style.height = '100%';
104            }
105        });
106    }); 
107
108    // Search functionality for session list
109    const sessionSearchInput = document.getElementById('session-search-input');
110    if (sessionSearchInput) {
111        sessionSearchInput.addEventListener('input', function() {
112            const searchQuery = this.value.toLowerCase();
113            const sessions = document.querySelectorAll('.session-item');
114
115            sessions.forEach(function(session) {
116                const title = session.querySelector('h3').innerText.toLowerCase();
117                const speakers = session.querySelector('.session-speakers') ? session.querySelector('.session-speakers').innerText.toLowerCase() : '';
118                const room = session.querySelector('.session-room') ? session.querySelector('.session-room').innerText.toLowerCase() : '';
119                const excerpt = session.querySelector('.session-excerpt') ? session.querySelector('.session-excerpt').innerText.toLowerCase() : '';
120
121                if (title.includes(searchQuery) || speakers.includes(searchQuery) || room.includes(searchQuery) || excerpt.includes(searchQuery)) {
122                    session.style.display = 'block';
123                } else {
124                    session.style.display = 'none';
125                }
126            });
127        });
128    }
129
130    // Search functionality for speaker list
131    const speakerSearchInput = document.getElementById('speaker-search-input');
132    if (speakerSearchInput) {
133        speakerSearchInput.addEventListener('input', function() {
134            const searchQuery = this.value.toLowerCase();
135            const speakers = document.querySelectorAll('.speaker-item');
136
137            speakers.forEach(function(speaker) {
138                const name = speaker.querySelector('h2').innerText.toLowerCase();
139
140                if (name.includes(searchQuery)) {
141                    speaker.style.display = 'block';
142                } else {
143                    speaker.style.display = 'none';
144                }
145            });
146        });
147    }
148
149    // Search functionality for organisation list
150    const orgSearchInput = document.getElementById('organisation-search-input');
151    if (orgSearchInput) {
152        orgSearchInput.addEventListener('input', function() {
153            const searchQuery = this.value.toLowerCase();
154            const orgs = document.querySelectorAll('.organisation-item');
155
156            orgs.forEach(function(org) {
157                const name = org.querySelector('h2').innerText.toLowerCase();
158
159                if (name.includes(searchQuery)) {
160                    org.style.display = '';
161                } else {
162                    org.style.display = 'none';
163                }
164            });
165        });
166    }
167
168    // Standalone favorite hearts (single session view): same localStorage
169    // list as the schedule views, announced with the same event.
170    document.querySelectorAll('.ps-favorite-standalone').forEach(function(star) {
171        const sessionId = star.getAttribute('data-session-id');
172        if (!sessionId) {
173            return;
174        }
175        function readLiked() {
176            try {
177                return new Set(JSON.parse(localStorage.getItem('likedSessions') || '[]'));
178            } catch (e) {
179                return new Set();
180            }
181        }
182        function render(liked) {
183            const isLiked = liked.has(sessionId);
184            star.classList.toggle('favorited', isLiked);
185            const title = star.getAttribute(isLiked ? 'data-title-remove' : 'data-title-add');
186            if (title) {
187                star.title = title;
188            }
189        }
190        render(readLiked());
191        star.addEventListener('click', function(event) {
192            event.preventDefault();
193            const liked = readLiked();
194            if (liked.has(sessionId)) {
195                liked.delete(sessionId);
196            } else {
197                liked.add(sessionId);
198            }
199            try {
200                localStorage.setItem('likedSessions', JSON.stringify(Array.from(liked)));
201            } catch (e) {
202                return;
203            }
204            render(liked);
205            star.dispatchEvent(new CustomEvent('programmesyncLikedChanged', { bubbles: true }));
206        });
207    });
208
209    // Collapsible filter panels: a .ps-toggle-filters button in a .ps-toolbar
210    // opens/closes the next .filter-container sibling of that toolbar.
211    // (The [programme] shortcode wires its own toggle and is not affected.)
212    document.querySelectorAll('.ps-toggle-filters').forEach(function(button) {
213        const toolbar = button.closest('.ps-toolbar');
214        let panel = toolbar ? toolbar.nextElementSibling : null;
215        while (panel && !(panel.classList && panel.classList.contains('filter-container'))) {
216            panel = panel.nextElementSibling;
217        }
218        if (!panel) {
219            return;
220        }
221        button.addEventListener('click', function() {
222            window.psFilterModal.toggle(panel, button);
223        });
224    });
225});

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.