Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- uses: actions-hub/stylelint@master
env:
PATTERN : 'web/css/*.css'
- 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"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down
1 change: 1 addition & 0 deletions docs/README_jp.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**: オートコンプリート候補の検索を高速な処理に切り替える(詳細は [オートコンプリートの高速検索について](#オートコンプリートの高速検索について) を確認してください)

Expand Down
4 changes: 4 additions & 0 deletions locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
4 changes: 4 additions & 0 deletions locales/ja/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"AutocompletePlus_Autocompletion_EnableModels": {
"name": "LoraとEmbeddingを候補に表示する"
},
"AutocompletePlus_Autocompletion_PrefixArtist": {
"name": "アーティストタグの前に追加する文字列",
"tooltip": "オートコンプリートからアーティストタグを挿入する際に付加する文字列。\n例: '@' -> '@artist_name'"
},
"AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": {
"name": "'_' を 'スペース' に置き換える",
"tooltip": "この設定は関連タグ表示にも影響します"
Expand Down
4 changes: 4 additions & 0 deletions locales/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"AutocompletePlus_Autocompletion_EnableModels": {
"name": "顯示Lora和Embedding"
},
"AutocompletePlus_Autocompletion_PrefixArtist": {
"name": "在藝術家標籤前添加的字串",
"tooltip": "透過自動完成插入藝術家標籤時,在標籤前添加的文字。\n例: '@' -> '@artist_name'"
},
"AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": {
"name": "將'_'替換為'空格'",
"tooltip": "此設定也會影響相關標籤顯示"
Expand Down
4 changes: 4 additions & 0 deletions locales/zh/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"AutocompletePlus_Autocompletion_EnableModels": {
"name": "显示Lora和Embedding"
},
"AutocompletePlus_Autocompletion_PrefixArtist": {
"name": "在艺术家标签前添加的字符串",
"tooltip": "通过自动完成插入艺术家标签时,在标签前添加的文本。\n例: '@' -> '@artist_name'"
},
"AutocompletePlus_Autocompletion_ReplaceUnderscoreWithSpace": {
"name": "将'_'替换为'空格'",
"tooltip": "此设置也会影响相关标签显示"
Expand Down
26 changes: 24 additions & 2 deletions web/js/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

/**
Expand All @@ -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();
}
}
Expand Down Expand Up @@ -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);
}
}

Expand Down
34 changes: 24 additions & 10 deletions web/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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'",
Expand Down Expand Up @@ -535,4 +549,4 @@ app.registerExtension({
},
},
]
});
});
2 changes: 2 additions & 0 deletions web/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down