diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ac959c5..23a7e5d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,17 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions-hub/stylelint@master - env: - PATTERN : 'web/css/*.css' \ No newline at end of file + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run stylelint + run: npx stylelint "web/css/*.css" \ No newline at end of file diff --git a/README.md b/README.md index 5c60def..11d683b 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ For example, by preparing the following CSV, you can quickly insert correspondin - **Max suggestions**: Maximum number of autocomplete suggestions to display. - **Auto-Insert Comma**: Automatically insert a comma after tags when inserting from autocomplete. - **Replace '_' with 'Space'**: Replaces underscores with spaces when inserting tags. This setting also affects related tag display. +- **String to add before artist tags**: Text to prepend when inserting an artist tag. For Anima models, specify `@`. - **Enable Loras and Embeddings**: Display Lora and Embedding in the suggestions. - **Use Fast Search**: Switch autocomplete suggestions search to fast processing (see [About Fast Search for Autocomplete](#about-fast-search-for-autocomplete) for details). diff --git a/docs/README_jp.md b/docs/README_jp.md index 1c44923..67e522d 100644 --- a/docs/README_jp.md +++ b/docs/README_jp.md @@ -167,6 +167,7 @@ worst_quality,5,9999999, - **Max Suggestions**: オートコンプリート候補の最大表示件数 - **Auto-Insert Comma**: タグの挿入時、末尾にカンマを追加する - **Replace '_' with 'Space'**: タグ挿入時にアンダースコアをスペースに置き換えます。この設定は関連タグ表示にも影響します +- **String to add before artist tags**: アーティストタグを挿入する際に付加する文字列。 Anima モデルの場合は「@」を指定します - **Enable Loras and Embeddings**: LoraとEmbeddingを候補に表示する - **Use Fast Search**: オートコンプリート候補の検索を高速な処理に切り替える(詳細は [オートコンプリートの高速検索について](#オートコンプリートの高速検索について) を確認してください) diff --git a/locales/en/settings.json b/locales/en/settings.json index 25a33cc..4e469ed 100644 --- a/locales/en/settings.json +++ b/locales/en/settings.json @@ -31,6 +31,10 @@ "AutocompletePlus_Autocompletion_EnableModels": { "name": "Enable Loras and Embeddings" }, + "AutocompletePlus_Autocompletion_PrefixArtist": { + "name": "String to add before artist tags", + "tooltip": "Text to prepend when inserting an artist tag via autocomplete.\ne.g. '@' -> '@artist_name'." + }, "AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": { "name": "Replace '_' with 'Space'", "tooltip": "This setting also affects related tags display." diff --git a/locales/ja/settings.json b/locales/ja/settings.json index b163286..2d79f31 100644 --- a/locales/ja/settings.json +++ b/locales/ja/settings.json @@ -31,6 +31,10 @@ "AutocompletePlus_Autocompletion_EnableModels": { "name": "LoraとEmbeddingを候補に表示する" }, + "AutocompletePlus_Autocompletion_PrefixArtist": { + "name": "アーティストタグの前に追加する文字列", + "tooltip": "オートコンプリートからアーティストタグを挿入する際に付加する文字列。\n例: '@' -> '@artist_name'" + }, "AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": { "name": "'_' を 'スペース' に置き換える", "tooltip": "この設定は関連タグ表示にも影響します" diff --git a/locales/zh-TW/settings.json b/locales/zh-TW/settings.json index b4b406c..b4f3858 100644 --- a/locales/zh-TW/settings.json +++ b/locales/zh-TW/settings.json @@ -31,6 +31,10 @@ "AutocompletePlus_Autocompletion_EnableModels": { "name": "顯示Lora和Embedding" }, + "AutocompletePlus_Autocompletion_PrefixArtist": { + "name": "在藝術家標籤前添加的字串", + "tooltip": "透過自動完成插入藝術家標籤時,在標籤前添加的文字。\n例: '@' -> '@artist_name'" + }, "AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": { "name": "將'_'替換為'空格'", "tooltip": "此設定也會影響相關標籤顯示" diff --git a/locales/zh/settings.json b/locales/zh/settings.json index 287b1f4..8017344 100644 --- a/locales/zh/settings.json +++ b/locales/zh/settings.json @@ -31,6 +31,10 @@ "AutocompletePlus_Autocompletion_EnableModels": { "name": "显示Lora和Embedding" }, + "AutocompletePlus_Autocompletion_PrefixArtist": { + "name": "在艺术家标签前添加的字符串", + "tooltip": "通过自动完成插入艺术家标签时,在标签前添加的文本。\n例: '@' -> '@artist_name'" + }, "AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": { "name": "将'_'替换为'空格'", "tooltip": "此设置也会影响相关标签显示" diff --git a/web/js/autocomplete.js b/web/js/autocomplete.js index 5c86a20..f87f680 100644 --- a/web/js/autocomplete.js +++ b/web/js/autocomplete.js @@ -351,11 +351,13 @@ function insertTagToTextArea(inputElement, tagDataToInsert) { const needsSpaceBefore = text[replaceStart - 1] === ','; const prefix = needsSpaceBefore ? ' ' : ''; + const prefixArtist = tagDataToInsert.categoryText == 'artist' ? settingValues.prefixArtist : ''; + // Standard separator (comma + space, or empty if autoInsertComma is disabled) const needsSuffixAfter = !",:".includes(text[replaceEnd]); // TODO: If ":" is part of the emoticon, a suffix is ​​required (e.g. ":o") const suffix = (needsSuffixAfter && settingValues.autoInsertComma) ? ', ' : ''; - const textToInsertWithAffixes = prefix + normalizedTag + suffix; + const textToInsertWithAffixes = prefix + prefixArtist + normalizedTag + suffix; // --- Use execCommand for Undo support --- // 1. Select the text range to be replaced @@ -939,6 +941,25 @@ export class AutocompleteEventHandler { constructor() { this.autocompleteUI = new AutocompleteUI(); this.keyDownWithModifier = new Map(); // Keep track of keydown events with modifiers + this._debounceTimer = null; // Timer ID for debounced search + } + + /** + * Calls autocompleteUI.updateDisplay() with debounce for sequential search, or immediately for fast search. + * @param {HTMLTextAreaElement} target + */ + _triggerUpdateDisplay(target) { + if (settingValues.useFastSearch || settingValues.searchDebounceTime <= 0) { + // FastSearch or debounce disabled: immediate update + this.autocompleteUI.updateDisplay(target); + } else { + // Sequential search: debounced update + clearTimeout(this._debounceTimer); + this._debounceTimer = setTimeout(() => { + this.autocompleteUI.updateDisplay(target); + this._debounceTimer = null; + }, settingValues.searchDebounceTime); + } } /** @@ -952,6 +973,7 @@ export class AutocompleteEventHandler { const partialTag = getCurrentPartialTag(event.target); if (partialTag.length <= 0) { + clearTimeout(this._debounceTimer); // Cancel pending debounced search this.autocompleteUI.hide(); } } @@ -1062,7 +1084,7 @@ export class AutocompleteEventHandler { // and default action is not prevented, update the display. // This will typically be for character inputs, Delete, Backspace or IME composition. if (!event.defaultPrevented) { - this.autocompleteUI.updateDisplay(event.target); + this._triggerUpdateDisplay(event.target); } } diff --git a/web/js/main.js b/web/js/main.js index 4673fa5..db81ecf 100644 --- a/web/js/main.js +++ b/web/js/main.js @@ -50,16 +50,19 @@ function initializeEventHandlers() { ComfyWidgets.STRING = function (node, inputName, inputData, appInstance) { // Use appInstance to avoid conflict with global app const result = originalStringWidget.apply(this, arguments); - // Check if the widget has an inputEl and if it's a TEXTAREA + // Check if the widget has an element and if it's a TEXTAREA // This is to ensure we are targeting multiline text inputs, related to '.comfy-multiline-input' - if (result && result.widget - && result.widget.inputEl && result.widget.inputEl.tagName === 'TEXTAREA' && !result.widget.inputEl.readOnly) { - const widgetConfig = inputData && inputData[1] ? inputData[1] : {}; - // Future: Add checks for Autocomplete Plus specific configurations if needed - // e.g., if (widgetConfig["AutocompletePlus.enabled"] === false) return result; - - const nodeInfo = new NodeInfo(node.comfyClass || node.constructor.name, inputName); - attachListeners(result.widget.inputEl, nodeInfo); + if (result && result.widget) { + // fallback for older Comfyui frontend versions + const inputEl = result.widget.element ?? result.widget.inputEl; + if (inputEl && inputEl.tagName === 'TEXTAREA' && !inputEl.readOnly) { + const widgetConfig = inputData && inputData[1] ? inputData[1] : {}; + // Future: Add checks for Autocomplete Plus specific configurations if needed + // e.g., if (widgetConfig["AutocompletePlus.enabled"] === false) return result; + + const nodeInfo = new NodeInfo(node.comfyClass || node.constructor.name, inputName); + attachListeners(inputEl, nodeInfo); + } } return result; }; @@ -377,6 +380,17 @@ app.registerExtension({ settingValues.enableModels = newVal; } }, + { + id: id + ".Autocompletion.PrefixArtist", + name: "String to add before artist tags", + tooltip: "Text to prepend when inserting an artist tag via autocomplete.\ne.g. '@' -> '@artist_name'.", + type: "text", + defaultValue: '', + category: [name, "Autocompletion", "String to add before artist tags"], + onChange: (newVal, oldVal) => { + settingValues.prefixArtist = newVal; + } + }, { id: id + ".Autocompletion.ReplaceUnderscoreWithSpace", name: "Replace '_' with 'Space'", @@ -535,4 +549,4 @@ app.registerExtension({ }, }, ] -}); \ No newline at end of file +}); diff --git a/web/js/settings.js b/web/js/settings.js index 726fc79..cbd47ef 100644 --- a/web/js/settings.js +++ b/web/js/settings.js @@ -10,7 +10,9 @@ export const settingValues = { enableModels: true, // Enable Lora and Embedding suggestions useFastSearch: false, replaceUnderscoreWithSpace: true, // Replace underscores with spaces in tag insertion + prefixArtist: '', // Prefix to be attached before artist tags autoInsertComma: true, + searchDebounceTime: 100, // Sequential search debounce time in milliseconds // Related tags feature settings enableRelatedTags: true,