// connection-ui.js // Public API: // injectConnectionUI({ afterTrId, groupId?, selectId?, defaultType?, idSuffix?, onTypeChange? }) // // All variable names and comments are in English. // It generates the connection type UI rows and handles basic show/hide behavior. export const varConnectionUI = { permission_all_urls: false } export function injectConnectionUI({ afterTrId = '', selectId = '', no_chatgpt_web = false, defaultType = '', tr_class = '', } = {}) { const anchorTr = document.getElementById(afterTrId); if (!anchorTr) { console.error(`[ThuderAI | injectConnectionUI] Can't find tr#${afterTrId}`); return null; } let tpl = ` __MSG_OpenChatGPTTab_Info__



__MSG_OpenChatGPTTab_Info2__
__MSG_Loading__
__MSG_Loading__
__MSG_remember_CORS__ [__MSG_more_info_string__]

__MSG_CORS_alternative_1__
__MSG_CORS_alternative_2__

__MSG_Loading__
__MSG_maybe_CORS_openai_comp__ [__MSG_more_info_string__]

__MSG_CORS_alternative_1__
__MSG_CORS_alternative_2__

__MSG_Loading__
__MSG_Loading__
__MSG_prefs_OptionText_anthropic_max_tokens__ `; const template = document.createElement('template'); template.innerHTML = tpl.trim(); const frag = template.content; const parent = anchorTr.parentElement; const nodes = Array.from(frag.childNodes); let last = anchorTr; nodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { parent.insertBefore(node, last.nextSibling); last = node; } }); // Bindings const bindClick = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('click', cb); }; const bindChange = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('change', cb); }; const bindInput = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('input', cb); }; populateConnectionTypeOptions(selectId, no_chatgpt_web); let selectEl = document.getElementById(selectId); if (!selectEl) { console.error('[ThuderAI | injectConnectionUI] Select not found after insertion.'); } const bindPasswordToggle = (idBase) => { const input = document.getElementById(idBase); const toggler = document.getElementById(`toggle_\${idBase}`); const icon = document.getElementById(`pwd-icon_\${idBase}`); if (!input || !toggler) return; toggler.addEventListener('click', () => { input.type = input.type === 'password' ? 'text' : 'password'; if (icon) icon.src = input.type === 'password' ? '/images/pwd-show.png' : '/images/pwd-hide.png'; }); }; bindPasswordToggle('chatgpt_api_key'); bindPasswordToggle('google_gemini_api_key'); bindPasswordToggle('openai_comp_api_key'); bindPasswordToggle('anthropic_api_key'); // Live warnings and enable/disable logic const applyLiveWarnings = () => { // ChatGPT API const chatgptKey = document.getElementById('chatgpt_api_key'); const btnChatGPT = document.getElementById('btnUpdateChatGPTModels'); const selChatGPT = document.getElementById('chatgpt_model'); if (chatgptKey && btnChatGPT && selChatGPT) { const empty = !chatgptKey.value; chatgptKey.style.border = empty ? '2px solid red' : ''; btnChatGPT.disabled = !!empty; selChatGPT.disabled = !!empty; if (!empty) { selChatGPT.style.border = (!selChatGPT.value || selChatGPT.selectedIndex === -1) ? '2px solid red' : ''; } else { selChatGPT.style.border = ''; } } // Google Gemini API const geminiKey = document.getElementById('google_gemini_api_key'); const btnGemini = document.getElementById('btnUpdateGoogleGeminiModels'); const selGemini = document.getElementById('google_gemini_model'); if (geminiKey && btnGemini && selGemini) { const empty = !geminiKey.value; geminiKey.style.border = empty ? '2px solid red' : ''; btnGemini.disabled = !!empty; selGemini.disabled = !!empty; if (!empty) { selGemini.style.border = (!selGemini.value || selGemini.selectedIndex === -1) ? '2px solid red' : ''; } else { selGemini.style.border = ''; } } // Ollama API const ollamaHost = document.getElementById('ollama_host'); const btnOllama = document.getElementById('btnUpdateOllamaModels'); const selOllama = document.getElementById('ollama_model'); if (ollamaHost && btnOllama && selOllama) { const empty = !ollamaHost.value; ollamaHost.style.border = empty ? '2px solid red' : ''; btnOllama.disabled = !!empty; selOllama.disabled = !!empty; if (!empty) { selOllama.style.border = (!selOllama.value || selOllama.selectedIndex === -1) ? '2px solid red' : ''; } else { selOllama.style.border = ''; } } // OpenAI-Compatible API const openaiCompHost = document.getElementById('openai_comp_host'); const btnOpenAIComp = document.getElementById('btnUpdateOpenAICompModels'); const selOpenAIComp = document.getElementById('openai_comp_model'); if (openaiCompHost && btnOpenAIComp && selOpenAIComp) { const empty = !openaiCompHost.value; openaiCompHost.style.border = empty ? '2px solid red' : ''; btnOpenAIComp.disabled = !!empty; selOpenAIComp.disabled = !!empty; if (!empty) { selOpenAIComp.style.border = (!selOpenAIComp.value || selOpenAIComp.selectedIndex === -1) ? '2px solid red' : ''; } else { selOpenAIComp.style.border = ''; } } // Anthropic API const anthropicKey = document.getElementById('anthropic_api_key'); const btnAnthropic = document.getElementById('btnUpdateAnthropicModels'); const selAnthropic = document.getElementById('anthropic_model'); const anthropicVersion = document.getElementById('anthropic_version'); if (anthropicKey && selAnthropic) { const emptyKey = !anthropicKey.value; anthropicKey.style.border = emptyKey ? '2px solid red' : ''; if (btnAnthropic) btnAnthropic.disabled = !!emptyKey; if (selAnthropic) selAnthropic.disabled = !!emptyKey; if (!emptyKey && selAnthropic) { selAnthropic.style.border = (!selAnthropic.value || selAnthropic.selectedIndex === -1) ? '2px solid red' : ''; } else if (selAnthropic) { selAnthropic.style.border = ''; } } if (anthropicVersion) { const emptyVer = !anthropicVersion.value; anthropicVersion.style.border = emptyVer ? '2px solid red' : ''; } }; // Bind inputs to live warnings bindInput('chatgpt_api_key', applyLiveWarnings); bindInput('google_gemini_api_key', applyLiveWarnings); bindInput('ollama_host', applyLiveWarnings); bindInput('openai_comp_host', applyLiveWarnings); bindInput('anthropic_api_key', applyLiveWarnings); bindInput('anthropic_version', applyLiveWarnings); bindChange('chatgpt_model', applyLiveWarnings); bindChange('google_gemini_model', applyLiveWarnings); bindChange('ollama_model', applyLiveWarnings); bindChange('openai_comp_model', applyLiveWarnings); bindChange('anthropic_model', applyLiveWarnings); // Run once on init applyLiveWarnings(); // Bind button clicks to provided callbacks (page-specific logic stays outside) // bindClick('btnChatGPTWeb_Tab', onOpenChatGPTWebTab); // bindClick('btnUpdateChatGPTModels', onFetchChatGPTModels); // bindClick('btnUpdateGoogleGeminiModels', onFetchGoogleGeminiModels); // bindClick('btnUpdateOllamaModels', onFetchOllamaModels); // bindClick('btnUpdateOpenAICompModels', onFetchOpenAICompModels); // bindClick('btnOpenAICompForceModel', onOpenAICompForceModel); // bindClick('btnOpenAICompClearModelsList', onOpenAICompClearModelsList); // bindClick('btnUpdateAnthropicModels', onFetchAnthropicModels); // bindClick('btnGiveAllUrlsPermission_ollama_api', onGiveAllUrlsPermissionOllama); // bindClick('btnGiveAllUrlsPermission_openai_comp_api', onGiveAllUrlsPermissionOpenAIComp); selectEl.addEventListener("change", () => showConnectionOptions(selectEl)); showConnectionOptions(selectEl); return { select: selectEl, onTypeChange: (fn) => { onTypeChange = fn; fn(selectEl.value, { select: selectEl }); } }; } function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { const selectEl = document.getElementById(selectId); if (!selectEl) return; const prevValue = selectEl.value; const options = [ { value: 'chatgpt_web', msgKey: 'prefs_Connection_type_ChatGPT_Web' }, { value: 'chatgpt_api', msgKey: 'prefs_Connection_type_ChatGPT_API' }, { value: 'google_gemini_api', msgKey: 'prefs_Connection_type_Google_Gemini_API' }, { value: 'anthropic_api', msgKey: 'prefs_Connection_type_Anthropic_API' }, { value: 'ollama_api', msgKey: 'prefs_Connection_type_Ollama_API' }, { value: 'openai_comp_api', msgKey: 'prefs_Connection_type_OpenAI_Comp_API' } ]; selectEl.innerHTML = ''; for (const opt of options.filter(o => !(no_chatgpt_web && o.value === 'chatgpt_web'))) { const optionEl = document.createElement('option'); optionEl.value = opt.value; optionEl.textContent = browser.i18n.getMessage(opt.msgKey) || opt.msgKey; selectEl.appendChild(optionEl); } if (options.some(o => o.value === prevValue)) { selectEl.value = prevValue; } } export function showConnectionOptions(conntype_select) { let chatgpt_web_display = 'table-row'; let chatgpt_api_display = 'none'; let ollama_api_display = 'none'; let openai_comp_api_display = 'none'; let google_gemini_api_display = 'none'; let anthropic_api_display = 'none'; let parent = conntype_select.parentElement.parentElement.parentElement; parent.classList.toggle("conntype_chatgpt_web", (conntype_select.value === "chatgpt_web")); parent.classList.toggle("conntype_chatgpt_api", (conntype_select.value === "chatgpt_api")); parent.classList.toggle("conntype_ollama_api", (conntype_select.value === "ollama_api")); parent.classList.toggle("conntype_openai_comp_api", (conntype_select.value === "openai_comp_api")); parent.classList.toggle("conntype_google_gemini_api", (conntype_select.value === "google_gemini_api")); parent.classList.toggle("conntype_anthropic_api", (conntype_select.value === "anthropic_api")); if (conntype_select.value === "chatgpt_web") { chatgpt_web_display = 'table-row'; }else{ chatgpt_web_display = 'none'; } if (conntype_select.value === "chatgpt_api") { chatgpt_api_display = 'table-row'; }else{ chatgpt_api_display = 'none'; } if (conntype_select.value === "ollama_api") { ollama_api_display = 'table-row'; }else{ ollama_api_display = 'none'; } if (conntype_select.value === "openai_comp_api") { openai_comp_api_display = 'table-row'; }else{ openai_comp_api_display = 'none'; } if (conntype_select.value === "google_gemini_api") { google_gemini_api_display = 'table-row'; }else{ google_gemini_api_display = 'none'; } if (conntype_select.value === "anthropic_api") { anthropic_api_display = 'table-row'; }else{ anthropic_api_display = 'none'; } document.querySelectorAll(".conntype_chatgpt_web").forEach(element => { element.style.display = chatgpt_web_display; }); document.querySelectorAll(".conntype_chatgpt_api").forEach(element => { element.style.display = chatgpt_api_display; }); document.querySelectorAll(".conntype_ollama_api").forEach(element => { element.style.display = ollama_api_display; }); document.querySelectorAll(".conntype_openai_comp_api").forEach(element => { element.style.display = openai_comp_api_display; }); document.querySelectorAll(".conntype_google_gemini_api").forEach(element => { element.style.display = google_gemini_api_display; }); document.querySelectorAll(".conntype_anthropic_api").forEach(element => { element.style.display = anthropic_api_display; }); if (varConnectionUI.permission_all_urls) { document.getElementById('openai_comp_api_cors_warning').style.display = 'none'; document.getElementById('ollama_api_cors_warning').style.display = 'none'; } }