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, '&') 181 .replace(/</g, '<') 182 .replace(/>/g, '>') 183 .replace(/"/g, '"'); 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.