PageSourceSearch

https://hls.kz/wp-content/plugins/emergency-map/assets/js/map-kz-panel.js?ver=1.6.17

js hls.kz collected 2026-10-02 07:24:39 UTC 10,873 bytes, 229 lines download raw bytes

1/**
2 * Emergency Map KZ - Panel Module
3 * Panel collapse, event popup, event cards, events list
4 */
5
6(function($, window) {
7    'use strict';
8    
9    window.EmergencyMapKZ = window.EmergencyMapKZ || {};
10    var KZ = window.EmergencyMapKZ;
11    
12    // ========== Panel collapse ==========
13    var isPanelCollapsed = sessionStorage.getItem('kzMapPanelCollapsed') === 'true';
14    var MOBILE_PANEL_QUERY = '(max-width: 600px)';
15
16    function isMobilePanel() {
17        return window.matchMedia && window.matchMedia(MOBILE_PANEL_QUERY).matches;
18    }
19
20    function getExpandedPanelCss() {
21        if (isMobilePanel()) {
22            return {
23                'left': '12px',
24                'right': '12px',
25                'width': 'auto',
26                'max-height': 'calc(100% - 88px)',
27                'overflow': 'visible'
28            };
29        }
30
31        return {
32            'left': 'auto',
33            'right': '24px',
34            'width': '400px',
35            'max-height': '500px',
36            'overflow': 'visible'
37        };
38    }
39    
40    function collapsePanel() {
41        $('#kz-events-panel')
42            .addClass('is-collapsed')
43            .css({ 'left': 'auto', 'width': '48px', 'max-height': '48px', 'overflow': 'hidden' });
44        $('#kz-filters, #kz-events-list, #kz-events-footer').css('opacity', '0').hide();
45        $('#kz-panel-title').hide();
46        $('#kz-events-header').css({ 'border-bottom': 'none', 'padding': '10px' });
47        $('.collapse-icon').hide();
48        $('.expand-icon').css('display', 'inline');
49        sessionStorage.setItem('kzMapPanelCollapsed', 'true');
50    }
51    
52    function expandPanel() {
53        $('#kz-events-panel')
54            .removeClass('is-collapsed')
55            .css(getExpandedPanelCss());
56        $('#kz-filters, #kz-events-list, #kz-events-footer').show().css('opacity', '1');
57        $('#kz-panel-title').show();
58        $('#kz-events-header').css({ 'border-bottom': '1px solid #dee2e6', 'padding': '16px' });
59        $('.collapse-icon').css('display', 'inline');
60        $('.expand-icon').hide();
61        sessionStorage.setItem('kzMapPanelCollapsed', 'false');
62    }
63    
64    // ========== Event popup ==========
65    KZ.showEventPopup = function(eventItem) {
66        var riskColor = KZ.riskColors[eventItem.risk_level] || '#9e9e9e';
67        var riskLabel = KZ.riskLabels[eventItem.risk_level] || '';
68        var i18n = KZ.config.i18n;
69        
70        var stageBadge = '';
71        if (eventItem.stage === 'signal') {
72            stageBadge = '<span style="padding: 4px 12px; background: #fff3cd; color: #856404; border-radius: 3px; font-size: 12px; font-weight: 600;">' + i18n.signal + '</span>';
73        } else {
74            stageBadge = '<span style="padding: 4px 12px; background: #d4edda; color: #155724; border-radius: 3px; font-size: 12px; font-weight: 600;">' + i18n.confirmed + '</span>';
75        }
76        
77        var content = '<div style="padding: 24px;">';
78        content += '<button id="kz-event-close" style="position: absolute; top: 12px; right: 12px; width: 24px; height: 24px; background: transparent; border: none; cursor: pointer; font-size: 24px; color: #999; line-height: 1; padding: 0;">&times;</button>';
79        content += '<h2 style="margin: 0 0 16px 0; font-size: 20px; font-weight: 600; color: #333; padding-right: 30px;">' + (eventItem.title || '') + '</h2>';
80        
81        content += '<div style="display: flex; gap: 12px; margin-bottom: 16px;">';
82        content += stageBadge;
83        if (riskLabel) {
84            content += '<div style="display: flex; align-items: center; gap: 8px;">';
85            content += '<span style="width: 16px; height: 16px; background: ' + riskColor + '; border-radius: 50%; border: 2px solid white; box-shadow: 0 2px 4px rgba(0,0,0,0.2);"></span>';
86            content += '<span style="font-size: 13px; color: #666;">' + i18n.riskLevel + ' ' + riskLabel + '</span>';
87            content += '</div>';
88        }
89        content += '</div>';
90        
91        if (eventItem.location || eventItem.region_name) {
92            content += '<div style="margin-bottom: 12px;">';
93            content += '<strong style="color: #666; font-size: 13px;">' + i18n.location + ':</strong> ';
94            content += '<span style="color: #333; font-size: 14px;">' + (eventItem.location || eventItem.region_name) + '</span>';
95            content += '</div>';
96        }
97        
98        if (eventItem.date) {
99            var dateOnly = KZ.formatDate(eventItem.date);
100            content += '<div style="margin-bottom: 16px;">';
101            content += '<strong style="color: #666; font-size: 13px;">' + i18n.date + ':</strong> ';
102            content += '<span style="color: #333; font-size: 14px;">' + dateOnly + '</span>';
103            content += '</div>';
104        }
105        
106        var sourcesHtml = KZ.buildSourcesHtml(eventItem, '14px');
107        if (sourcesHtml) {
108            content += '<div style="padding-top: 16px; border-top: 1px solid #dee2e6;">';
109            content += sourcesHtml;
110            content += '</div>';
111        }
112        
113        content += '</div>';
114        
115        $('#kz-event-popup').html(content);
116        $('#kz-event-overlay').fadeIn(200);
117        $('#kz-event-popup').fadeIn(200);
118    };
119    
120    // ========== Event card ==========
121    KZ.renderEventCard = function(eventItem) {
122        var riskColor = KZ.riskColors[eventItem.risk_level] || '#9e9e9e';
123        var riskLabel = KZ.riskLabels[eventItem.risk_level] || '';
124        var i18n = KZ.config.i18n;
125        
126        var stageBadge = eventItem.stage === 'signal'
127            ? '<span style="padding: 2px 8px; background: #fff3cd; color: #856404; border-radius: 3px; font-size: 11px; font-weight: 600;">
127' + i18n.signal + '</span>'
128            : '<span style="padding: 2px 8px; background: #d4edda; color: #155724; border-radius: 3px; font-size: 11px; font-weight: 600;">' + i18n.confirmed + '</span>';
129        
130        var title = eventItem.title || eventItem.threat_name || '';
131        var shortTitle = title.length > 100 ? title.substring(0, 100) + '...' : title;
132        var dateOnly = KZ.formatDate(eventItem.date);
133        
134        var card = '<div class="kz-event-card" data-event-id="' + eventItem.id + '" data-lat="' + (eventItem.lat || '') + '" data-lng="' + (eventItem.lng || '') + '" style="padding: 12px; border: 1px solid #dee2e6; border-radius: 6px; margin-bottom: 8px; cursor: pointer; transition: box-shadow 0.2s;" onmouseover="this.style.boxShadow=\'0 2px 8px rgba(0,0,0,0.1)\'" onmouseout="this.style.boxShadow=\'none\'">';
135        
136        card += '<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">';
137        card += stageBadge;
138        card += '<span style="display: flex; align-items: center; gap: 6px;">';
139        card += '<span style="width: 12px; height: 12px; background: ' + riskColor + '; border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 3px rgba(0,0,0,0.2);"></span>';
140        card += '<span style="font-size: 11px; color: #666;">' + riskLabel + '</span>';
141        card += '</span>';
142        card += '</div>';
143        
144        card += '<div style="font-weight: 600; font-size: 14px; color: #333; margin-bottom: 4px;">' + shortTitle + '</div>';
145        card += '<div style="font-size: 13px; color: #666; margin-bottom: 6px;">' + (eventItem.location || eventItem.region_name || '') + '</div>';
146        card += '<div style="font-size: 12px; color: #777; margin-bottom: 6px;">' + dateOnly + '</div>';
147        
148        var cardSourcesHtml = KZ.buildSourcesHtml(eventItem, '12px');
149        if (cardSourcesHtml) {
150            card += '<div style="margin-bottom: 6px;">' + cardSourcesHtml + '</div>';
151        }
152        
153        card += '<div>';
154        card += '<a href="#" class="kz-event-details-link" data-event-id="' + eventItem.id + '" style="font-size: 12px; color: #007bff; text-decoration: none; font-weight: 500;" onclick="event.preventDefault();">' + i18n.moreDetails + '</a>';
155        card += '</div>';
156        
157        card += '</div>';
158        return card;
159    };
160    
161    // ========== Render events list ==========
162    KZ.renderEventsList = function(events) {
163        var $list = $('#kz-events-list');
164        if (!events || events.length === 0) {
165            $list.html('<div style="text-align: center; padding: 40px 20px; color: #999;">' + KZ.config.i18n.noEvents + '</div>');
166            return;
167        }
168        
169        var html = '';
170        events.forEach(function(ev) {
171            html += KZ.renderEventCard(ev);
172        });
173        $list.html(html);
174    };
175    
176    // ========== Click handlers ==========
177    $(document).ready(function() {
178        // Panel toggle
179        if (isPanelCollapsed) {
180            collapsePanel();
181        } else {
182            expandPanel();
183        }
184        
185        $('#kz-panel-toggle').on('click', function(e) {
186            e.stopPropagation();
187            if (sessionStorage.getItem('kzMapPanelCollapsed') === 'true') {
188                expandPanel();
189            } else {
190                collapsePanel();
191            }
192        });
193        
194        // Close event popup
195        $(document).on('click', '#kz-event-close, #kz-event-overlay', function() {
196            $('#kz-event-overlay').fadeOut(200);
197            $('#kz-event-popup').fadeOut(200);
198        });
199        
200        // Click on event card → pan to marker + highlight active card
201        $(document).on('click', '.kz-event-card', function(e) {
202            if ($(e.target).hasClass('kz-event-details-link') || $(e.target).closest('a').length) return;
203            var lat = parseFloat($(this).data('lat'));
204            var lng = parseFloat($(this).data('lng'));
205            // Highlight active card
206            $('.kz-event-card').css({'border-color': '#dee2e6', 'background': 'white'});
207            $(this).css({'border-color': '#007bff', 'background': '#f0f7ff'});
208            if (!isNaN(lat) && !isNaN(lng) && typeof KZ.focusOnMarker === 'function') {
209                KZ.focusOnMarker(lat, lng);
210            }
211        });
212        
213        // Click "More details"
214        $(document).on('click', '.kz-event-details-link', function(e) {
215            e.preventDefault();
216            e.stopPropagation();
217            var eventId = $(this).data('event-id');
218            var eventItem = KZ.allMapData.find(function(ev) { return ev.id == eventId; });
219            if (eventItem) KZ.showEventPopup(eventItem);
220        });
221
222        $(window).on('resize', function() {
223            if (sessionStorage.getItem('kzMapPanelCollapsed') !== 'true') {
224                $('#kz-events-panel').css(getExpandedPanelCss());
225            }
226        });
227    });
228    
229})(jQuery, window);

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.