1/** 2 * Locale Modal (LM) â Globe icon popup for Country / Language / Currency 3 * 4 * Works on ALL pages: 5 * - Homepage: calls LZ.setCountry/setLanguage/setCurrency (live, no reload) 6 * - Analysis pages: saves to localStorage + cookies, then reloads 7 * 8 * Data source: window.__LM_DATA__ injected server-side (countries, languages, currencies) 9 * 10 * Public API: 11 * LM.open(opts) â open the modal; opts.lockCountry = true disables the country field 12 * LM.close() â close the modal 13 * LM.apply() â apply selections and close 14 */ 15(function () { 16 'use strict'; 17 if (window.LM) return; 18 19 var LM = window.LM = {}; 20 var _built = false; 21 var _lockCountry = false; 22 var _countries = []; // CX-11A: full-world country list (code/flag/name) 23 var _selectedCountry = 'SA'; // CX-11A: state for the searchable country picker 24 var _noResultsText = 'No countries found'; 25 26 // ââ Fallback locale data (used if __LM_DATA__ not available) âââââââââââââââ 27 var _fallbackCountries = [ 28 { code: 'SA', flag: '\uD83C\uDDF8\uD83C\uDDE6', name: '\u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0629' }, 29 { code: 'AE', flag: '\uD83C\uDDE6\uD83C\uDDEA', name: '\u0627\u0644\u0625\u0645\u0627\u0631\u0627\u062A' }, 30 { code: 'EG', flag: '\uD83C\uDDEA\uD83C\uDDEC', name: '\u0645\u0635\u0631' }, 31 { code: 'US', flag: '\uD83C\uDDFA\uD83C\uDDF8', name: 'United States' }, 32 { code: 'GB', flag: '\uD83C\uDDEC\uD83C\uDDE7', name: 'United Kingdom' }, 33 { code: 'IN', flag: '\uD83C\uDDEE\uD83C\uDDF3', name: 'India' }, 34 ]; 35 var _fallbackLanguages = [ 36 { code: 'ar', labelFull: '\uD83C\uDF10 \u0639\u0631\u0628\u064A' }, 37 { code: 'en', labelFull: '\uD83C\uDF10 English' }, 38 ]; 39 var _fallbackCurrencies = ['SAR', 'AED', 'EGP', 'USD', 'INR', 'EUR', 'GBP']; 40 41 // ââ Read current locale values ââââââââââââââââââââââââââââââââââââââââââââââ 42 // PHASE UI-01 (completion) â language always comes from the single 43 // Presentation Context; only country/currency (out of PresentationContext's 44 // scope) still read LZ / the sm_lz_v1 bundle. 45 function _getCurrent() { 46 var country = 'SA', currency = 'SAR'; 47 if (window.LZ) { 48 country = LZ.country || country; 49 currency = LZ.currency || currency; 50 } else { 51 try { 52 var s = JSON.parse(localStorage.getItem('sm_lz_v1') || '{}'); 53 if (s.country_code) country = s.country_code; 54 if (s.currency_code) currency = s.currency_code; 55 } catch (_e) {} 56 } 57 return { country: country, language: window.PresentationContext.language, currency: currency }; 58 } 59 60 // ââ Build modal HTML (once) âââââââââââââââââââââââââââââââââââââââââââââââââ 61 function _build() { 62 if (_built) return; 63 _built = true; 64 65 var data = window.__LM_DATA__ || {}; 66 var countries = (data.countries && data.countries.length) ? data.countries : _fallbackCountries; 67 var languages = (data.languages && data.languages.length) ? data.languages : _fallbackLanguages; 68 var currencies = (data.currencies && data.currencies.length) ? data.currencies : _fallbackCurrencies; 69 70 var isAr = window.PresentationContext.language === 'ar'; 71 72 var T = isAr ? { 73 title: '\u0627\u0644\u0644\u063A\u0629 \u0648\u0627\u0644\u0639\u0645\u0644\u0629', 74 titleFull: '\u0627\u0644\u062F\u0648\u0644\u0629 \u0648\u0627\u0644\u0644\u063A\u0629 \u0648\u0627\u0644\u0639\u0645\u0644\u0629', 75 country: '\u0627\u0644\u062F\u0648\u0644\u0629', 76 lang: '\u0627\u0644\u0644\u063A\u0629', 77 currency: '\u0627\u0644\u0639\u0645\u0644\u0629', 78 apply: '\u062A\u0637\u0628\u064A\u0642', 79 close: '\u0625\u063A\u0644\u0627\u0642', 80 countryNote: '\u062B\u0627\u0628\u062A\u0629 \u2014 \u062A\u0645 \u062A\u062D\u062F\u064A\u062F\u0647\u0627 \u0639\u0646\u062F \u0628\u062F\u0621 \u0627\u0644\u0628\u062D\u062B', 81 searchPlaceholder: '\u0627\u0628\u062D\u062B \u0639\u0646 \u062F\u0648\u0644\u0629...', 82 noResults: '\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C', 83 } : { 84 title: 'Language & Currency', 85 titleFull: 'Country, Language & Currency', 86 country: 'Country', 87 lang: 'Language', 88 currency: 'Currency', 89 apply: 'Apply', 90 close: 'Close', 91 countryNote: 'Fixed â set when the search started', 92 searchPlaceholder: 'Search for a country...', 93 noResults: 'No countries found', 94 }; 95 _noResultsText = T.noResults; 96 97 // Inject CSS 98 var style = document.createElement('style'); 99 style.textContent = [ 100 '#lm-overlay{position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.5);display:none;', 101 'align-items:flex-end;justify-content:center;padding:0}', 102 '@media(min-width:480px){#lm-overlay{align-items:center;padding:16px}}', 103 '#lm-overlay.lm-open{display:flex}', 104 '#lm-modal{background:#fff;border-radius:20px 20px 0 0;width:100%;max-width:460px;', 105 'box-shadow:0 -8px 40px rgba(0,0,0,.2);overflow:hidden;font-family:inherit;', 106 'display:flex;flex-direction:column;max-height:92svh;max-height:92vh;', 107 'animation:lmSlideUp .22s ease}', 108 '@media(min-width:480px){#lm-modal{border-radius:20px;animation:lmFadeIn .18s ease;max-height:90vh}}', 109 '.lm-body{overflow-y:auto;flex:1 1 auto}', 110 '.lm-ft{flex-shrink:0}',
111 '@keyframes lmSlideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}', 112 '@keyframes lmFadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}', 113 '.lm-hd{display:flex;align-items:center;justify-content:space-between;', 114 'padding:18px 20px 14px;border-bottom:1px solid #F1F5F9}', 115 '.lm-title{font-size:16px;font-weight:800;color:#0F172A}', 116 '.lm-close-btn{width:32px;height:32px;border-radius:50%;background:#F1F5F9;border:none;', 117 'cursor:pointer;font-size:16px;display:flex;align-items:center;justify-content:center;', 118 'color:#64748B;transition:background .15s}', 119 '.lm-close-btn:hover{background:#E2E8F0}', 120 '.lm-body{padding:20px;display:flex;flex-direction:column;gap:16px}', 121 '.lm-group{display:flex;flex-direction:column;gap:6px}', 122 '.lm-label{font-size:11px;font-weight:700;color:#94A3B8;text-transform:uppercase;letter-spacing:.07em;', 123 'display:flex;align-items:center;gap:6px}', 124 '.lm-lock-icon{font-size:11px}', 125 '.lm-select{width:100%;padding:11px 14px;border:1.5px solid #E2E8F0;border-radius:12px;', 126 'font-size:14px;font-weight:600;color:#0F172A;background:#F8FAFC;cursor:pointer;', 127 'outline:none;font-family:inherit;-webkit-appearance:none;appearance:none;', 128 'background-image:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'12\' height=\'8\' viewBox=\'0 0 12 8\'%3E%3Cpath fill=\'%2394A3B8\' d=\'M6 8L0 0h12z\'/%3E%3C/svg%3E");', 129 'background-repeat:no-repeat;background-position:calc(100% - 14px) center}', 130 'html[dir=rtl] .lm-select{background-position:14px center;padding-right:14px;padding-left:36px}', 131 '.lm-select:focus{border-color:#F97316;box-shadow:0 0 0 3px rgba(249,115,22,.12);background:#fff}', 132 '.lm-select:disabled{opacity:1;cursor:not-allowed;color:#64748B;background:#F1F5F9;', 133 'border-color:#E2E8F0;background-image:none}', 134 '.lm-country-note{font-size:11px;color:#94A3B8;margin-top:2px;display:none}', 135 '.lm-country-note.lm-visible{display:block}', 136 /* CX-11A: searchable country picker */ 137 '.lm-country-search-wrap{position:relative}', 138 '.lm-country-search{width:100%;padding:11px 14px;border:1.5px solid #E2E8F0;border-radius:12px;', 139 'font-size:14px;font-weight:600;color:#0F172A;background:#F8FAFC;outline:none;', 140 'font-family:inherit;box-sizing:border-box}', 141 '.lm-country-search:focus{border-color:#F97316;box-shadow:0 0 0 3px rgba(249,115,22,.12);background:#fff}', 142 '.lm-country-search:disabled{opacity:1;cursor:not-allowed;color:#64748B;background:#F1F5F9}', 143 '.lm-country-list{margin-top:6px;max-height:200px;overflow-y:auto;border:1.5px solid #E2E8F0;', 144 'border-radius:12px;background:#fff}', 145 '.lm-country-list.lm-hidden{display:none}', 146 '.lm-country-item{display:flex;align-items:center;gap:8px;padding:10px 14px;font-size:14px;', 147 'font-weight:600;color:#0F172A;cursor:pointer;transition:background .1s}', 148 '.lm-country-item:hover,.lm-country-item.lm-active{background:#FFF7ED}', 149 '.lm-country-item.lm-selected{background:#FFEDD5;color:#C2410C}', 150 '.lm-country-empty{padding:14px;text-align:center;font-size:13px;color:#94A3B8}', 151 '.lm-country-current{display:flex;align-items:center;gap:8px;padding:11px 14px;', 152 'border:1.5px solid #E2E8F0;border-radius:12px;background:#F8FAFC;font-size:14px;', 153 'font-weight:600;color:#0F172A;cursor:pointer}', 154 '.lm-country-current:hover{border-color:#CBD5E1}', 155 '.lm-country-current.lm-locked{cursor:not-allowed;color:#64748B}', 156 '.lm-ft{padding:16px 20px 20px;border-top:1px solid #F1F5F9}', 157 '.lm-apply-btn{width:100%;padding:14px;border:none;border-radius:12px;', 158 'background:#F97316;color:#fff;font-size:15px;font-weight:800;cursor:pointer;', 159 'letter-spacing:.02em;transition:background .15s;font-family:inherit}', 160 '.lm-apply-btn:hover{background:#E54B00}', 161 '.lm-apply-btn:active{background:#C73F00}', 162 ].join(''); 163 document.head.appendChild(style); 164 165 _countries = countries; 166 167 var lOpts = languages.map(function (l) { 168 return '<option value="' + l.code + '">' + l.labelFull + '</option>'; 169 }).join(''); 170 var cyOpts = currencies.map(function (c) { 171 return '<option value="' + c + '">' + c + '</option>'; 172 }).join(''); 173 174 var dir = isAr ? 'rtl' : 'ltr'; 175 var html = '<div id="lm-overlay" onclick="if(event.target===this)LM.close()" role="dialog" aria-modal="true" aria-label="' + T.titleFull + '">' 176 + '<div id="lm-modal" dir="' + dir + '">' 177 + '<div class="lm-hd">' 178 + '<span class="lm-title" id="lm-title">' + T.titleFull + '</span>' 179 + '<button class="lm-close-btn" onclick="LM.close()" aria-label="' + T.close + '">✕</button>' 180 + '</div>' 181 + '<div class="lm-body">' 182 + '<div class="lm-group" id="lm-country-group">' 183 + '<label class="lm-label"><span id="lm-country-lock-icon"></span>' + T.country + '</label>' 184 + '<div class="lm-country-search-wrap">' 185 + '<input type="text" id="lm-country-search" class="lm-country-search" placeholder="' + T.searchPlaceholder + '" autocomplete="off" />' 186 + '<div class="lm-country-list lm-hidden" id="lm-country-list" role="listbox"></div>' 187 + '</div>' 188 + '<div class="lm-country-note" id="lm-country-note">' + T.countryNote + '</div>' 189 + '</div>' 190 + '<div class="lm-group"><label class="lm-label">' + T.lang + '</label>' 191 + '<select id="lm-sel-lang" class="lm-select">' + lOpts + '</select></div>' 192 + '<div class="lm-group"><label class="lm-label">' + T.currency + '</label>' 193 + '<select id="lm-sel-currency" class="lm-select">' + cyOpts + '</select></div>' 194 + '</div>' 195 + '<div class="lm-ft"><button class="lm-apply-btn" onclick="LM.apply()">' + T.apply + '</button></div>' 196 + '</div></div>'; 197 198 document.body.insertAdjacentHTML('beforeend', html); 199 _wireCountrySearch(); 200 } 201 202 // ââ CX-11A: searchable country picker âââââââââââââââââââââââââââââââââââââââ 203 function _escHtml(s) { 204 return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); 205 } 206 207 function _findCountry(code) { 208 for (var i = 0; i < _countries.length; i++) { 209 if (_countries[i].code === code) return _countries[i]; 210 } 211 return null; 212 } 213 214 function _renderCountryList(filterText) { 215 var listEl = document.getElementById('lm-country-list'); 216 if (!listEl) return; 217 var q = (filterText || '').trim().toLowerCase(); 218 var matches = !q ? _countries : _countries.filter(function (c) { 219 return c.name.toLowerCase().indexOf(q) !== -1 || c.code.toLowerCase().indexOf(q) !== -1; 220 }); 221 if (!matches.length) { 222 listEl.innerHTML = '<div class="lm-country-empty">' + _escHtml(_noResultsText) + '</div>'; 223 return; 224 } 225 listEl.innerHTML = matches.slice(0, 300).map(function (c) { 226 var sel = c.code === _selectedCountry ? ' lm-selected' : ''; 227 return '<div class="lm-country-item' + sel + '" role="option" data-code="' + c.c
227ode + '">' 228 + c.flag + ' ' + _escHtml(c.name) + '</div>'; 229 }).join(''); 230 } 231 232 function _selectCountry(code) { 233 var c = _findCountry(code); 234 if (!c) return; 235 _selectedCountry = code; 236 var input = document.getElementById('lm-country-search'); 237 if (input) input.value = c.flag + ' ' + c.name; 238 var listEl = document.getElementById('lm-country-list'); 239 if (listEl) listEl.classList.add('lm-hidden'); 240 } 241 242 function _wireCountrySearch() { 243 var input = document.getElementById('lm-country-search'); 244 var listEl = document.getElementById('lm-country-list'); 245 if (!input || !listEl) return; 246 247 input.addEventListener('focus', function () { 248 if (_lockCountry) return; 249 _renderCountryList(input.value === _currentDisplayValue() ? '' : input.value); 250 listEl.classList.remove('lm-hidden'); 251 }); 252 input.addEventListener('input', function () { 253 if (_lockCountry) return; 254 _renderCountryList(input.value); 255 listEl.classList.remove('lm-hidden'); 256 }); 257 // Delay hide so click on a list item registers before blur closes it. 258 input.addEventListener('blur', function () { 259 setTimeout(function () { listEl.classList.add('lm-hidden'); }, 150); 260 }); 261 listEl.addEventListener('mousedown', function (e) { 262 var item = e.target.closest ? e.target.closest('.lm-country-item') : null; 263 if (!item) return; 264 e.preventDefault(); 265 _selectCountry(item.getAttribute('data-code')); 266 }); 267 } 268 269 function _currentDisplayValue() { 270 var c = _findCountry(_selectedCountry); 271 return c ? (c.flag + ' ' + c.name) : ''; 272 } 273 274 // ââ Apply lock state visually âââââââââââââââââââââââââââââââââââââââââââââââ 275 function _applyLockState() { 276 var cs = document.getElementById('lm-country-search'); 277 var listEl = document.getElementById('lm-country-list'); 278 var lockIcon = document.getElementById('lm-country-lock-icon'); 279 var lockNote = document.getElementById('lm-country-note'); 280 var titleEl = document.getElementById('lm-title'); 281 var isAr = window.PresentationContext.language === 'ar'; 282 283 if (cs) cs.disabled = _lockCountry; 284 if (_lockCountry && listEl) listEl.classList.add('lm-hidden'); 285 286 if (lockIcon) lockIcon.textContent = _lockCountry ? '\uD83D\uDD12 ' : ''; 287 288 if (lockNote) { 289 if (_lockCountry) lockNote.classList.add('lm-visible'); 290 else lockNote.classList.remove('lm-visible'); 291 } 292 293 if (titleEl) { 294 if (_lockCountry) { 295 titleEl.textContent = isAr ? '\u0627\u0644\u0644\u063A\u0629 \u0648\u0627\u0644\u0639\u0645\u0644\u0629' : 'Language & Currency'; 296 } else { 297 titleEl.textContent = isAr ? '\u0627\u0644\u062F\u0648\u0644\u0629 \u0648\u0627\u0644\u0644\u063A\u0629 \u0648\u0627\u0644\u0639\u0645\u0644\u0629' : 'Country, Language & Currency'; 298 } 299 } 300 } 301 302 // ââ Public API ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 303 LM.open = function (opts) { 304 opts = opts || {}; 305 _lockCountry = !!opts.lockCountry; 306 307 _build(); 308 309 var cur = _getCurrent(); 310 var cs = document.getElementById('lm-country-search'); 311 var ls = document.getElementById('lm-sel-lang'); 312 var cy = document.getElementById('lm-sel-currency'); 313 _selectedCountry = cur.country; 314 if (cs) cs.value = _currentDisplayValue() || cur.country; 315 if (ls) ls.value = cur.language; 316 if (cy) cy.value = cur.currency; 317 318 _applyLockState(); 319 320 var ov = document.getElementById('lm-overlay'); 321 if (ov) { ov.classList.add('lm-open'); document.body.style.overflow = 'hidden'; } 322 }; 323 324 LM.close = function () { 325 var ov = document.getElementById('lm-overlay'); 326 if (ov) { ov.classList.remove('lm-open'); document.body.style.overflow = ''; } 327 }; 328 329 LM.apply = function () { 330 var ls = document.getElementById('lm-sel-lang'); 331 var cy = document.getElementById('lm-sel-currency'); 332 // Country is ignored when locked 333 var country = !_lockCountry ? _selectedCountry : null; 334 var language = ls ? ls.value : null; 335 var currency = cy ? cy.value : null; 336 337 if (window.LZ && typeof LZ.setLanguage === 'function') { 338 // Homepage: LZ handles live re-render without page reload. 339 // IMPORTANT: only call setCountry if the country actually changed. 340 // setCountry is async and resets _langManual, which causes it to overwrite 341 // the language cookie set by setLanguage (race condition). 342 var _currentCountry = LZ.country || null; 343 var _countryChanged = country && country !== _currentCountry; 344 if (language) LZ.setLanguage(language); 345 if (currency) LZ.setCurrency(currency); 346 if (_countryChanged) LZ.setCountry(country); 347 LM.updateButtons(); 348 LM.close(); 349 } else { 350 // Analysis pages: persist to localStorage + cookies, then reload
351 try { 352 var s = JSON.parse(localStorage.getItem('sm_lz_v1') || '{}'); 353 if (country) { s.country_code = country; s.manual = true; } 354 if (language) { s.language_code = language; s.lang_manual = true; } 355 if (currency) { s.currency_code = currency; s.curr_manual = true; } 356 localStorage.setItem('sm_lz_v1', JSON.stringify(s)); 357 } catch (_e) {} 358 // PHASE UI-01 (completion): single write path for sm_lang persistence â 359 // see presentation-language-context.js. locale-modal.js is only ever 360 // loaded on pages that inject the context first (see server.js). 361 if (language) window.PresentationContext.setLanguage(language); 362 if (country) { 363 document.cookie = 'sm_country=' + country + '; path=/; max-age=31536000'; 364 } 365 LM.close(); 366 window.location.reload(); 367 } 368 }; 369 370 // ââ Button sync â updates flag + country name in locale pill buttons ââââââââ 371 function _codeToFlag(code) { 372 if (!code || code.length !== 2) return 'ð'; 373 try { 374 return String.fromCodePoint( 375 0x1F1E6 + code.toUpperCase().charCodeAt(0) - 65, 376 0x1F1E6 + code.toUpperCase().charCodeAt(1) - 65 377 ); 378 } catch (_e) { return 'ð'; } 379 } 380 381 var _COUNTRY_NAMES = { 382 SA:{ar:'Ø§ÙØ³Ø¹ÙØ¯ÙØ©', en:'Saudi Arabia'}, AE:{ar:'Ø§ÙØ¥Ù ارات', en:'UAE'}, 383 EG:{ar:'٠صر', en:'Egypt'}, KW:{ar:'اÙÙÙÙØª', en:'Kuwait'}, 384 QA:{ar:'ÙØ·Ø±', en:'Qatar'}, BH:{ar:'Ø§ÙØ¨ØØ±ÙÙ', en:'Bahrain'}, 385 OM:{ar:'عÙ٠اÙ', en:'Oman'}, JO:{ar:'Ø§ÙØ£Ø±Ø¯Ù', en:'Jordan'}, 386 IQ:{ar:'Ø§ÙØ¹Ø±Ø§Ù', en:'Iraq'}, LB:{ar:'ÙØ¨ÙاÙ', en:'Lebanon'}, 387 YE:{ar:'اÙÙÙ Ù', en:'Yemen'}, IN:{ar:'اÙÙÙØ¯', en:'India'}, 388 US:{ar:'أ٠رÙÙØ§', en:'United States'}, GB:{ar:'Ø¨Ø±ÙØ·Ø§ÙÙØ§', en:'UK'}, 389 CA:{ar:'ÙÙØ¯Ø§', en:'Canada'}, AU:{ar:'أستراÙÙØ§', en:'Australia'}, 390 TR:{ar:'ترÙÙØ§', en:'Turkey'}, DE:{ar:'Ø£Ù٠اÙÙØ§', en:'Germany'}, 391 FR:{ar:'ÙØ±Ùسا', en:'France'}, MA:{ar:'اÙ٠غرب', en:'Morocco'}, 392 DZ:{ar:'Ø§ÙØ¬Ø²Ø§Ø¦Ø±', en:'Algeria'}, PK:{ar:'Ø¨Ø§ÙØ³ØªØ§Ù', en:'Pakistan'}, 393 ID:{ar:'Ø¥ÙØ¯ÙÙÙØ³Ùا', en:'Indonesia'}, PH:{ar:'اÙÙÙØ¨ÙÙ', en:'Philippines'}, 394 TH:{ar:'تاÙÙØ§Ùد', en:'Thailand'}, ES:{ar:'إسباÙÙØ§', en:'Spain'}, 395 IT:{ar:'Ø¥ÙØ·Ø§ÙÙØ§', en:'Italy'}, PL:{ar:'بÙÙÙØ¯Ø§', en:'Poland'}, 396 RU:{ar:'Ø±ÙØ³Ùا', en:'Russia'} 397 }; 398 399 function _codeToName(countryCode, langCode) { 400 var c = (countryCode || '').toUpperCase(); 401 var l = (langCode || 'ar').toLowerCase(); 402 // CX-11A: prefer the full-world list (already localized server-side) when available. 403 var full = _findCountry(c); 404 if (full && full.name) return full.name; 405 var rec = _COUNTRY_NAMES[c]; 406 if (!rec) return c; 407 return l === 'ar' ? rec.ar : rec.en; 408 } 409 410 LM.updateButtons = function () { 411 var cur = _getCurrent(); 412 var flag = _codeToFlag(cur.country); 413 var name = _codeToName(cur.country, cur.language); 414 var lang = (cur.language || 'AR').toUpperCase(); 415 416 // Update both locale token instances (homepage + analysis page) 417 [['hp2LocaleFlag','hp2LocaleName','hp2LocaleLang'], 418 ['aspLocaleFlag','aspLocaleName','aspLocaleLang']].forEach(function(ids) { 419 var elFlag = document.getElementById(ids[0]); 420 var elCountry = document.getElementById(ids[1]); 421 var elLang = document.getElementById(ids[2]); 422 if (elFlag) elFlag.textContent = flag; 423 if (elCountry) elCountry.textContent = name; 424 if (elLang) elLang.textContent = lang; 425 }); 426 }; 427 428 // Close on Escape key 429 document.addEventListener('keydown', function (e) { 430 if (e.key === 'Escape') LM.close(); 431 }); 432})();
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.