OpenRouter: match both id/text in select2 (#4237) * OpenRouter: match both id/text in select2 * Update public/scripts/utils.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed| @@ -61,6 +61,7 @@ import { | |||
| 61 | parseJsonFile, | 61 | parseJsonFile, |
| 62 | resetScrollHeight, | 62 | resetScrollHeight, |
| 63 | stringFormat, | 63 | stringFormat, |
| 64 | textValueMatcher, | ||
| 64 | uuidv4, | 65 | uuidv4, |
| 65 | } from './utils.js'; | 66 | } from './utils.js'; |
| 66 | import { countTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js'; | 67 | import { countTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js'; |
| @@ -6348,6 +6349,7 @@ export function initOpenAI() { | |||
| 6348 | searchInputCssClass: 'text_pole', | 6349 | searchInputCssClass: 'text_pole', |
| 6349 | width: '100%', | 6350 | width: '100%', |
| 6350 | templateResult: getOpenRouterModelTemplate, | 6351 | templateResult: getOpenRouterModelTemplate, |
| 6352 | matcher: textValueMatcher, | ||
| 6351 | }); | 6353 | }); |
| 6352 | $('#model_aimlapi_select').select2({ | 6354 | $('#model_aimlapi_select').select2({ |
| 6353 | placeholder: t`Select a model`, | 6355 | placeholder: t`Select a model`, |
| @@ -7,7 +7,7 @@ import { renderTemplateAsync } from './templates.js'; | |||
| 7 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; | 7 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; |
| 8 | import { t } from './i18n.js'; | 8 | import { t } from './i18n.js'; |
| 9 | import { accountStorage } from './util/AccountStorage.js'; | 9 | import { accountStorage } from './util/AccountStorage.js'; |
| 10 | import { localizePagination, PAGINATION_TEMPLATE } from './utils.js'; | 10 | import { localizePagination, PAGINATION_TEMPLATE, textValueMatcher } from './utils.js'; |
| 11 | 11 | ||
| 12 | let mancerModels = []; | 12 | let mancerModels = []; |
| 13 | let togetherModels = []; | 13 | let togetherModels = []; |
| @@ -1005,6 +1005,7 @@ export function initTextGenModels() { | |||
| 1005 | searchInputCssClass: 'text_pole', | 1005 | searchInputCssClass: 'text_pole', |
| 1006 | width: '100%', | 1006 | width: '100%', |
| 1007 | templateResult: getOpenRouterModelTemplate, | 1007 | templateResult: getOpenRouterModelTemplate, |
| 1008 | matcher: textValueMatcher, | ||
| 1008 | }); | 1009 | }); |
| 1009 | $('#vllm_model').select2({ | 1010 | $('#vllm_model').select2({ |
| 1010 | placeholder: t`Select a model`, | 1011 | placeholder: t`Select a model`, |
| @@ -2483,3 +2483,53 @@ export function clearInfoBlock(target) { | |||
| 2483 | infoBlock.innerHTML = ''; | 2483 | infoBlock.innerHTML = ''; |
| 2484 | } | 2484 | } |
| 2485 | } | 2485 | } |
| 2486 | |||
| 2487 | /** | ||
| 2488 | * Provides a matcher function for select2 that matches both the text and value of options. | ||
| 2489 | * @param {import('select2').SearchOptions} params | ||
| 2490 | * @param {import('select2').OptGroupData|import('select2').OptionData} data | ||
| 2491 | * @return {import('select2').OptGroupData|import('select2').OptionData|null} | ||
| 2492 | */ | ||
| 2493 | export function textValueMatcher(params, data) { | ||
| 2494 | // Always return the object if there is nothing to compare | ||
| 2495 | if (params.term == null || params.term.trim() === '') { | ||
| 2496 | return data; | ||
| 2497 | } | ||
| 2498 | |||
| 2499 | // Do a recursive check for options with children | ||
| 2500 | if (data.children && data.children.length > 0) { | ||
| 2501 | // Clone the data object if there are children | ||
| 2502 | // This is required as we modify the object to remove any non-matches | ||
| 2503 | const match = $.extend(true, {}, data); | ||
| 2504 | |||
| 2505 | // Check each child of the option | ||
| 2506 | for (let c = data.children.length - 1; c >= 0; c--) { | ||
| 2507 | const child = data.children[c]; | ||
| 2508 | |||
| 2509 | const matches = textValueMatcher(params, child); | ||
| 2510 | |||
| 2511 | // If there wasn't a match, remove the object in the array | ||
| 2512 | if (matches == null) { | ||
| 2513 | match.children.splice(c, 1); | ||
| 2514 | } | ||
| 2515 | } | ||
| 2516 | |||
| 2517 | // If any children matched, return the new object | ||
| 2518 | if (match.children.length > 0) { | ||
| 2519 | return match; | ||
| 2520 | } | ||
| 2521 | |||
| 2522 | // If there were no matching children, check just the plain object | ||
| 2523 | return textValueMatcher(params, match); | ||
| 2524 | } | ||
| 2525 | |||
| 2526 | const textMatch = compareIgnoreCaseAndAccents(data.text, params.term, (a, b) => a.indexOf(b) > -1); | ||
| 2527 | const valueMatch = data.element instanceof HTMLOptionElement && compareIgnoreCaseAndAccents(data.element.value, params.term, (a, b) => a.indexOf(b) > -1); | ||
| 2528 | |||
| 2529 | if (textMatch || valueMatch) { | ||
| 2530 | return data; | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | // If it doesn't contain the term, don't return anything | ||
| 2534 | return null; | ||
| 2535 | } | ||