diff --git a/public/scripts/extensions/quick-reply/api/QuickReplyApi.js b/public/scripts/extensions/quick-reply/api/QuickReplyApi.js index acb877dd3..15ff1d4da 100644 --- a/public/scripts/extensions/quick-reply/api/QuickReplyApi.js +++ b/public/scripts/extensions/quick-reply/api/QuickReplyApi.js @@ -6,6 +6,7 @@ import { QuickReplySet } from '../src/QuickReplySet.js'; import { QuickReplySettings } from '../src/QuickReplySettings.js'; // eslint-disable-next-line no-unused-vars import { SettingsUi } from '../src/ui/SettingsUi.js'; +import { onlyUnique } from '../../../utils.js'; export class QuickReplyApi { /**@type {QuickReplySettings}*/ settings; @@ -460,4 +461,20 @@ export class QuickReplyApi { } return set.qrList.map(it=>it.label); } + + /** + * Gets a list of all Automation IDs used by quick replies. + * + * @returns {String[]} array with all automation IDs used by quick replies + */ + listAutomationIds() { + return this + .listSets() + .flatMap(it => ({ set: it, qrs: this.listQuickReplies(it) })) + .map(it => it.qrs?.map(qr => this.getQrByLabel(it.set, qr)?.automationId)) + .flat() + .filter(Boolean) + .filter(onlyUnique) + .map(String); + } } diff --git a/public/scripts/extensions/quick-reply/index.js b/public/scripts/extensions/quick-reply/index.js index 8e6cd1a2c..a032a12d6 100644 --- a/public/scripts/extensions/quick-reply/index.js +++ b/public/scripts/extensions/quick-reply/index.js @@ -200,6 +200,8 @@ const init = async () => { autoExec = new AutoExecuteHandler(settings); eventSource.on(event_types.APP_READY, async()=>await finalizeInit()); + + window['quickReplyApi'] = quickReplyApi; }; const finalizeInit = async () => { log('executing startup'); diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js index 9b4a2e5b7..9c8295027 100644 --- a/public/scripts/world-info.js +++ b/public/scripts/world-info.js @@ -1286,7 +1286,7 @@ function getWorldEntry(name, data, entry) { saveWorldInfo(name, data); }); groupInput.val(entry.group ?? '').trigger('input'); - setTimeout(() => createInclusionGroupAutocomplete(groupInput, data), 1); + setTimeout(() => createEntryInputAutocomplete(groupInput, getInclusionGroupCallback(data)), 1); // probability if (entry.probability === undefined) { @@ -1586,6 +1586,7 @@ function getWorldEntry(name, data, entry) { saveWorldInfo(name, data); }); automationIdInput.val(entry.automationId ?? '').trigger('input'); + setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1); template.find('.inline-drawer-content').css('display', 'none'); //entries start collapsed @@ -1617,12 +1618,12 @@ function getWorldEntry(name, data, entry) { } /** - * Create an autocomplete for the inclusion group. - * @param {JQuery} input Input element to attach the autocomplete to + * Get the inclusion groups for the autocomplete. * @param {any} data WI data + * @returns {(input: any, output: any) => any} Callback function for the autocomplete */ -function createInclusionGroupAutocomplete(input, data) { - function getGroups(input, output) { +function getInclusionGroupCallback(data) { + return function(input, output) { const groups = new Set(); for (const entry of Object.values(data.entries)) { if (entry.group) { @@ -1641,17 +1642,54 @@ function createInclusionGroupAutocomplete(input, data) { } output(result); - } + }; +} +function getAutomationIdCallback(data) { + return function(input, output) { + const ids = new Set(); + for (const entry of Object.values(data.entries)) { + if (entry.automationId) { + ids.add(String(entry.automationId)); + } + } + + if ('quickReplyApi' in window) { + // @ts-ignore + for (const automationId of window['quickReplyApi'].listAutomationIds()) { + ids.add(String(automationId)); + } + } + + const haystack = Array.from(ids); + haystack.sort((a, b) => a.localeCompare(b)); + const needle = input.term.toLowerCase(); + const hasExactMatch = haystack.findIndex(x => x.toLowerCase() == needle) !== -1; + const result = haystack.filter(x => x.toLowerCase().includes(needle)); + + if (input.term && !hasExactMatch) { + result.unshift(input.term); + } + + output(result); + }; +} + +/** + * Create an autocomplete for the inclusion group. + * @param {JQuery} input Input element to attach the autocomplete to + * @param {(input: any, output: any) => any} callback Source data callbacks + */ +function createEntryInputAutocomplete(input, callback) { $(input).autocomplete({ minLength: 0, - source: getGroups, + source: callback, select: function (event, ui) { $(input).val(ui.item.value).trigger('input').trigger('blur'); }, }); - $(input).on('focus', function () { + $(input).on('focus click', function () { $(input).autocomplete('search', String($(input).val())); }); } @@ -2886,7 +2924,7 @@ jQuery(() => { } $('#WorldInfo').on('scroll', () => { - $('.world_entry input[name="group"]').each((_, el) => { + $('.world_entry input[name="group"], .world_entry input[name="automationId"]').each((_, el) => { const instance = $(el).autocomplete('instance'); if (instance !== undefined) {