refactor: Rename similar tags to related tags and update related settings

This commit is contained in:
newtextdoc1111
2025-05-08 16:14:18 +09:00
parent 12b782ec02
commit 63fce9cf7a
4 changed files with 125 additions and 125 deletions
+21 -21
View File
@@ -114,8 +114,8 @@ body.dark-theme {
white-space: nowrap;
}
/* Similar Tags UI Styles */
#similar-tags-container {
/* Related Tags UI Styles */
#related-tags-container {
position: absolute;
z-index: 999;
top: 0;
@@ -127,7 +127,7 @@ body.dark-theme {
overflow-y: auto;
}
#similar-tags-header {
#related-tags-header {
position: sticky;
z-index: 1;
top: 0;
@@ -137,89 +137,89 @@ body.dark-theme {
color: var(--descrip-text);
}
.similar-tags-header-tag-name {
.related-tags-header-tag-name {
font-weight: bold;
}
#similar-tags-list {
#related-tags-list {
display: grid;
box-shadow: 0 2px 8px rgb(0 0 0 / 30%);
grid-auto-rows: auto;
grid-template-columns: max-content 1fr auto auto;
}
.similar-tag-item {
.related-tag-item {
display: contents;
cursor: pointer;
}
.similar-tag-item[data-tag-category="general"] {
.related-tag-item[data-tag-category="general"] {
color: var(--autocomplete-plus-text-color-cat-general);
}
.similar-tag-item[data-tag-category="artist"] {
.related-tag-item[data-tag-category="artist"] {
color: var(--autocomplete-plus-text-color-cat-artist);
}
.similar-tag-item[data-tag-category="copyright"] {
.related-tag-item[data-tag-category="copyright"] {
color: var(--autocomplete-plus-text-color-cat-copyright);
}
.similar-tag-item[data-tag-category="character"] {
.related-tag-item[data-tag-category="character"] {
color: var(--autocomplete-plus-text-color-cat-character);
}
.similar-tag-item[data-tag-category="meta"] {
.related-tag-item[data-tag-category="meta"] {
color: var(--autocomplete-plus-text-color-cat-meta);
}
.similar-tag-item[data-tag-category="unknown"] {
.related-tag-item[data-tag-category="unknown"] {
color: var(--autocomplete-plus-text-color-cat-unknown);
}
.similar-tag-item span {
.related-tag-item span {
align-content: center;
padding: 4px 8px;
border-bottom: 1px solid var(--border-color);
}
.similar-tag-item:nth-child(even) span {
.related-tag-item:nth-child(even) span {
background-color: var(--comfy-menu-bg);
}
.similar-tag-item:nth-child(odd) span {
.related-tag-item:nth-child(odd) span {
background-color: var(--comfy-menu-secondary-bg);
}
.similar-tag-item:hover span {
.related-tag-item:hover span {
background-color: var(--p-form-field-filled-hover-background);
}
.similar-tag-name {
.related-tag-name {
padding: 8px;
white-space: nowrap;
}
.similar-tag-alias {
.related-tag-alias {
overflow: hidden;
color: var(--descrip-text);
text-overflow: ellipsis;
white-space: nowrap;
}
.similar-tag-similarity {
.related-tag-relatedity {
color: var(--descrip-text);
text-align: right;
white-space: nowrap;
}
.similar-tags-loading-message {
.related-tags-loading-message {
padding: 12px;
font-style: italic;
text-align: center;
}
.similar-tags-empty {
.related-tags-empty {
padding: 12px;
color: var(--error-text);
font-style: italic;
+30 -30
View File
@@ -4,11 +4,11 @@ import { settingValues } from "./settings.js";
import { loadCSS } from "./utils.js";
import { loadAllData } from "./data.js";
import { AutocompleteEventHandler } from "./autocomplete.js";
import { SimilarTagsEventHandler } from "./similar-tags.js";
import { RelatedTagsEventHandler } from "./related-tags.js";
function initializeEventHandlers() {
const autocompleteEventHandler = new AutocompleteEventHandler();
const similarTagsEventHandler = new SimilarTagsEventHandler();
const relatedTagsEventHandler = new RelatedTagsEventHandler();
const attachedElements = new WeakSet(); // Keep track of elements that have listeners attached
// Function to attach listeners
@@ -22,7 +22,7 @@ function initializeEventHandlers() {
element.addEventListener('keyup', handleKeyUp);
element.addEventListener('keypress', handleKeyPress);
// Add new event listeners for similar tags feature
// Add new event listeners for related tags feature
element.addEventListener('mousemove', handleMouseMove);
element.addEventListener('click', handleClick);
@@ -38,7 +38,7 @@ function initializeEventHandlers() {
const result = originalStringWidget.apply(this, arguments);
// Check if the widget has an inputEl and if it's a TEXTAREA
// This is to ensure we are targeting multiline text inputs, similar to '.comfy-multiline-input'
// 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') {
const widgetConfig = inputData && inputData[1] ? inputData[1] : {};
// Future: Add checks for Autocomplete Plus specific configurations if needed
@@ -85,44 +85,44 @@ function initializeEventHandlers() {
function handleInput(event) {
autocompleteEventHandler.handleInput(event);
similarTagsEventHandler.handleInput(event);
relatedTagsEventHandler.handleInput(event);
}
function handleFocus(event) {
autocompleteEventHandler.handleFocus(event);
similarTagsEventHandler.handleFocus(event);
relatedTagsEventHandler.handleFocus(event);
}
function handleBlur(event) {
autocompleteEventHandler.handleBlur(event);
similarTagsEventHandler.handleBlur(event);
relatedTagsEventHandler.handleBlur(event);
}
function handleKeyDown(event) {
autocompleteEventHandler.handleKeyDown(event);
similarTagsEventHandler.handleKeyDown(event);
relatedTagsEventHandler.handleKeyDown(event);
}
function handleKeyUp(event) {
autocompleteEventHandler.handleKeyUp(event);
similarTagsEventHandler.handleKeyUp(event);
relatedTagsEventHandler.handleKeyUp(event);
}
function handleKeyPress(event) {
autocompleteEventHandler.handleKeyPress(event);
similarTagsEventHandler.handleKeyPress(event);
relatedTagsEventHandler.handleKeyPress(event);
}
// New event handler for mousemove to show similar tags on hover
// New event handler for mousemove to show related tags on hover
function handleMouseMove(event) {
autocompleteEventHandler.handleMouseMove(event);
similarTagsEventHandler.handleMouseMove(event);
relatedTagsEventHandler.handleMouseMove(event);
}
// New event handler for click to show similar tags
// New event handler for click to show related tags
function handleClick(event) {
autocompleteEventHandler.handleClick(event);
similarTagsEventHandler.handleClick(event);
relatedTagsEventHandler.handleClick(event);
}
}
@@ -166,22 +166,22 @@ app.registerExtension({
settingValues.maxSuggestions = newVal;
}
},
// Similar Tags Settings
// Related Tags Settings
{
id: id + ".similar_tags_enable",
name: "Enable Similar Tags",
description: "Enable or disable the similar tags feature.",
id: id + ".related_tags_enable",
name: "Enable Related Tags",
description: "Enable or disable the related tags feature.",
type: "boolean",
defaultValue: true,
category: [name, "Similar Tags", "Enable Similar Tags"],
category: [name, "Related Tags", "Enable Related Tags"],
onChange: (newVal, oldVal) => {
settingValues.enableSimilarTags = newVal;
settingValues.enableRelatedTags = newVal;
}
},
{
id: id + ".max_similar_tags",
name: "Max similar tags",
description: "Maximum number of similar tags to display",
id: id + ".max_related_tags",
name: "Max related tags",
description: "Maximum number of related tags to display",
type: "slider",
attrs: {
min: 5,
@@ -189,21 +189,21 @@ app.registerExtension({
step: 5,
},
defaultValue: 20,
category: [name, "Similar Tags", "Max similar tags"],
category: [name, "Related Tags", "Max related tags"],
onChange: (newVal, oldVal) => {
settingValues.maxSimilarTags = newVal;
settingValues.maxRelatedTags = newVal;
}
},
{
id: id + ".similar_tags_position",
name: "Similar Tags Display Position",
description: "Position of similar tags display",
id: id + ".related_tags_position",
name: "Related Tags Display Position",
description: "Position of related tags display",
type: "combo",
options: ["horizontal", "vertical"],
defaultValue: "horizontal",
category: [name, "Similar Tags", "Display Position"],
category: [name, "Related Tags", "Display Position"],
onChange: (newVal, oldVal) => {
settingValues.similarTagsDisplayPosition = newVal;
settingValues.relatedTagsDisplayPosition = newVal;
}
}
]
@@ -1,4 +1,4 @@
// filepath: v:\Programs\StabilityMatrix-win-x64\Data\Packages\ComfyUI-New\custom_nodes\ComfyUI-Autocomplete-Plus\web\js\similar-tags.js
// filepath: v:\Programs\StabilityMatrix-win-x64\Data\Packages\ComfyUI-New\custom_nodes\ComfyUI-Autocomplete-Plus\web\js\related-tags.js
import { settingValues } from './settings.js';
import { TagCategory, autoCompleteData } from './data.js';
import {
@@ -9,27 +9,27 @@ import {
getViewportMargin
} from './utils.js';
// --- SimilarTags UI Class ---
// --- RelatedTags UI Class ---
/**
* Class that manages the UI for displaying similar tags.
* Shows a panel with tags similar to the current tag under cursor.
* Class that manages the UI for displaying related tags.
* Shows a panel with tags related to the current tag under cursor.
*/
class SimilarTagsUI {
class RelatedTagsUI {
constructor() {
// Create the main container
this.root = document.createElement('div');
this.root.id = 'similar-tags-container';
this.root.id = 'related-tags-container';
// Create header row
this.header = document.createElement('div');
this.header.id = 'similar-tags-header';
this.header.textContent = 'Similar Tags';
this.header.id = 'related-tags-header';
this.header.textContent = 'Related Tags';
this.root.appendChild(this.header);
// Create a tbody for the tags
this.tagsContainer = document.createElement('div');
this.tagsContainer.id = 'similar-tags-list';
this.tagsContainer.id = 'related-tags-list';
this.root.appendChild(this.tagsContainer);
// Add to DOM
@@ -41,7 +41,7 @@ class SimilarTagsUI {
// Add click handler for tag selection
this.tagsContainer.addEventListener('mousedown', (e) => {
const row = e.target.closest('.similar-tag-item');
const row = e.target.closest('.related-tag-item');
if (row && row.dataset.tag) {
this.selectTag(row.dataset.tag);
e.preventDefault();
@@ -54,13 +54,13 @@ class SimilarTagsUI {
}
/**
* Shows the similar tags UI for a specific tag and text input element.
* Shows the related tags UI for a specific tag and text input element.
* @param {HTMLTextAreaElement} inputElement The textarea being used
* @param {string} tag The tag to find similarities for
* @param {Array<{tag: string, similarity: number, count: number, alias?: string[]}>} similarTags List of similar tags
* @param {string} tag The tag to find relatedities for
* @param {Array<{tag: string, similarity: number, count: number, alias?: string[]}>} relatedTags List of related tags
*/
show(inputElement, tag, similarTags) {
if (!settingValues.enableSimilarTags) {
show(inputElement, tag, relatedTags) {
if (!settingValues.enableRelatedTags) {
this.hide();
return;
}
@@ -68,8 +68,8 @@ class SimilarTagsUI {
this.activeInput = inputElement;
this.currentTag = tag;
// Update content (even if there are no similar tags, we'll show a message)
this.updateContent(similarTags);
// Update content (even if there are no related tags, we'll show a message)
this.updateContent(relatedTags);
// Calculate and update position
this.updatePosition(inputElement);
@@ -82,13 +82,13 @@ class SimilarTagsUI {
clearTimeout(this.autoRefreshTimerId);
}
this.autoRefreshTimerId = setTimeout(() => {
similarTagsUI.show(inputElement, tag, similarTags);
relatedTagsUI.show(inputElement, tag, relatedTags);
}, 500);
}
}
/**
* Hides the similar tags UI.
* Hides the related tags UI.
*/
hide() {
if(this.autoRefreshTimerId){
@@ -101,10 +101,10 @@ class SimilarTagsUI {
}
/**
* Updates the content of the similar tags panel with the provided tags.
* @param {Array<{tag: string, similarity: number, count: number, alias?: string[]}>} similarTags
* Updates the content of the related tags panel with the provided tags.
* @param {Array<{tag: string, similarity: number, count: number, alias?: string[]}>} relatedTags
*/
updateContent(similarTags) {
updateContent(relatedTags) {
this.root.style.left = 0;
this.root.style.top = 0;
this.root.style.maxWidth = `${window.innerWidth / 2}px`;
@@ -115,34 +115,34 @@ class SimilarTagsUI {
this.header.innerHTML = ''; // Clear previous content
this.header.textContent = 'Tags related to: ';
const tagNameSpan = document.createElement('span');
tagNameSpan.className = 'similar-tags-header-tag-name';
tagNameSpan.className = 'related-tags-header-tag-name';
tagNameSpan.textContent = this.currentTag;
this.header.appendChild(tagNameSpan);
if (!autoCompleteData.cooccurrenceLoaded) {
const messageDiv = document.createElement('div');
messageDiv.className = 'similar-tags-loading-message';
messageDiv.className = 'related-tags-loading-message';
messageDiv.textContent = `Initializing cooccurrence data... [${autoCompleteData.cooccurrenceInitProgress}%]`;
this.tagsContainer.appendChild(messageDiv);
return;
}
if (!similarTags || similarTags.length === 0) {
if (!relatedTags || relatedTags.length === 0) {
const messageCell = document.createElement('div');
messageCell.textContent = 'No similar tags found';
messageCell.textContent = 'No related tags found';
this.tagsContainer.appendChild(messageCell);
return;
}
// Create tag rows
similarTags.forEach(tagData => {
relatedTags.forEach(tagData => {
const tagRow = this.createTagElement(tagData);
this.tagsContainer.appendChild(tagRow);
});
}
/**
* Creates an HTML table row for a similar tag.
* Creates an HTML table row for a related tag.
* @param {{tag: string, similarity: number, count: number, alias?: string[]}} tagData
* @returns {HTMLTableRowElement} The tag row element
*/
@@ -150,18 +150,18 @@ class SimilarTagsUI {
const categoryText = TagCategory[tagData.category] || "unknown";
const tagRow = document.createElement('div');
tagRow.className = 'similar-tag-item';
tagRow.className = 'related-tag-item';
tagRow.dataset.tag = tagData.tag;
tagRow.dataset.tagCategory = categoryText;
// Tag name cell
const tagNameCell = document.createElement('span');
tagNameCell.className = 'similar-tag-name';
tagNameCell.className = 'related-tag-name';
tagNameCell.textContent = tagData.tag;
// Alias cell (middle column)
const aliasCell = document.createElement('span');
aliasCell.className = 'similar-tag-alias';
aliasCell.className = 'related-tag-alias';
// Display alias if available
if (tagData.alias && tagData.alias.length > 0) {
@@ -172,12 +172,12 @@ class SimilarTagsUI {
// Category cell
const categoryCell = document.createElement('span');
categoryCell.className = `similar-tag-category`;
categoryCell.className = `related-tag-category`;
categoryCell.textContent = `${categoryText.substring(0, 2)}`;
// Similarity cell
const similarityCell = document.createElement('span');
similarityCell.className = 'similar-tag-similarity';
similarityCell.className = 'related-tag-similarity';
similarityCell.textContent = `${(tagData.similarity * 100).toFixed(2)}%`;
// Create tooltip with more info
@@ -197,9 +197,9 @@ class SimilarTagsUI {
}
/**
* Updates the position of the similar tags panel.
* Updates the position of the related tags panel.
* Position is calculated based on the input element, available space,
* and the setting `similarTagsDisplayPosition`.
* and the setting `relatedTagsDisplayPosition`.
* @param {HTMLElement} inputElement The input element to position
*/
updatePosition(inputElement) {
@@ -241,7 +241,7 @@ class SimilarTagsUI {
}
/**
* Handles the selection of a similar tag.
* Handles the selection of a related tag.
* Inserts the tag into the active input.
* @param {string} tag
*/
@@ -256,7 +256,7 @@ class SimilarTagsUI {
}
/**
* Checks if the similar tags UI is currently visible.
* Checks if the related tags UI is currently visible.
* @returns {boolean}
*/
isVisible() {
@@ -289,7 +289,7 @@ class SimilarTagsUI {
height: Math.min(elemHeight, viewportHeight - margin.top - margin.bottom)
};
if (settingValues.similarTagsDisplayPosition === 'vertical') {
if (settingValues.relatedTagsDisplayPosition === 'vertical') {
// Vertical placement
const topSpace = inputRect.top - margin.top;
const bottomSpace = viewportHeight - inputRect.bottom - margin.bottom;
@@ -355,11 +355,11 @@ function calculateJaccardSimilarity(tagA, tagB) {
}
/**
* Finds similar tags for a given tag.
* @param {string} tag The tag to find similar tags for
* Finds related tags for a given tag.
* @param {string} tag The tag to find related tags for
* @returns {Array<{tag: string, similarity: number, count: number, alias?: string[]}>}
*/
function findSimilarTags(tag) {
function findRelatedTags(tag) {
const startTime = performance.now(); // Record start time for performance measurement
if (!tag || !autoCompleteData.cooccurrenceMap.has(tag)) {
@@ -367,7 +367,7 @@ function findSimilarTags(tag) {
}
const cooccurrences = autoCompleteData.cooccurrenceMap.get(tag);
const similarTags = [];
const relatedTags = [];
// Convert to array for sorting
cooccurrences.forEach((count, coTag) => {
@@ -381,7 +381,7 @@ function findSimilarTags(tag) {
// Calculate similarity
const similarity = calculateJaccardSimilarity(tag, coTag);
similarTags.push({
relatedTags.push({
tag: coTag,
similarity: similarity,
alias: tagData.alias,
@@ -391,10 +391,10 @@ function findSimilarTags(tag) {
});
// Sort by similarity (highest first)
similarTags.sort((a, b) => b.similarity - a.similarity);
relatedTags.sort((a, b) => b.similarity - a.similarity);
// Limit to max number of suggestions
const result = similarTags.slice(0, settingValues.maxSimilarTags);
const result = relatedTags.slice(0, settingValues.maxRelatedTags);
const endTime = performance.now();
const duration = endTime - startTime;
@@ -555,27 +555,27 @@ function findAllTagPositions(text) {
// --- Main Exports ---
// Create a singleton instance
const similarTagsUI = new SimilarTagsUI();
const relatedTagsUI = new RelatedTagsUI();
// Helper function to show similar tags based on cursor position
function showSimilarTagsForCurrentPosition(textareaElement) {
// Helper function to show related tags based on cursor position
function showRelatedTagsForCurrentPosition(textareaElement) {
// Get the tag at current cursor position
const currentTag = normalizeTagToSearch(getCurrentTag(textareaElement));
// If no valid tag or tag is too short, hide the panel
if (!isValidTag(currentTag)) {
similarTagsUI.hide();
relatedTagsUI.hide();
return;
}
// Find similar tags
const similarTagsResults = findSimilarTags(currentTag);
// Find related tags
const relatedTagsResults = findRelatedTags(currentTag);
// Always show the panel with current tag, even if there are no similar tags
similarTagsUI.show(textareaElement, currentTag, similarTagsResults);
// Always show the panel with current tag, even if there are no related tags
relatedTagsUI.show(textareaElement, currentTag, relatedTagsResults);
}
export class SimilarTagsEventHandler {
export class RelatedTagsEventHandler {
constructor() {
}
@@ -585,9 +585,9 @@ export class SimilarTagsEventHandler {
* @param {KeyboardEvent} event
*/
handleInput(event) {
if (settingValues.enableSimilarTags) {
if (similarTagsUI && similarTagsUI.isVisible()) {
similarTagsUI.hide();
if (settingValues.enableRelatedTags) {
if (relatedTagsUI && relatedTagsUI.isVisible()) {
relatedTagsUI.hide();
}
}
}
@@ -609,17 +609,17 @@ export class SimilarTagsEventHandler {
return;
}
// Use setTimeout to delay hiding. This allows clicks on the similar tags UI
// Use setTimeout to delay hiding. This allows clicks on the related tags UI
// to be processed before the UI is hidden.
setTimeout(() => {
// Check if the new focused element is part of the similar tags UI.
// Check if the new focused element is part of the related tags UI.
// document.activeElement refers to the currently focused element.
const activeElement = document.activeElement;
const similarTagsElement = similarTagsUI.root;
const relatedTagsElement = relatedTagsUI.root;
// If the focus is not within the similar tags UI, hide it.
if (similarTagsUI && !similarTagsElement.contains(activeElement)) {
similarTagsUI.hide();
// If the focus is not within the related tags UI, hide it.
if (relatedTagsUI && !relatedTagsElement.contains(activeElement)) {
relatedTagsUI.hide();
}
}, 150); // Delay in milliseconds (adjust if necessary)
}
@@ -631,19 +631,19 @@ export class SimilarTagsEventHandler {
handleKeyDown(event) {
const textareaElement = event.target;
// For similar tags panel, handle Escape key
if (similarTagsUI && similarTagsUI.isVisible()) {
// For related tags panel, handle Escape key
if (relatedTagsUI && relatedTagsUI.isVisible()) {
if (event.key === 'Escape') {
event.preventDefault();
similarTagsUI.hide();
relatedTagsUI.hide();
}
}
// Show similar tags on Ctrl+Space
if (settingValues.enableSimilarTags) {
// Show related tags on Ctrl+Space
if (settingValues.enableRelatedTags) {
if (event.key === ' ' && event.ctrlKey && event.shiftKey ) {
event.preventDefault();
showSimilarTagsForCurrentPosition(textareaElement);
showRelatedTagsForCurrentPosition(textareaElement);
}
}
}
@@ -680,6 +680,6 @@ export class SimilarTagsEventHandler {
*/
handleClick(event) {
const textareaElement = event.target;
showSimilarTagsForCurrentPosition(textareaElement);
showRelatedTagsForCurrentPosition(textareaElement);
}
}
+4 -4
View File
@@ -3,10 +3,10 @@ export const settingValues = {
enabled: true,
maxSuggestions: 10,
// Similar tags feature settings
enableSimilarTags: true,
maxSimilarTags: 20,
similarTagsDisplayPosition: 'horizontal', // 'horizontal' or 'vertical'
// Related tags feature settings
enableRelatedTags: true,
maxRelatedTags: 20,
relatedTagsDisplayPosition: 'horizontal', // 'horizontal' or 'vertical'
// Internal logic settings
_useFallbackAttachmentForEventListener: false, // Fallback to attach event listener if not using jQuery