feat: Implement auto-formatting block logic

This commit is contained in:
newtextdoc1111
2025-11-20 22:00:15 +09:00
parent 79fb35ff8c
commit f68c0c7dc2
3 changed files with 142 additions and 12 deletions
+63 -2
View File
@@ -1,4 +1,59 @@
import { settingValues } from './settings.js';
import { NodeInfo } from './node-info.js';
/**
* Determines if the text content should be auto-formatted.
*
* Format conditions:
* 1. Skip formatting if node is in blocklist
* 2. Skip formatting if text contains only numbers, hyphens, commas, dots, and spaces
* 3. Format if text contains "word + comma" pattern at least twice
* 4. Otherwise, don't format
*
* @param {NodeInfo} nodeInfo - The node information.
* @returns {boolean} - True if the text should be formatted, false otherwise.
*/
function shouldAutoFormat(text, nodeInfo) {
if (!text || text.trim().length === 0) return false;
// 1. Check if the node name is in the blocklist
const blocklist = [
["Power Puter (rgthree)", "code"],
["LoraLoaderBlockWeight //Inspire", "block_vector"]
];
const isBlocklisted = blocklist.some(([type, input]) =>
type === nodeInfo.nodeType && input === nodeInfo.inputName
);
if (isBlocklisted) {
// console.debug(`[Autocomplete-Plus] auto-formatter on blur => nodeType: ${nodeInfo.nodeType}, inputName: ${nodeInfo.inputName} => blocklisted`);
return false;
} else {
// console.debug(`[Autocomplete-Plus] auto-formatter on blur => nodeType: ${nodeInfo.nodeType}, inputName: ${nodeInfo.inputName}`);
}
const trimmedText = text.trim();
// 2. Check if the text is purely numeric data with hyphens and commas
// (e.g., "0,0,0,1,1,1" or "0.5, -1.2, 0.8" for LoRA Block Weight)
const numericPattern = /^[\d.,\s-]+$/;
if (numericPattern.test(trimmedText)) {
return false; // Don't format numeric data
}
// 3. Check if the text contains the pattern "word + comma"
const wordCommaPattern = /\w+\s*,/g;
const matches = trimmedText.match(wordCommaPattern);
if (matches == null) {
return false;
}
return true; // Text should be formatted
}
/**
* Format the prompt text: add a comma and space after each tag, and remove extra spaces.
@@ -79,12 +134,18 @@ export class AutoFormatterEventHandler {
* Handle blur event to trigger auto-formatting
* @param {Event} event - The blur event
*/
handleBlur(event) {
handleBlur(event, nodeInfo) {
if (
settingValues.enableAutoFormat &&
event.target.tagName === 'TEXTAREA'
) {
formatTextareaOnBlur(event.target);
const textarea = event.target;
const text = textarea.value;
// Check if the content should be auto-formatted
if (shouldAutoFormat(text, nodeInfo)) {
formatTextareaOnBlur(textarea);
}
}
}
+65 -10
View File
@@ -7,6 +7,7 @@ import { TagSource, loadDataAsync } from "./data.js";
import { AutocompleteEventHandler } from "./autocomplete.js";
import { RelatedTagsEventHandler } from "./related-tags.js";
import { AutoFormatterEventHandler } from "./auto-formatter.js";
import { NodeInfo } from "./node-info.js";
// --- Constants ---
const id = "AutocompletePlus";
@@ -20,11 +21,11 @@ function initializeEventHandlers() {
const autocompleteEventHandler = new AutocompleteEventHandler();
const relatedTagsEventHandler = new RelatedTagsEventHandler();
const autoFormatterEventHandler = new AutoFormatterEventHandler();
const attachedElements = new WeakSet(); // Keep track of elements that have listeners attached
const attachedElementNodeInfoMap = new WeakMap(); // Map to track attached elements and their node info
// Function to attach listeners
function attachListeners(element) {
if (attachedElements.has(element)) return; // Prevent double attachment
function attachListeners(element, nodeInfo) {
if (attachedElementNodeInfoMap.has(element)) return; // Prevent double attachment
element.addEventListener('input', handleInput);
element.addEventListener('focus', handleFocus);
@@ -37,7 +38,7 @@ function initializeEventHandlers() {
element.addEventListener('mousemove', handleMouseMove);
element.addEventListener('click', handleClick);
attachedElements.add(element); // Mark as attached
attachedElementNodeInfoMap.set(element, nodeInfo); // Mark as attached and store node info
}
// Attempt Widget Override as the primary method
@@ -50,12 +51,14 @@ function initializeEventHandlers() {
// Check if the widget has an inputEl 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') {
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;
attachListeners(result.widget.inputEl);
const nodeInfo = new NodeInfo(node.comfyClass || node.constructor.name, inputName);
attachListeners(result.widget.inputEl, nodeInfo);
}
return result;
};
@@ -75,9 +78,11 @@ function initializeEventHandlers() {
targetSelectors.forEach(selector => {
// Check if the added node itself matches or contains matching elements
if (node.matches(selector)) {
attachListeners(node);
attachListeners(node, new NodeInfo('Fallback', 'unknown'));
} else {
node.querySelectorAll(selector).forEach(attachListeners);
node.querySelectorAll(selector).forEach(el => {
attachListeners(el, new NodeInfo('Fallback', 'unknown'));
});
}
});
}
@@ -87,7 +92,9 @@ function initializeEventHandlers() {
// Initial scan for existing elements
targetSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(attachListeners);
document.querySelectorAll(selector).forEach(el => {
attachListeners(el, new NodeInfo('Fallback', 'unknown'));
});
});
// Start observing the document body for changes
@@ -95,41 +102,89 @@ function initializeEventHandlers() {
}
function handleInput(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleInput:', event.target);
return;
}
autocompleteEventHandler.handleInput(event);
relatedTagsEventHandler.handleInput(event);
autoFormatterEventHandler.handleInput(event);
}
function handleFocus(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleFocus:', event.target);
return;
}
autocompleteEventHandler.handleFocus(event);
relatedTagsEventHandler.handleFocus(event);
autoFormatterEventHandler.handleFocus(event);
}
function handleBlur(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleBlur:', event.target);
return;
}
autocompleteEventHandler.handleBlur(event);
relatedTagsEventHandler.handleBlur(event);
autoFormatterEventHandler.handleBlur(event);
autoFormatterEventHandler.handleBlur(event, nodeInfo);
}
function handleKeyDown(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleKeyDown:', event.target);
return;
}
autocompleteEventHandler.handleKeyDown(event);
relatedTagsEventHandler.handleKeyDown(event);
autoFormatterEventHandler.handleKeyDown(event);
}
function handleKeyUp(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleKeyUp:', event.target);
return;
}
autocompleteEventHandler.handleKeyUp(event);
relatedTagsEventHandler.handleKeyUp(event);
autoFormatterEventHandler.handleKeyUp(event);
}
// New event handler for mousemove to show related tags on hover
function handleMouseMove(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleMouseMove:', event.target);
return;
}
autocompleteEventHandler.handleMouseMove(event);
relatedTagsEventHandler.handleMouseMove(event);
autoFormatterEventHandler.handleMouseMove(event);
}
// New event handler for click to show related tags
function handleClick(event) {
const nodeInfo = attachedElementNodeInfoMap.get(event.target);
if (!nodeInfo) {
console.warn('[Autocomplete-Plus] Node info not found for element in handleClick:', event.target);
return;
}
autocompleteEventHandler.handleClick(event);
relatedTagsEventHandler.handleClick(event);
autoFormatterEventHandler.handleClick(event);
}
}
+14
View File
@@ -0,0 +1,14 @@
/**
* Class to hold information about the node attached to an input element.
* Used to control behavior based on node information.
*/
export class NodeInfo {
/**
* @param {string} nodeType - The type/class name of the node
* @param {string} inputName - The name of the input widget
*/
constructor(nodeType, inputName) {
this.nodeType = nodeType;
this.inputName = inputName;
}
}