PageSourceSearch

https://fogos.pt/js/map-filters.js?v=1783011343

js fogos.pt collected 2026-10-01 09:14:42 UTC 9,410 bytes, 190 lines download raw bytes

1/**
2 * Advanced filters panel — numeric inputs (active >= N hours, total
3 * resources >= N) applied client-side to the cached fire list. Calls
4 * window.fogosApplyFilters() (defined in main.js) to re-render markers
5 * after a short debounce.
6 *
7 * State persists in localStorage under "fogos:map-filters".
8 */
9(function () {
10    var STORE_KEY = 'fogos:map-filters';
11
12    function loadState() {
13        try {
14            if (typeof store !== 'undefined' && store.get) {
15                return store.get(STORE_KEY) || {};
16            }
17            var raw = localStorage.getItem(STORE_KEY);
18            return raw ? JSON.parse(raw) : {};
19        } catch (e) { return {}; }
20    }
21    function saveState(s) {
22        try {
23            if (typeof store !== 'undefined' && store.set) store.set(STORE_KEY, s);
24            else localStorage.setItem(STORE_KEY, JSON.stringify(s));
25        } catch (e) {}
26    }
27
28    function injectStyles() {
29        if (document.getElementById('fogos-filters-styles')) return;
30        var css = '' +
31            '.fogos-filters{width:240px;background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,.18);font-family:"Roboto",sans-serif;user-select:none;overflow:hidden}' +
32            '.fogos-filters.is-collapsed{width:44px}' +
33            '.fogos-filters.is-collapsed .fogos-filters__body,.fogos-filters.is-collapsed .fogos-filters__title{display:none}' +
34            '.fogos-filters.is-collapsed .fogos-filters__header{cursor:pointer;justify-content:center;padding:10px}' +
35            '.fogos-filters.is-collapsed .fogos-filters__collapse i{transform:rotate(180deg)}' +
36            '.fogos-filters__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:linear-gradient(135deg,#3b6db5,#1f3f73);color:#fff;font-weight:500;font-size:13px;text-transform:uppercase;letter-spacing:.4px}' +
37            '.fogos-filters__title{flex:1}' +
38            '.fogos-filters__collapse{background:transparent;border:0;color:#fff;cursor:pointer;padding:4px 6px;font-size:14px;line-height:1;flex-shrink:0}' +
39            '.fogos-filters__collapse i{transition:transform .2s;display:inline-block;min-width:14px;text-align:center}' +
40            '.fogos-filters__body{padding:10px 12px}' +
41            '.fogos-filters__row{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}' +
42            '.fogos-filters__row:last-child{margin-bottom:0}' +
43            '.fogos-filters__label{font-size:12px;color:#333;flex:1;margin-right:8px}' +
44            '.fogos-filters__input{width:70px;padding:4px 6px;border:1px solid #ccc;border-radius:4px;font-size:13px;text-align:right}' +
45            '.fogos-filters__input:focus{outline:none;border-color:#3b6db5}' +
46            '.fogos-filters__footer{margin-top:8px;display:flex;justify-content:space-between;align-items:center;font-size:11px;color:#666}' +
47            '.fogos-filters__clear{background:transparent;border:0;color:#3b6db5;cursor:pointer;font-size:11px;padding:0;text-decoration:underline}';
48        var s = document.createElement('style');
49        s.id = 'fogos-filters-styles';
50        s.appendChild(document.createTextNode(css));
51        document.head.appendChild(s);
52    }
53
54    L.Control.FogosFilters = L.Control.extend({
55        options: { position: 'topleft' },
56
57        onAdd: function (map) {
58            injectStyles();
59            this._map = map;
60            this._state = loadState();
61            window.fogosFilters = {
62                minHours: parseFloat(this._state.minHours) || 0,
63                minMeios: parseFloat(this._state.minMeios) || 0
64            };
65
66            var c = this._container = L.DomUtil.create('div', 'fogos-filters');
67            if (this._state.__collapsed !== false) {
68                L.DomUtil.addClass(c, 'is-collapsed');
69            }
70            L.DomEvent.disableClickPropagation(c);
71            L.DomEvent.disableScrollPropagation(c);
72
73            this._render();
74            return c;
75        },
76
77        _render: function () {
78            var tf = (window.trans && window.trans.filtersPanel) || {};
79            var f = window.fogosFilters;
80            var html = '';
81            html += '<div class="fogos-filters__header" data-role="header">';
82            html += '  <span class="fogos-filters__title">' + this._escape(tf.title || 'Filtros avançados') + '</span>';
83            html += '  <button type="button" class="fogos-filters__collapse" aria-label="Toggle"><i class="fas fa-chevron-left"></i></button>';
84            html += '</div>';
85            html += '<div class="fogos-filters__body">';
86            html += '  <div class="fogos-filters__row">';
87            html += '    <label class="fogos-filters__label" for="fogos-f-hours">' + this._escape(tf.minHours || 'Ativo há mais de (h)') + '</label>';
88            html += '    <input id="fogos-f-hours" class="fogos-filters__input" type="number" min="0" step="1" data-filter="minHours" value="' + (f.minHours || '') + '">';
89            html += '  </div>';
90            html += '  <div class="fogos-filters__row">';
91            html += '    <label class="fogos-filters__label" for="fogos-f-meios">' + this._escape(tf.minMeios || 'Total de meios ≥') + '</label>';
92            html += '    <input id="fogos-f-meios" class="fogos-filters__input" type="number" min="0" step="1" data-filter="minMeios" value="' + (f.minMeios || '') + '">';
93            html += '  </div>';
94            html += '  <div class="fogos-filters__footer">';
95            html += '    <span data-role="count"></span>';
96            html += '    <button type="button" class="fogos-filters__clear" data-role="clear">' + this._escape(tf.clear || 'Limpar') + '</button>';
97            html += '  </div>';
98            html += '</div>';
99            this._container.innerHTML = html;
100            this._bind();
101            this._renderCount();
102        },
103
104        _renderCount: function () {
105            if (!this._container) return;
106            var el = this._container.querySelector('[data-role="count"]');
107            if (!el) return;
108            var c = window.fogosFilterCount;
109            if (!c) { el.textContent = ''; return; }
110            var tf = (window.trans && window.trans.filtersPanel) || {};
111            var tpl = tf.showing || '{shown}/{total}';
112            el.textContent = tpl.replace('{shown}', c.shown).replace('{total}', c.total);
113        },
114
115        _bind: function () {
116            var self = this;
117            var collapseBtn = this._container.querySelector('.fogos-filters__collapse');
118            if (collapseBtn) {
119                L.DomEvent.on(collapseBtn, 'click', function (e) {
120                    L.DomEvent.stop(e);
121                    self._toggleCollapse();
122                });
123            }
124            var header = this._container.querySelector('[data-role="header"]');
125            if (header) {
126                L.DomEvent.on(header, 'click', function (e) {
127                    if (L.DomUtil.hasClass(self._container, 'is-collapsed')) {
128                        L.DomEvent.stop(e);
129                        self._toggleCollapse();
130                    }
131                });
132            }
133            var inputs = this._container.querySelectorAll('.fogos-filters__input');
134            Array.prototype.forEach.call(inputs, function (input) {
135                L.DomEvent.on(input, 'input', function () {
136                    var key = input.getAttribute('data-filter');
137                    var val = parseFloat(input.value);
138                    val = (isNaN(val) || val < 0) ? 0 : val;
139                    window.fogosFilters[key] = val;
140                    self._state[key] = val;
141                    saveState(self._state);
142                    self._scheduleApply();
143                });
144            });
145            var clearBtn = this._container.querySelector('[data-role="clear"]');
146            if (clearBtn) {
147                L.DomEvent.on(clearBtn, 'click', function (e) {
148                    L.DomEvent.stop(e);
149                    window.fogosFilters = { minHours: 0, minMeios: 0 };
150                    self._state.minHours = 0;
151                    self._state.minMeios = 0;
152                    saveState(self._state);
153                    self._render();
154                    self._scheduleApply();
155                });
156            }
157        },
158
159        _toggleCollapse: function () {
160            var collapsed = !L.DomUtil.hasClass(this._container, 'is-collapsed');
161            if (collapsed) L.DomUtil.addClass(this._container, 'is-collapsed');
162            else L.DomUtil.removeClass(this._container, 'is-collapsed');
163            this._state.__collapsed = collapsed;
164            saveState(this._state);
165        },
166
167        _scheduleApply: function () {
168            if (this._debounce) clearTimeout(this._debounce);
169            this._debounce = setTimeout(function () {
170                if (typeof window.fogosApplyFilters === 'function') {
171                    window.fogosApplyFilters();
172                }
173            }, 250);
174        },
175
176        refreshCount: function () { this._renderCount(); },
177
178        _escape: function (s) {
179            return String(s == null ? '' : s)
180                .replace(/&/g, '&amp;')
181                .replace(/</g, '&lt;')
182                .replace(/>/g, '&gt;')
183                .replace(/"/g, '&quot;');
184        }
185    });
186
187    L.control.fogosFilters = function (options) {
188        return new L.Control.FogosFilters(options);
189    };
190})();

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.