(opts = {})
| 231 | } |
| 232 | |
| 233 | export async function initSourceSelector(opts = {}) { |
| 234 | const wrap = document.getElementById('sourceSelectorWrap'); |
| 235 | const select = document.getElementById('sourceSelector'); |
| 236 | if (!wrap || !select) return; |
| 237 | if (wrap.__initialized && !opts.force) return; |
| 238 | |
| 239 | if (!wrap.__initialized) { |
| 240 | wrap.__initialized = true; |
| 241 | wrap.hidden = true; |
| 242 | } |
| 243 | |
| 244 | const prevId = select.getAttribute('data-prev') || select.value || ''; |
| 245 | const keepActive = !!opts.keepActive; |
| 246 | const origin = opts.origin || (opts.force ? 'refresh' : 'init'); |
| 247 | |
| 248 | const apiData = await loadVisibleSourcesFromApi(); |
| 249 | let sourcesCfg = {}; |
| 250 | let sources = []; |
| 251 | let enabled = false; |
| 252 | |
| 253 | if (apiData) { |
| 254 | sourcesCfg = apiData || {}; |
| 255 | enabled = !!apiData.enabled; |
| 256 | sources = Array.isArray(apiData.sources) ? apiData.sources : []; |
| 257 | try { window.__FR_SOURCES_API_ENABLED__ = true; } catch (e) { /* ignore */ } |
| 258 | } else { |
| 259 | const cfg = await loadSiteConfig(); |
| 260 | sourcesCfg = getSourcesConfig(cfg); |
| 261 | enabled = !!sourcesCfg.enabled; |
| 262 | sources = Array.isArray(sourcesCfg.sources) ? sourcesCfg.sources : []; |
| 263 | try { window.__FR_SOURCES_API_ENABLED__ = false; } catch (e) { /* ignore */ } |
| 264 | } |
| 265 | |
| 266 | if (!enabled || !sources.length) { |
| 267 | select.innerHTML = ''; |
| 268 | wrap.hidden = true; |
| 269 | try { window.__FR_SOURCE_NAME_MAP = {}; } catch (e) { /* ignore */ } |
| 270 | try { window.__FR_SOURCE_META_MAP = {}; } catch (e) { /* ignore */ } |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | const nameMap = {}; |
| 275 | const metaMap = {}; |
| 276 | try { window.__FR_SOURCE_NAME_MAP = nameMap; } catch (e) { /* ignore */ } |
| 277 | try { window.__FR_SOURCE_META_MAP = metaMap; } catch (e) { /* ignore */ } |
| 278 | |
| 279 | select.innerHTML = ''; |
| 280 | sources.forEach(src => { |
| 281 | if (!src || typeof src !== 'object') return; |
| 282 | const id = String(src.id || src.key || src.name || ''); |
| 283 | if (!id) return; |
| 284 | const name = String(src.name || id); |
| 285 | const type = String(src.type || ''); |
| 286 | const ro = src.readOnly ? ` \uD83D\uDD12 ${t('read_only')}` : ''; |
| 287 | const label = type ? `${name} (${type})${ro}` : `${name}${ro}`; |
| 288 | const opt = document.createElement('option'); |
| 289 | opt.value = id; |
| 290 | opt.textContent = label; |
no test coverage detected