PageSourceSearch

https://www.rarediseaseday.org/wp-content/plugins/underline-events-map/js/script.js?ver=1790239737

js rarediseaseday.org collected 2026-09-24 08:49:22 UTC 12,245 bytes, 340 lines download raw bytes

1jQuery(document).ready(function($) {
2    let map;
3    let markers = [];
4    let markerCluster;
5    let oms;
6    let infoWindow;
7    let geocoder;
8
9    let initialFilters = {};
10
11    //NEW: wait until Google Maps is actually ready (works with loading=async)
12    function runWhenMapsReady(fn, tries = 0) {
13        if (window.google && google.maps && typeof google.maps.Map === 'function') {
14            fn();
15            return;
16        }
17        if (tries > 200) return; // ~20s max (200 * 100ms)
18        setTimeout(function() {
19            runWhenMapsReady(fn, tries + 1);
20        }, 100);
21    }
22
23    function initMap() {
24        // Optional extra guard (harmless)
25        const el = document.getElementById('rdd-events-map');
26        if (!el) return;
27
28        map = new google.maps.Map(el, {
29            center: {lat: 30, lng: 0},
30            zoom: 2,
31            mapTypeControl: false
32        });
33
34        oms = new OverlappingMarkerSpiderfier(map, {
35            markersWontMove: true,
36            markersWontHide: true,
37            basicFormatEvents: true
38        });
39
40        infoWindow = new google.maps.InfoWindow();
41        geocoder = new google.maps.Geocoder();
42
43        setFiltersFromUrlParams();
44        loadEvents();
45    }
46
47    function setFiltersFromUrlParams() {
48        const urlParams = new URLSearchParams(window.location.search);
49        const country = urlParams.get('Country');
50        const eventType = urlParams.get('Type');
51        const showPastEvents = urlParams.get('Past') === 'true';
52
53        if (country) {
54            $('#filter-country').val(country);
55        }
56        if (showPastEvents) {
57            $('#show-past-events').prop('checked', true);
58        }
59
60        initialFilters = { 
61            country: country ? capitalizeWords(country) : '', 
62            eventType: eventType || '', 
63            showPastEvents: showPastEvents 
64        };
65    }
66
67    function loadEvents() {
68        $('#rdd-events-list').html('<p class="loading-message">Loading...</p>');
69
70        let selectedCountry = $('#filter-country').val() || '';
71        let selectedEventType = $('#filter-event-type').val() || '';
72        let showPastEvents = $('#show-past-events').is(':checked') || false;
73
74        if (initialFilters && (initialFilters.country || initialFilters.eventType || typeof initialFilters.showPastEvents === 'boolean')) {
75            selectedCountry = initialFilters.country || selectedCountry;
76            selectedEventType = initialFilters.eventType || selectedEventType;
77            showPastEvents = (typeof initialFilters.showPastEvents === 'boolean') ? initialFilters.showPastEvents : showPastEvents;
78            initialFilters = null;
79        }
80
81        console.log('Loading events:', { selectedCountry, selectedEventType, showPastEvents });
82
83        $.ajax({
84            url: rddEventsMapData.ajaxurl,
85            type: 'POST',
86            data: {
87                action: 'rdd_load_events',
88                nonce: rddEventsMapData.nonce,
89                country: selectedCountry,
90                event_type: selectedEventType,
91                show_past_events: showPastEvents
92            },
93            success: function(response) {
94                if (response.success) {
95                    const normalizedEvents = normalizeEventsForPastFilter(response.data.events, showPastEvents);
96
97                    clearMarkers();
98                    addMarkers(normalizedEvents);
99                    updateEventsList(normalizedEvents);
100                    updateEventTypeOptions(response.data.types, selectedEventType);
101
102                    if (selectedCountry) {
103                        zoomToCountry(selectedCountry);
104                    } else {
105                        map.setCenter({lat: 30, lng: 0});
106                        map.setZoom(2);
107                    }
108
109                    const newUrl = new URL(window.location);
110
111                    if (selectedCountry && selectedCountry !== 'undefined' && selectedCountry.trim() !== '') {
112                        newUrl.searchParams.set('Country', selectedCountry);
113                    } else {
114                        newUrl.searchParams.delete('Country');
115                    }
116
117                    if (selectedEventType && selectedEventType !== 'undefined' && selectedEventType.trim() !== '') {
118                        newUrl.searchParams.set('Type', selectedEventType);
119                    } else {
120                        newUrl.searchParams.delete('Type');
121                    }
122
123                    newUrl.searchParams.set('Past', showPastEvents);
124                    window.history.pushState({}, '', newUrl);
125                } else {
126                    $('#rdd-events-list').html('<p class="error-message">Greška pri učitavanju događaja.</p>');
127                }
128            },
129            error: function() {
130                $('#rdd-events-list').html('<p class="error-message">Greška pri komunikaciji sa serverom.</p>');
131            }
132        });
133    }
134
135    function normalizeEventsForPastFilter(events, showPastEvents) {
136        const today = new Date();
137        today.setHours(0, 0, 0, 0);
138
139        const getComparableDate = function(event) {
140            return parseEventDateValue(event.end_date) || parseEventDateValue(event.date);
141        };
142
143        const isPastEvent = function(event) {
144            const comparableDate = getComparableDate(event);
145            return comparableDate ? comparableDate < today : false;
146        };
147
148        const filtered = events.filter(function(event) {
149            return showPastEvents ? isPastEvent(event) : !isPastEvent(event);
150        });
151
152        filtered.sort(function(a, b) {
153            const dateA = getComparableDate(a);
154            const dateB = getComparableDate(b);
155
156            if (!dateA && !dateB) return 0;
157            if (!dateA) return 1;
158            if (!dateB) return -1;
159
160            return showPastEvents ? (dateB - dateA) : (dateA - dateB);
161        });
162
163        return filtered;
164    }
165
166    function parseEventDateValue(dateValue) {
167        if (!dateValue || typeof dateValue !== 'string') {
168            return null;
169        }
170
171        const trimmed = dateValue.trim();
172        const isoMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
173
174        if (isoMatch) {
175            const year = parseInt(isoMatch[1], 10);
176            const month = parseInt(isoMatch[2], 10) - 1;
177            const day = parseInt(isoMatch[3], 10);
178            return new Date(year, month, day);
179        }
180
181        const parsed = new Date(trimmed);
182        return Number.isNaN(parsed.getTime()) ? null : parsed;
183    }
184
185    function clearMarkers() {
186        for (let i = 0; i < markers.length; i++) {
187            markers[i].setMap(null);
188        }
189        markers = [];
190        if (markerCluster) {
191            markerCluster.clearMarkers();
192        }
193        oms.clearMarkers();
194    }
195
196    function addMarkers(events) {
197        console.log(events);
198
199        events.forEach(function(event, index) {
200            if (event.lat && event.lng) {
201                const marker = new google.maps.Marker({
202                    position: {
203                        lat: parseFloat(event.lat) + (Math.random() - 0.5) * 0.0001,
204                        lng: parseFloat(event.lng) + (Math.random() - 0.5) * 0.0001
205                    },
206                    map: map,
207                    title: event.title,
208                    icon: {
209                        path: 'M11 2c-3.9 0-7 3.1-7 7 0 5.3 7 13 7 13 0 0 7-7.7 7-13 0-3.9-3.1-7-7-7Zm0 9.5c-1.4 0-2.5-1.1-2.5-2.5 0-1.4 1.1-2.5 2.5-2.5 1.4 0 2.5 1.1 2.5 2.5 0 1.4-1.1 2.5-2.5 2.5Z',
210                        scale: 1.6363636363636365,
211                        anchor: new google.maps.Point(11, 22),
212                        fillOpacity: 1,
213                        fillColor: '#c36',
214                        strokeOpacity: 0
215                    }
216                });
217
218                marker.addListener('click', function() {
219                    selectEventInList(index);
220                });
221
222                markers.push(marker);
223                oms.addMarker(marker);
224            }
225        });
226
227        markerCluster = new MarkerClusterer(map, markers, {
228            imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
229        });
230    }
231
232    function updateEventsList(events) {
233        const $eventsList = $('#rdd-events-list');
234        $eventsList.empty();
235
236        if (events.length === 0) {
237            $eventsList.html('<p class="loading-message">Sorry, no events match your filters.</p>');
238            return;
239        }
240
241        events.forEach(function(event, index) {
242            const eventHtml =
243                '<div class="event-item" data-event-index="' + index + '">' +
244                    '<div class="event-image" style="background-image: url(' + event.photo + ')" title="' + event.title + '"></div>' +
245                    '<div class="event-info">' +
246                        '<a class="event-title" href="' + event.url + '" target="_blank">' + event.title + '</a>' +
247                        '<div class="event-location">' +
248                            '<span>' + formatDate(event.date) + '</span>, ' +
249                            '<a href="'+ event.country_url + '" target="_blank"><span>' + event.city + ', ' + event.country + '</span></a>' +
250                        '</div>' +
251                        '<p class="event-description">' + event.description + '</p>' +
252                    '</div>' +
253                '</div>';
254            $eventsList.append(eventHtml);
255        });
256    }
257
258    function selectEventInList(index) {
259        $('.event-item').removeClass('selected');
260        const $selectedItem = $('.event-item[data-event-index="' + index + '"]');
261        $selectedItem.addClass('selected');
262
263        const $list = $('#rdd-events-list');
264        const itemOffsetTop = $selectedItem.offset().top;
265        const listOffsetTop = $list.offset().top;
266        const scrollTop = itemOffsetTop - listOffsetTop + $list.scrollTop();
267
268        $list.animate({ scrollTop: scrollTop }, 500);
269    }
270
271    function zoomToCountry(country) {
272        geocoder.geocode({ 'address': country }, function(results, status) {
273            if (status === google.maps.GeocoderStatus.OK && results[0]) {
274                map.fitBounds(results[0].geometry.viewport);
275            } else {
276                console.log('Nije pronađena zemlja: ' + country);
277            }
278        });
279    }
280
281    function updateEventTypeOptions(types, selectedValue) {
282        const $eventTypeSelect = $('#filter-event-type');
283        const currentValue = $eventTypeSelect.val();
284
285        $eventTypeSelect.empty();
286        $eventTypeSelect.append($('<option>', {
287            value: '',
288            text: 'All'
289        }));
290
291        types.forEach(function(type) {
292            $eventTypeSelect.append($('<option>', {
293                value: type,
294                text: type
295            }));
296        });
297
298        if (selectedValue) {
299            $eventTypeSelect.val(selectedValue);
300        } else {
301            $eventTypeSelect.val(currentValue);
302        }
303    }
304
305    $('#filter-country, #filter-event-type, #show-past-events').on('change', function(event) {
306        const isShowPastEvents = (event.target.id === 'show-past-events');
307        const isCountryFilter = (event.target.id === 'filter-country');
308
309        if (isCountryFilter || (isShowPastEvents && !$(this).is(':checked'))) {
310            $('#filter-event-type').val('');
311
312            if (isShowPastEvents && !$(this).is(':checked')) {
313                $('#filter-country').val('');
314            }
315
316            const urlParams = new URLSearchParams(window.location.search);
317            urlParams.delete('Type');
318            window.history.replaceState({}, '', `${window.location.pathname}?${urlParams}`);
319        }
320
321        loadEvents();
322    });
323
324    //CHANGED: don't call initMap() immediately
325    runWhenMapsReady(initMap);
326});
327
328function formatDate(dateString) {
329    const date = new Date(dateString);
330    const day = date.getDate();
331    const month = date.toLocaleString('default', { month: 'short' });
332    const year = date.getFullYear();
333    return `${day} ${month}, ${year}`;
334}
335
336function capitalizeWords(str) {
337    return str.replace(/\b\w/g, function(char) {
338        return char.toUpperCase();
339    });
340}

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.