Compare commits

...
13 Commits
Author SHA1 Message Date
newtextdoc1111 57f80f0991 Merge pull request #22 from newtextdoc1111/feature/#21-add_tag_alias_to_header
Feature/#21 add tag alias to related tags display header
2025-06-14 17:48:14 +09:00
newtextdoc1111 31f8fe4517 fix: Update version to 1.1.0 in pyproject.toml 2025-06-14 17:44:32 +09:00
newtextdoc1111 292c99ae17 fix: Remove unused CSS classes for related tags layout 2025-06-10 04:10:08 +09:00
newtextdoc1111 86b63047c2 feat: Add tag aliases to related tags display 2025-06-10 04:05:22 +09:00
newtextdoc1111 5e4b4fae04 Merge pull request #20 from newtextdoc1111/dev
Merge Dev
2025-05-29 18:07:45 +09:00
newtextdoc1111 7a73a5b1b3 fix: Bump version to 1.0.2 in pyproject.toml 2025-05-29 17:59:07 +09:00
newtextdoc1111 47635d5aea docs: Update user CSV instructions with naming conventions and console log details 2025-05-29 17:52:09 +09:00
newtextdoc1111 4415e22744 fix: Log CSV file status in ComfyUI console and browser network tab 2025-05-29 17:51:50 +09:00
newtextdoc1111 939569d076 Merge pull request #18 from newtextdoc1111/dev
Merge Dev
2025-05-27 20:31:40 +09:00
newtextdoc1111 c8820c89d1 fix: Bump version to 1.0.1 in pyproject.toml 2025-05-27 20:21:40 +09:00
newtextdoc1111 d97900de4e fix: Adjust item highlighting timing in autocomplete and related tags UI (#17) 2025-05-27 20:21:30 +09:00
newtextdoc1111 8c54defc6c Merge pull request #16 from newtextdoc1111/dev
Merge Dev
2025-05-25 16:56:06 +09:00
newtextdoc1111 74565b442f docs: Update installation instructions and enhance tag selection description in README files 2025-05-25 16:53:52 +09:00
8 changed files with 282 additions and 195 deletions
+22 -3
View File
@@ -28,11 +28,16 @@
## Installation
### ComfyUI-Manager
1. Search for `Autocomplete-Plus` in [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager), install the custom node that appears, and restart.
2. The necessary CSV data will be automatically downloaded from HuggingFace upon startup.
### Manual
1. Clone or copy this repository into the `custom_nodes` folder of ComfyUI.
`git clone https://github.com/newtextdoc1111/ComfyUI-Autocomplete-Plus.git`
2. Launch ComfyUI. The necessary CSV data will be automatically downloaded from HuggingFace on the first launch only.
2. Launch ComfyUI. The necessary CSV data will be automatically downloaded from HuggingFace upon startup.
## Autocomplete
@@ -47,7 +52,7 @@ When you type in a text input area, tags that partially match the text are displ
![ss02](https://github.com/user-attachments/assets/854571cd-01eb-4e92-a118-2303bec0b175)
When you select any tag in a text input area, highly related tags list are displayed. The UI's position and size are automatically adjusted based on the text area being edited.
When you select any tag in a text input area, a list of highly related tags is displayed. You can insert a tag by clicking it or by selecting it with the up/down arrow keys and then pressing Enter or Tab. The UI's position and size are automatically adjusted based on the text area being edited.
- The display position is primarily at the bottom of the text area and automatically adjusts vertically based on available space.
- You can switch between vertical and horizontal display positions using the "↕️|↔️" button in the header.
@@ -87,7 +92,12 @@ Also, displaying related tags is not supported.
### User CSV
Users can also use their own CSV files. For example, frequently used meta tags can be added to the autocomplete suggestions by placing a file named `danbooru_tags_meta.csv` in the `data` folder.
Users can also use their own CSV files. CSV files should be placed in the `data` folder according to the following naming convention:
- **CSV for Autocomplete**: `<danbooru | e621>_tags*.csv`
- **CSV for Related Tags**: `<danbooru | e621>_tags_cooccurrence*.csv`
For example, you can add frequently used meta tags to the autocomplete suggestions by placing a file named `danbooru_tags_meta.csv` in the `data` folder.
A header row is not required. A browser reload is necessary to apply the changes.
**Example of meta tags:**
@@ -101,6 +111,15 @@ low_quality,5,9999999,
worst_quality,5,9999999,
```
When the browser is reloaded, you can check the list of loaded CSV files in the ComfyUI console log. If a file is not included in the log output, please verify that the file name follows the naming convention.
**Example of ComfyUI console log output:**
```
[Autocomplete-Plus] CSV file status:
* Danbooru -> base: True, extra: danbooru_tags_meta.csv // If displayed here, meta tags can be autocompleted
* E621 -> base: False, extra:
```
>[!NOTE]
> If there are multiple user CSV files, they are loaded in alphabetical order. If the same tag exists in multiple files, the one loaded first is retained. The basic CSV is loaded last.
+22 -3
View File
@@ -26,11 +26,16 @@
## インストール
### ComfyUI-Manager
1. [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager) で `Autocomplete-Plus` と検索して表示されたカスタムノードをインストールし、再起動します
2. 起動時に必要な CSV データが HuggingFace から自動的にダウンロードされます
### マニュアル
1. このリポジトリを ComfyUI の `custom_nodes` フォルダにクローンまたはコピーします
`git clone https://github.com/newtextdoc1111/ComfyUI-Autocomplete-Plus.git`
3. ComfyUI を起動します。初回起動時のみ、必要な CSV データが HuggingFace から自動的にダウンロードされます
2. ComfyUI を起動します。起動時に必要な CSV データが HuggingFace から自動的にダウンロードされます
## オートコンプリート
@@ -45,7 +50,7 @@
![ss02](https://github.com/user-attachments/assets/854571cd-01eb-4e92-a118-2303bec0b175)
テキスト入力エリアの任意のタグを選択すると、関連性の高いタグを一覧表示します。UIは編集中のテキストエリアを基準に位置とサイズが自動で調整されます。
テキスト入力エリアの任意のタグを選択すると、関連性の高いタグを一覧表示します。タグをクリックするか、キーボードの上下キーで選択後にEnterまたはTabキーでタグを挿入出来ます。UIは編集中のテキストエリアを基準に位置とサイズが自動で調整されます。
- 表示位置は、テキストエリアの下部を基本とし、空きスペースに応じて上下に自動調整されます
- ヘッダーの「↕️|↔️」ボタンで上下と左右の表示位置に切り替えられます
@@ -85,7 +90,12 @@
### ユーザーCSV
ユーザーが自身で用意した CSV を使用することも可能です。例として、よく使うメタタグを `danbooru_tags_meta.csv` の名前で `data` フォルダーに配置することでオートコンプリート候補に追加できます。
ユーザーが自身で用意した CSV を使用することも可能です。 CSV ファイルは以下の命名規則に従って `data` フォルダーに配置してください。
- **オートコンプリート用 CSV**: <danbooru | e621>_tags*.csv
- **関連タグ用 CSV**: <danbooru | e621>_tags_cooccurrence*.csv
例として、よく使うメタタグを `danbooru_tags_meta.csv` の名前で `data` フォルダーに配置することでオートコンプリート候補に追加できます。
ヘッダー行はなくても構いません。反映にはブラウザのリロードが必要です。
**メタタグの例**
@@ -99,6 +109,15 @@ low_quality,5,9999999,
worst_quality,5,9999999,
```
ブラウザリロード時、ロードされる CSV ファイル一覧をComfyUIのコンソールのログで確認出来ます。ログ出力に含まれていない場合はファイル名が命名規則に沿っているか確認してください。
**ComfyUIコンソールログ出力の例:**
```
[Autocomplete-Plus] CSV file status:
* Danbooru -> base: True, extra: danbooru_tags_meta.csv // ここに表示されていればメタタグを入力補完できます
* E621 -> base: False, extra:
```
>[!NOTE]
> ユーザー CSV が複数ある場合アルファベット順に読み込まれます。同じタグが複数のファイルに存在する場合は先に読み込まれた方が保持されます。基本 CSV は最後にロードされます。
+10 -4
View File
@@ -103,17 +103,23 @@ async def get_csv_list(_request):
response = {
DANBOORU_PREFIX: {
'base_tags': csv_file_status[DANBOORU_PREFIX]['base_tags'],
'extra_tags': len(csv_file_status[DANBOORU_PREFIX]['extra_tags']),
'extra_tags': csv_file_status[DANBOORU_PREFIX]['extra_tags'],
'base_cooccurrence': csv_file_status[DANBOORU_PREFIX]['base_cooccurrence'],
'extra_cooccurrence': len(csv_file_status[DANBOORU_PREFIX]['extra_cooccurrence']),
'extra_cooccurrence': csv_file_status[DANBOORU_PREFIX]['extra_cooccurrence'],
},
E621_PREFIX: {
'base_tags': csv_file_status[E621_PREFIX]['base_tags'],
'extra_tags': len(csv_file_status[E621_PREFIX]['extra_tags']),
'extra_tags': csv_file_status[E621_PREFIX]['extra_tags'],
'base_cooccurrence': csv_file_status[E621_PREFIX]['base_cooccurrence'],
'extra_cooccurrence': len(csv_file_status[E621_PREFIX]['extra_cooccurrence']),
'extra_cooccurrence': csv_file_status[E621_PREFIX]['extra_cooccurrence'],
}
}
# Print csv file status to the console for debugging
print(f"""[Autocomplete-Plus] CSV file status:
* Danbooru -> base: {response[DANBOORU_PREFIX]['base_tags']}, extra: {", ".join(response[DANBOORU_PREFIX]['extra_tags'])}
* E621 -> base: {response[E621_PREFIX]['base_tags']}, extra: {", ".join(response[E621_PREFIX]['extra_tags'])}""")
return web.json_response(response)
@server.PromptServer.instance.routes.get('/autocomplete-plus/csv/{source}/{suffix}/base')
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-autocomplete-plus"
description = "Autocomplete and Related Tag display for ComfyUI"
version = "1.0.0"
version = "1.1.0"
license = {file = "LICENSE"}
dependencies = ["",]
+144 -147
View File
@@ -37,6 +37,62 @@ body.dark-theme {
color: var(--input-text);
}
#autocomplete-plus-root .danbooru[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-blue);
}
#autocomplete-plus-root .danbooru[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#autocomplete-plus-root .danbooru[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
#autocomplete-plus-root .danbooru[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
#autocomplete-plus-root .danbooru[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-yellow);
}
#autocomplete-plus-root .danbooru[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
#autocomplete-plus-root .e621[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-sky);
}
#autocomplete-plus-root .e621[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-orange);
}
#autocomplete-plus-root .e621[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
#autocomplete-plus-root .e621[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
#autocomplete-plus-root .e621[data-tag-category="species"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#autocomplete-plus-root .e621[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-white);
}
#autocomplete-plus-root .e621[data-tag-category="lore"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#autocomplete-plus-root .e621[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
#autocomplete-plus-list {
display: grid;
box-shadow: 0 2px 8px rgb(0 0 0 / 30%);
@@ -52,62 +108,6 @@ body.dark-theme {
grid-template-columns: subgrid;
}
.autocomplete-plus-item.danbooru[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-blue);
}
.autocomplete-plus-item.danbooru[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.autocomplete-plus-item.danbooru[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
.autocomplete-plus-item.danbooru[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
.autocomplete-plus-item.danbooru[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-yellow);
}
.autocomplete-plus-item.danbooru[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
.autocomplete-plus-item.e621[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-sky);
}
.autocomplete-plus-item.e621[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-orange);
}
.autocomplete-plus-item.e621[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
.autocomplete-plus-item.e621[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
.autocomplete-plus-item.e621[data-tag-category="species"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.autocomplete-plus-item.e621[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-white);
}
.autocomplete-plus-item.e621[data-tag-category="lore"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.autocomplete-plus-item.e621[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
.autocomplete-plus-item span {
align-content: center;
padding: 4px 8px;
@@ -124,11 +124,7 @@ body.dark-theme {
}
.autocomplete-plus-item.selected span {
background-color: var(
--comfy-menu-bg-selected,
var(--comfy-button-bg)
);
font-weight: bold;
background-color: var(--border-color);
}
.autocomplete-plus-item:hover span {
@@ -172,26 +168,91 @@ body.dark-theme {
color: var(--input-text);
}
#related-tags-root .danbooru[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-blue);
}
#related-tags-root .danbooru[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#related-tags-root .danbooru[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
#related-tags-root .danbooru[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
#related-tags-root .danbooru[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-yellow);
}
#related-tags-root .danbooru[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
#related-tags-root .e621[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-sky);
}
#related-tags-root .e621[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-orange);
}
#related-tags-root .e621[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
#related-tags-root .e621[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
#related-tags-root .e621[data-tag-category="species"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#related-tags-root .e621[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-white);
}
#related-tags-root .e621[data-tag-category="lore"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
#related-tags-root .e621[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
#related-tags-header {
position: sticky;
z-index: 1;
top: 0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
padding: 8px;
border-bottom: 1px solid var(--border-color);
background-color: var(--comfy-menu-bg);
color: var(--descrip-text);
gap: 8px;
}
.related-tags-header-text {
flex-grow: 1;
.related-tags-header-text-container {
display:flex;
flex: 1;
flex-wrap: wrap;
align-items: center;
gap: 12px;
}
.related-tags-header-tag-text {
padding: 2px 0;
line-height: 1.25em;
}
.related-tags-header-tag-name {
font-weight: bold;
word-break: break-all;
}
.related-tags-header-tag-name .autocomplete-plus-tag-icon-svg {
@@ -200,17 +261,22 @@ body.dark-theme {
vertical-align: middle;
}
.related-tags-header-tag-alias {
overflow: auto;
max-height: 5em;
padding: 2px 4px;
border-radius: 4px;
background-color: var(--bg-color);
color: var(--descrip-text);
line-height: 1.25em;
}
.related-tags-header-controls {
display: flex;
align-items: center;
margin-left: 16px;
gap: 4px;
margin-left: auto;
}
.related-tags-layout-toggle {
padding: 2px 6px;
.related-tags-header-controls button {
border: none;
border-radius: 4px;
background: none;
color: var(--input-text);
cursor: pointer;
@@ -218,19 +284,8 @@ body.dark-theme {
transition: background-color 0.2s;
}
.related-tags-layout-toggle:hover {
background-color: var(--comfy-button-bg);
}
.related-tags-pin-toggle {
padding: 2px 6px;
border: none;
border-radius: 4px;
background: none;
color: var(--input-text);
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
.related-tags-header-controls button:hover {
background-color: var(--border-color);
}
#related-tags-list {
@@ -248,62 +303,6 @@ body.dark-theme {
grid-template-columns: subgrid;
}
.related-tag-item.danbooru[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-blue);
}
.related-tag-item.danbooru[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.related-tag-item.danbooru[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
.related-tag-item.danbooru[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
.related-tag-item.danbooru[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-yellow);
}
.related-tag-item.danbooru[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
.related-tag-item.e621[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-sky);
}
.related-tag-item.e621[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-orange);
}
.related-tag-item.e621[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-purple);
}
.related-tag-item.e621[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-green);
}
.related-tag-item.e621[data-tag-category="species"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.related-tag-item.e621[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-white);
}
.related-tag-item.e621[data-tag-category="lore"] {
color: var(--autocomplete-plus-text-color-cat-red);
}
.related-tag-item.e621[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-gray);
}
/* stylelint-disable-next-line no-descending-specificity */
.related-tag-item span {
align-content: center;
@@ -324,11 +323,7 @@ body.dark-theme {
}
.related-tag-item.selected span {
background-color: var(
--comfy-menu-bg-selected,
var(--comfy-button-bg)
);
font-weight: bold;
background-color: var(--border-color);
}
.related-tag-item .related-tag-name {
@@ -352,9 +347,11 @@ body.dark-theme {
white-space: nowrap;
}
.related-tags-loading-message {
.related-tags-message {
width: 100%;
padding: 12px;
font-style: italic;
grid-column: 1 / -1;
text-align: center;
}
+11 -10
View File
@@ -332,10 +332,11 @@ class AutocompleteUI {
// Calculate caret position using the helper function (returns viewport-relative coordinates)
this.#updatePosition();
// Highlight the first item
this.#highlightItem();
this.root.style.display = 'block'; // Make it visible
// Highlight the selected item
// This function must be called after the route has been displayed, in order to scroll the highlighted item into view.
this.#highlightItem();
}
/**
@@ -826,7 +827,7 @@ export class AutocompleteEventHandler {
this.keyDownWithModifier.set(event.key.toLowerCase(), event.ctrlKey || event.altKey || event.metaKey);
// Handle autocomplete navigation
if (this.autocompleteUI && this.autocompleteUI.isVisible()) {
if (this.autocompleteUI.isVisible()) {
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
@@ -878,11 +879,11 @@ export class AutocompleteEventHandler {
if (this.autocompleteUI.isVisible()) {
switch (event.key) {
case "Escape":
case 'ArrowDown':
case 'ArrowUp':
event.preventDefault();
this.autocompleteUI.hide();
return; // Return here to prevent updateDisplay after hiding with Escape
// Other keys like Enter, Tab, Arrows are handled in keyDown.
return; // Prevent redundant display updates
// For other character keys, Backspace, Delete, we fall through to updateDisplay.
}
} else {
@@ -894,9 +895,9 @@ export class AutocompleteEventHandler {
}
}
// If the event was not handled by the above (e.g. Escape, or ignored special keys)
// If the event was not handled by the above (e.g. Arrow keys, or ignored special keys)
// and default action is not prevented, update the display.
// This will typically be for character inputs, Delete, or Backspace.
// This will typically be for character inputs, Delete, Backspace or IME composition.
if (!event.defaultPrevented) {
this.autocompleteUI.updateDisplay(event.target);
}
+10 -9
View File
@@ -340,8 +340,8 @@ export async function initializeData(csvListData, source) {
return;
}
const extraTagsCount = csvListData[source].extra_tags || 0;
const extraCooccurrenceCount = csvListData[source].extra_cooccurrence || 0;
const extraTagsFileList = csvListData[source].extra_tags || [];
const extraCooccurrenceFileList = csvListData[source].extra_cooccurrence || [];
const tagsUrl = `/autocomplete-plus/csv/${source}/tags`;
const cooccurrenceUrl = `/autocomplete-plus/csv/${source}/tags_cooccurrence`;
@@ -349,7 +349,7 @@ export async function initializeData(csvListData, source) {
// Factory for loading tags for the current sourte
const siteTagsLoaderFactory = async () => {
let promiseChain = Promise.resolve();
for (let i = 0; i < extraTagsCount; i++) {
for (let i = 0; i < extraTagsFileList.length; i++) {
promiseChain = promiseChain.then(() => loadTags(`${tagsUrl}/extra/${i}`, source));
}
if (csvListData[source].base_tags) {
@@ -362,7 +362,7 @@ export async function initializeData(csvListData, source) {
// Factory for loading cooccurrence data for the current sourte
const siteCooccurrenceLoaderFactory = async () => {
let promiseChain = Promise.resolve();
for (let i = 0; i < extraCooccurrenceCount; i++) {
for (let i = 0; i < extraCooccurrenceFileList.length; i++) {
promiseChain = promiseChain.then(() => loadCooccurrence(`${cooccurrenceUrl}/extra/${i}`, source));
}
if (csvListData[source].base_cooccurrence) {
@@ -377,14 +377,15 @@ export async function initializeData(csvListData, source) {
await Promise.all([
Promise.all(tagsLoadPromiseFactories.map(factory => factory())).then(() => {
const endTime = performance.now();
console.log(`[Autocomplete-Plus] "${source}" Tags loading complete in ${(endTime - startTime).toFixed(2)}ms`);
if (csvListData[source].base_tags) {
console.log(`[Autocomplete-Plus] "${source}" Tags loading complete in ${(endTime - startTime).toFixed(2)}ms`);
}
}),
Promise.all(cooccurrenceLoadPromiseFactories.map(factory => factory())).then(() => {
const endTime = performance.now();
// The original log for extraCooccurrenceCount was potentially misleading as it showed
// the count for the last processed sourte. Removed for clarity.
// If a total count is needed, it should be calculated across all sites.
console.log(`[Autocomplete-Plus] "${source}" Co-occurrence loading complete in ${(endTime - startTime).toFixed(2)}ms.`);
if (csvListData[source].base_cooccurrence) {
console.log(`[Autocomplete-Plus] "${source}" Co-occurrence loading complete in ${(endTime - startTime).toFixed(2)}ms.`);
}
})
]);
+62 -18
View File
@@ -67,7 +67,7 @@ function searchRelatedTags(tag) {
const tagSource = TagSource.Danbooru; // TODO: Leave the tag source as Danbooru until e621_tags_cooccurrence.csv is ready
if (!tag || !autoCompleteData[tagSource].cooccurrenceMap.has(tag)) {
if (!tag || !autoCompleteData[tagSource].initialized || !autoCompleteData[tagSource].cooccurrenceMap.has(tag)) {
return [];
}
@@ -199,11 +199,20 @@ class RelatedTagsUI {
this.header = document.createElement('div');
this.header.id = 'related-tags-header';
this.headerTextContainer = document.createElement('div');
this.headerTextContainer.className = 'related-tags-header-text-container';
this.header.appendChild(this.headerTextContainer);
// Create header text div for the left side
this.headerText = document.createElement('div');
this.headerText.className = 'related-tags-header-text';
this.headerText.className = 'related-tags-header-tag-text';
this.headerText.textContent = 'Related Tags';
this.header.appendChild(this.headerText);
this.headerTextContainer.appendChild(this.headerText);
// Create header alias div for the 2nd line
this.headerAlias = document.createElement('div');
this.headerAlias.className = 'related-tags-header-tag-alias';
this.headerTextContainer.appendChild(this.headerAlias);
// Create header controls for the right side
this.headerControls = document.createElement('div');
@@ -249,7 +258,7 @@ class RelatedTagsUI {
this.headerControls.appendChild(this.pinBtn);
this.header.appendChild(this.headerControls);
this.root.appendChild(this.header);
// Create a tbody for the tags
@@ -318,11 +327,13 @@ class RelatedTagsUI {
this.#updateHeader();
this.#updateContent();
this.#updatePosition();
this.#highlightItem();
// Make visible
this.root.style.display = 'block';
// This function must be called after the content is updated and the root is displayed.
this.#highlightItem();
// Update initialization status if not already done
if (!autoCompleteData[TagSource.Danbooru].initialized) {
if (this.autoRefreshTimerId) {
@@ -389,7 +400,7 @@ class RelatedTagsUI {
*/
#updateHeader() {
// Find the tag data for the current tag
const tagData = Object.values(TagSource)
let tagData = Object.values(TagSource)
.map((source) => {
if (source in autoCompleteData && autoCompleteData[source].tagMap.has(this.currentTag)) {
return autoCompleteData[source].tagMap.get(this.currentTag);
@@ -397,21 +408,49 @@ class RelatedTagsUI {
})
.find((tagData) => tagData !== undefined);
if (!tagData) {
tagData = new TagData({
tag: this.currentTag,
source: TagSource.Danbooru,
category: 'unknown',
count: 0,
alias: [],
});
}
const tagText = this.currentTag;
const categoryText = TagCategory[tagData.source][tagData.category];
// Update header text with current tag
this.headerText.innerHTML = ''; // Clear previous content
this.headerText.textContent = 'Tags related to: ';
const tagName = document.createElement('span');
tagName.className = 'related-tags-header-tag-name';
tagName.textContent = this.currentTag;
if (tagData && ['left', 'right'].includes(settingValues.tagSourceIconPosition)) {
tagName.classList.add('related-tags-header-tag-name', tagData.source);
tagName.title = `Count: ${tagData.count}\nCategory: ${categoryText}`;
tagName.dataset.tagCategory = categoryText;
if (tagData.source && ['left', 'right'].includes(settingValues.tagSourceIconPosition)) {
const tagSourceIconHtml = `<svg class="autocomplete-plus-tag-icon-svg"><use xlink:href="#autocomplete-plus-icon-${tagData.source}"></use></svg>`;
tagName.innerHTML = settingValues.tagSourceIconPosition == 'left'
? `${tagSourceIconHtml} ${tagData.tag}`
: `${tagData.tag} ${tagSourceIconHtml}`;
? `${tagSourceIconHtml} ${tagText}`
: `${tagText} ${tagSourceIconHtml}`;
} else {
tagName.textContent += tagText;
}
this.headerText.appendChild(tagName);
// Clear previous alias
this.headerAlias.style.display = 'none';
this.headerAlias.innerHTML = '';
// Add alias if available
if (tagData.alias?.length > 0) {
this.headerAlias.textContent = tagData.alias.join(', ');
this.headerAlias.style.display = 'block';
}
// Update pin button
this.pinBtn.textContent = this.isPinned ? '🎯' : '📌';
@@ -430,7 +469,7 @@ class RelatedTagsUI {
if (!autoCompleteData[TagSource.Danbooru].initialized) {
// Show loading message
const messageDiv = document.createElement('div');
messageDiv.className = 'related-tags-loading-message';
messageDiv.className = 'related-tags-message';
messageDiv.textContent = `Initializing cooccurrence data... [${autoCompleteData[TagSource.Danbooru].baseLoadingProgress.cooccurrence}%]`;
this.tagsContainer.appendChild(messageDiv);
return;
@@ -439,6 +478,7 @@ class RelatedTagsUI {
if (!this.relatedTags || this.relatedTags.length === 0) {
// Show no related tags message
const messageDiv = document.createElement('div');
messageDiv.className = 'related-tags-message';
messageDiv.textContent = 'No related tags found';
this.tagsContainer.appendChild(messageDiv);
return;
@@ -528,20 +568,24 @@ class RelatedTagsUI {
this.root.style.maxWidth = '';
this.tagsContainer.style.maxHeight = '';
const rootRect = this.root.getBoundingClientRect();
const headerRect = this.header.getBoundingClientRect();
// Hide it again after measurement
this.root.style.display = 'none';
this.root.style.visibility = 'visible';
// Get the optimal placement area
const placementArea = this.#getOptimalPlacementArea(rootRect.width, rootRect.height);
// Apply Styles
// Apply position and size
this.root.style.left = `${placementArea.x}px`;
this.root.style.top = `${placementArea.y}px`;
this.root.style.maxWidth = `${placementArea.width}px`;
this.tagsContainer.style.maxHeight = `${placementArea.height - headerRect.height}px`;
const newHeaderRect = this.header.getBoundingClientRect();
if(this.relatedTags.length > 0){
this.tagsContainer.style.maxHeight = `${placementArea.height - newHeaderRect.height}px`;
}
// Hide it again after measurement
this.root.style.display = 'none';
this.root.style.visibility = 'visible';
}
/** Highlights the item (row) at the given index */