Refactor event handling functions
This commit is contained in:
+73
-112
@@ -8,10 +8,6 @@ import {
|
||||
escapeParentheses,
|
||||
unescapeParentheses
|
||||
} from './helper.js';
|
||||
import {
|
||||
SimilarTagsEventHandler,
|
||||
} from './similar-tags.js';
|
||||
import { registerEventHandlers } from './event-handler.js';
|
||||
|
||||
// --- Autocomplete UI Class ---
|
||||
|
||||
@@ -470,7 +466,6 @@ class AutocompleteUI {
|
||||
|
||||
// --- Autocomplete Logic ---
|
||||
const autocompleteUI = new AutocompleteUI();
|
||||
const similarTagsEventHandler = new SimilarTagsEventHandler(); // Pass the autocomplete UI instance
|
||||
|
||||
/**
|
||||
* Finds tag completion candidates based on the input query.
|
||||
@@ -642,116 +637,82 @@ function insertTag(inputElement, tagToInsert) {
|
||||
inputElement.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
|
||||
// --- Event Handlers ---
|
||||
|
||||
function handleInput(event) {
|
||||
if (!settingValues.enabled || !autocompleteUI) return;
|
||||
|
||||
const ESCAPE_SEQUENCE = ["#", "/"];
|
||||
const textareaElement = event.target;
|
||||
const partialTag = getCurrentPartialTag(textareaElement);
|
||||
if (partialTag.length > 0 && !ESCAPE_SEQUENCE.some(seq => partialTag.startsWith(seq))) {
|
||||
const candidates = findCompletionCandidates(partialTag);
|
||||
autocompleteUI.show(textareaElement, candidates);
|
||||
} else {
|
||||
autocompleteUI.hide();
|
||||
}
|
||||
|
||||
similarTagsEventHandler.handleInput(event);
|
||||
}
|
||||
|
||||
function handleFocus(event) {
|
||||
if (!settingValues.enabled) return;
|
||||
// Potentially show suggestions immediately on focus?
|
||||
// For now, only show on input
|
||||
if (!autocompleteUI) {
|
||||
autocompleteUI = new AutocompleteUI();
|
||||
}
|
||||
// Maybe check if there's already text and show suggestions?
|
||||
// handleInput(event); // Trigger check immediately
|
||||
|
||||
similarTagsEventHandler.handleFocus(event);
|
||||
}
|
||||
|
||||
function handleBlur(event) {
|
||||
// Need a slight delay because clicking the autocomplete list causes blur
|
||||
setTimeout(() => {
|
||||
if (autocompleteUI && !autocompleteUI.element.contains(document.activeElement)) {
|
||||
export class AutocompleteEventHandler {
|
||||
handleInput(event) {
|
||||
if (!settingValues.enabled || !autocompleteUI) return;
|
||||
|
||||
const ESCAPE_SEQUENCE = ["#", "/"]; // prevent autocomplete for these sequences
|
||||
const textareaElement = event.target;
|
||||
const partialTag = getCurrentPartialTag(textareaElement);
|
||||
if (partialTag.length > 0 && !ESCAPE_SEQUENCE.some(seq => partialTag.startsWith(seq))) {
|
||||
const candidates = findCompletionCandidates(partialTag);
|
||||
autocompleteUI.show(textareaElement, candidates);
|
||||
} else {
|
||||
autocompleteUI.hide();
|
||||
}
|
||||
|
||||
similarTagsEventHandler.handleBlur(event);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
if (!settingValues.enabled) return;
|
||||
|
||||
const textareaElement = event.target;
|
||||
|
||||
// Handle autocomplete navigation
|
||||
if (autocompleteUI && autocompleteUI.isVisible()) {
|
||||
switch (event.key) {
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
autocompleteUI.navigate(1);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
event.preventDefault();
|
||||
autocompleteUI.navigate(-1);
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
if (autocompleteUI.getSelectedTag() !== null) {
|
||||
event.preventDefault();
|
||||
insertTag(textareaElement, autocompleteUI.getSelectedTag());
|
||||
} else {
|
||||
// Allow default Tab/Enter if no item is selected
|
||||
autocompleteUI.hide();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
handleFocus(event) {
|
||||
if (!settingValues.enabled) return;
|
||||
// Potentially show suggestions immediately on focus?
|
||||
// For now, only show on input
|
||||
if (!autocompleteUI) {
|
||||
autocompleteUI = new AutocompleteUI();
|
||||
}
|
||||
// Maybe check if there's already text and show suggestions?
|
||||
// handleInput(event); // Trigger check immediately
|
||||
}
|
||||
|
||||
handleBlur(event) {
|
||||
// Need a slight delay because clicking the autocomplete list causes blur
|
||||
setTimeout(() => {
|
||||
if (autocompleteUI && !autocompleteUI.element.contains(document.activeElement)) {
|
||||
autocompleteUI.hide();
|
||||
break;
|
||||
}
|
||||
}, 150);
|
||||
}
|
||||
|
||||
handleKeyDown(event) {
|
||||
if (!settingValues.enabled) return;
|
||||
|
||||
const textareaElement = event.target;
|
||||
|
||||
// Handle autocomplete navigation
|
||||
if (autocompleteUI && autocompleteUI.isVisible()) {
|
||||
switch (event.key) {
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
autocompleteUI.navigate(1);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
event.preventDefault();
|
||||
autocompleteUI.navigate(-1);
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
if (autocompleteUI.getSelectedTag() !== null) {
|
||||
event.preventDefault();
|
||||
insertTag(textareaElement, autocompleteUI.getSelectedTag());
|
||||
} else {
|
||||
// Allow default Tab/Enter if no item is selected
|
||||
autocompleteUI.hide();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
event.preventDefault();
|
||||
autocompleteUI.hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
similarTagsEventHandler.handleKeyDown(event);
|
||||
}
|
||||
|
||||
// New event handler for mousemove to show similar tags on hover
|
||||
function handleMouseMove(event) {
|
||||
similarTagsEventHandler.handleMouseMove(event);
|
||||
}
|
||||
|
||||
// New event handler for click to show similar tags
|
||||
function handleClick(event) {
|
||||
if (!settingValues.enabled || !settingValues.enableSimilarTags ||
|
||||
settingValues.similarTagsDisplayMode !== 'click') return;
|
||||
|
||||
similarTagsEventHandler.handleClick(event);
|
||||
}
|
||||
|
||||
// --- End Data Loading Functions ---
|
||||
|
||||
// --- Initialization ---
|
||||
|
||||
export async function initializeAutocomplete(rootPath) {
|
||||
try {
|
||||
await loadAllData(rootPath);
|
||||
|
||||
registerEventHandlers({
|
||||
handleInput: handleInput,
|
||||
handleFocus: handleFocus,
|
||||
handleBlur: handleBlur,
|
||||
handleKeyDown: handleKeyDown,
|
||||
handleMouseMove: handleMouseMove,
|
||||
handleClick: handleClick
|
||||
});
|
||||
|
||||
console.log("[Autocomplete-Plus] Autocomplete and similar tags features initialized.");
|
||||
} catch (e) {
|
||||
console.error("[Autocomplete-Plus] Error during API data loading:", e);
|
||||
|
||||
// New event handler for mousemove to show similar tags on hover
|
||||
handleMouseMove(event) {
|
||||
}
|
||||
}
|
||||
|
||||
// New event handler for click to show similar tags
|
||||
handleClick(event) {
|
||||
if (!settingValues.enabled || !settingValues.enableSimilarTags ||
|
||||
settingValues.similarTagsDisplayMode !== 'click') return;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Registers event handlers for dynamically added and existing textareas in the DOM.
|
||||
* This function uses a MutationObserver to monitor changes in the DOM and attaches
|
||||
* event listeners to elements matching specified selectors.
|
||||
*
|
||||
* @param {Object} eventHandlers - An object containing the event handler functions.
|
||||
* @param {Function} eventHandlers.handleInput - Function to handle the 'input' event.
|
||||
* @param {Function} eventHandlers.handleFocus - Function to handle the 'focus' event.
|
||||
* @param {Function} eventHandlers.handleBlur - Function to handle the 'blur' event.
|
||||
* @param {Function} eventHandlers.handleKeyDown - Function to handle the 'keydown' event.
|
||||
* @param {Function} eventHandlers.handleMouseMove - Function to handle the 'mousemove' event.
|
||||
* @param {Function} eventHandlers.handleClick - Function to handle the 'click' event.
|
||||
*/
|
||||
export function registerEventHandlers(eventHandlers) {
|
||||
// Find relevant textareas (e.g., prompt inputs)
|
||||
// This selector might need adjustment based on ComfyUI's structure
|
||||
const targetSelectors = [
|
||||
'.comfy-multiline-input',
|
||||
// Add other selectors if needed
|
||||
];
|
||||
|
||||
// Use MutationObserver to detect dynamically added textareas
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
targetSelectors.forEach(selector => {
|
||||
// Check if the added node itself matches or contains matching elements
|
||||
if (node.matches(selector)) {
|
||||
attachListeners(node);
|
||||
} else {
|
||||
node.querySelectorAll(selector).forEach(attachListeners);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Function to attach listeners
|
||||
function attachListeners(element) {
|
||||
if (element.dataset.autocompleteAttached) return; // Prevent double attachment
|
||||
|
||||
element.addEventListener('input', eventHandlers.handleInput);
|
||||
element.addEventListener('focus', eventHandlers.handleFocus);
|
||||
element.addEventListener('blur', eventHandlers.handleBlur);
|
||||
element.addEventListener('keydown', eventHandlers.handleKeyDown);
|
||||
|
||||
// Add new event listeners for similar tags feature
|
||||
element.addEventListener('mousemove', eventHandlers.handleMouseMove);
|
||||
element.addEventListener('click', eventHandlers.handleClick);
|
||||
|
||||
element.dataset.autocompleteAttached = 'true';
|
||||
}
|
||||
|
||||
// Initial scan for existing elements
|
||||
targetSelectors.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(attachListeners);
|
||||
});
|
||||
|
||||
// Start observing the document body for changes
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
+14
-1
@@ -93,4 +93,17 @@ export function unescapeParentheses(str) {
|
||||
if (!str) return str;
|
||||
return str.replace(/\\\(/g, '(').replace(/\\\)/g, ')');
|
||||
}
|
||||
// --- End String Helper Functions ---
|
||||
|
||||
// --- End String Helper Functions ---
|
||||
|
||||
// Function to load a CSS file
|
||||
export function loadCSS(href) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = href;
|
||||
// Ensure the CSS is loaded before other scripts might rely on its styles
|
||||
// by adding it to the head.
|
||||
document.head.appendChild(link);
|
||||
console.debug(`Loaded CSS: ${href}`); // Optional: Log loading
|
||||
}
|
||||
|
||||
+92
-12
@@ -1,17 +1,95 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
import { initializeAutocomplete } from './autocomplete.js';
|
||||
import { settingValues } from "./settings.js";
|
||||
import { loadCSS } from "./helper.js";
|
||||
import { loadAllData } from "./data.js";
|
||||
import { AutocompleteEventHandler } from "./autocomplete.js";
|
||||
import { SimilarTagsEventHandler } from "./similar-tags.js";
|
||||
|
||||
// Function to load a CSS file
|
||||
function loadCSS(href) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = href;
|
||||
// Ensure the CSS is loaded before other scripts might rely on its styles
|
||||
// by adding it to the head.
|
||||
document.head.appendChild(link);
|
||||
console.debug(`Loaded CSS: ${href}`); // Optional: Log loading
|
||||
function initializeEventHandlers() {
|
||||
// Singletons for event handlers
|
||||
const autocompleteEventHandler = new AutocompleteEventHandler();
|
||||
const similarTagsEventHandler = new SimilarTagsEventHandler();
|
||||
|
||||
// Find relevant textareas (e.g., prompt inputs)
|
||||
// This selector might need adjustment based on ComfyUI's structure
|
||||
const targetSelectors = [
|
||||
'.comfy-multiline-input',
|
||||
// Add other selectors if needed
|
||||
];
|
||||
|
||||
// Use MutationObserver to detect dynamically added textareas
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
targetSelectors.forEach(selector => {
|
||||
// Check if the added node itself matches or contains matching elements
|
||||
if (node.matches(selector)) {
|
||||
attachListeners(node);
|
||||
} else {
|
||||
node.querySelectorAll(selector).forEach(attachListeners);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Function to attach listeners
|
||||
function attachListeners(element) {
|
||||
if (element.dataset.autocompleteAttached) return; // Prevent double attachment
|
||||
|
||||
element.addEventListener('input', handleInput);
|
||||
element.addEventListener('focus', handleFocus);
|
||||
element.addEventListener('blur', handleBlur);
|
||||
element.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
// Add new event listeners for similar tags feature
|
||||
element.addEventListener('mousemove', handleMouseMove);
|
||||
element.addEventListener('click', handleClick);
|
||||
|
||||
element.dataset.autocompleteAttached = 'true';
|
||||
}
|
||||
|
||||
// Initial scan for existing elements
|
||||
targetSelectors.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(attachListeners);
|
||||
});
|
||||
|
||||
// Start observing the document body for changes
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
function handleInput(event) {
|
||||
autocompleteEventHandler.handleInput(event);
|
||||
similarTagsEventHandler.handleInput(event);
|
||||
}
|
||||
|
||||
function handleFocus(event) {
|
||||
autocompleteEventHandler.handleFocus(event);
|
||||
similarTagsEventHandler.handleFocus(event);
|
||||
}
|
||||
|
||||
function handleBlur(event) {
|
||||
autocompleteEventHandler.handleBlur(event);
|
||||
similarTagsEventHandler.handleBlur(event);
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
autocompleteEventHandler.handleKeyDown(event);
|
||||
similarTagsEventHandler.handleKeyDown(event);
|
||||
}
|
||||
|
||||
// New event handler for mousemove to show similar tags on hover
|
||||
function handleMouseMove(event) {
|
||||
autocompleteEventHandler.handleMouseMove(event);
|
||||
similarTagsEventHandler.handleMouseMove(event);
|
||||
}
|
||||
|
||||
// New event handler for click to show similar tags
|
||||
function handleClick(event) {
|
||||
autocompleteEventHandler.handleClick(event);
|
||||
similarTagsEventHandler.handleClick(event);
|
||||
}
|
||||
}
|
||||
|
||||
const id = "AutocompletePlus";
|
||||
@@ -20,10 +98,12 @@ app.registerExtension({
|
||||
id: id,
|
||||
name: name,
|
||||
setup() {
|
||||
initializeEventHandlers();
|
||||
|
||||
let rootPath = import.meta.url.replace("js/main.js", "");
|
||||
loadCSS(rootPath + "css/autocomplete-plus.css"); // Load CSS for autocomplete
|
||||
|
||||
initializeAutocomplete(rootPath); // Initialize after tags are loaded
|
||||
loadAllData(rootPath);
|
||||
},
|
||||
settings: [
|
||||
{
|
||||
|
||||
@@ -5,4 +5,8 @@ export const settingValues = {
|
||||
enableSimilarTags: true,
|
||||
maxSimilarTags: 20,
|
||||
similarTagsDisplayMode: 'click', // 'hover' or 'click'
|
||||
}
|
||||
|
||||
export function initSettings(){
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user