fix: lora entry selection and strength display issues

- Fix lora entry click-to-select broken after pointer events refactoring
  - Only stopPropagation() after pointer moves beyond 3 pixel threshold
  - This allows click events to fire on lora entries for selection
  - Applied to all drag handlers: initDrag, initHeaderDrag, initReorderDrag

- Fix strength value display to always show 2 decimal places
  - Use toFixed(2) when updating strength input during drag
  - Ensures consistent display (e.g., "1.00" instead of "1", "1.40" instead of "1.4")
This commit is contained in:
Will Miao
2026-01-15 19:04:56 +08:00
parent c5b597dc89
commit bd0dfd4ef5

View File

@@ -116,6 +116,7 @@ export function initDrag(
let initialX = 0; let initialX = 0;
let initialStrength = 0; let initialStrength = 0;
let currentDragElement = null; let currentDragElement = null;
let hasMoved = false;
const { onDragStart, onDragEnd } = dragCallbacks; const { onDragStart, onDragEnd } = dragCallbacks;
// Create a drag handler using pointer events for Vue DOM render mode compatibility // Create a drag handler using pointer events for Vue DOM render mode compatibility
@@ -138,6 +139,7 @@ export function initDrag(
initialX = e.clientX; initialX = e.clientX;
initialStrength = isClipStrength ? loraData.clipStrength : loraData.strength; initialStrength = isClipStrength ? loraData.clipStrength : loraData.strength;
isDragging = true; isDragging = true;
hasMoved = false;
activePointerId = e.pointerId; activePointerId = e.pointerId;
currentDragElement = e.currentTarget; currentDragElement = e.currentTarget;
@@ -145,24 +147,33 @@ export function initDrag(
const target = e.currentTarget; const target = e.currentTarget;
target.setPointerCapture(e.pointerId); target.setPointerCapture(e.pointerId);
// Add class to body to enforce cursor style globally // Prevent text selection
e.preventDefault();
});
dragEl.addEventListener('pointermove', (e) => {
if (!isDragging) return;
// Track if pointer moved significantly (more than 3 pixels)
if (Math.abs(e.clientX - initialX) > 3) {
hasMoved = true;
}
// Only stop propagation if we've started dragging (moved beyond threshold)
if (hasMoved) {
e.stopPropagation();
}
// Only process drag if we've moved beyond threshold
if (!hasMoved) return;
// Add class to body to enforce cursor style globally only after drag starts
document.body.classList.add('lm-lora-strength-dragging'); document.body.classList.add('lm-lora-strength-dragging');
if (typeof onDragStart === 'function') { if (typeof onDragStart === 'function') {
onDragStart(); onDragStart();
} }
// Prevent text selection and default behavior
e.preventDefault();
e.stopPropagation();
});
dragEl.addEventListener('pointermove', (e) => {
if (!isDragging) return;
// Stop propagation to prevent canvas from interfering
e.stopPropagation();
// Call the strength adjustment function without updating widget.value during drag // Call the strength adjustment function without updating widget.value during drag
handleStrengthDrag(name, initialStrength, initialX, e, widget, isClipStrength, false); handleStrengthDrag(name, initialStrength, initialX, e, widget, isClipStrength, false);
@@ -173,7 +184,7 @@ export function initDrag(
const loraData = lorasData.find(l => l.name === name); const loraData = lorasData.find(l => l.name === name);
if (loraData) { if (loraData) {
const strengthValue = isClipStrength ? loraData.clipStrength : loraData.strength; const strengthValue = isClipStrength ? loraData.clipStrength : loraData.strength;
strengthInput.value = strengthValue; strengthInput.value = Number(strengthValue).toFixed(2);
} }
} }
@@ -185,9 +196,12 @@ export function initDrag(
const endDrag = (e) => { const endDrag = (e) => {
if (!isDragging) return; if (!isDragging) return;
e.stopPropagation(); // Only stop propagation if we actually dragged
if (hasMoved) {
e.stopPropagation();
}
// Release pointer capture if still have the element // Release pointer capture if still have the element
if (currentDragElement && activePointerId !== null) { if (currentDragElement && activePointerId !== null) {
try { try {
@@ -196,21 +210,26 @@ export function initDrag(
// Ignore errors if element is no longer in DOM // Ignore errors if element is no longer in DOM
} }
} }
const wasDragging = hasMoved;
isDragging = false; isDragging = false;
hasMoved = false;
activePointerId = null; activePointerId = null;
currentDragElement = null; currentDragElement = null;
// Remove the class to restore normal cursor behavior // Remove the class to restore normal cursor behavior
document.body.classList.remove('lm-lora-strength-dragging'); document.body.classList.remove('lm-lora-strength-dragging');
if (typeof onDragEnd === 'function') { // Only call onDragEnd and re-render if we actually dragged
onDragEnd(); if (wasDragging) {
} if (typeof onDragEnd === 'function') {
onDragEnd();
// Now do the re-render after drag is complete }
if (renderFunction) {
renderFunction(widget.value, widget); // Now do the re-render after drag is complete
if (renderFunction) {
renderFunction(widget.value, widget);
}
} }
}; };
@@ -225,6 +244,7 @@ export function initHeaderDrag(headerEl, widget, renderFunction) {
let initialX = 0; let initialX = 0;
let initialStrengths = []; let initialStrengths = [];
let currentHeaderElement = null; let currentHeaderElement = null;
let hasMoved = false;
// Add cursor style to indicate draggable // Add cursor style to indicate draggable
// Create a drag handler using pointer events for Vue DOM render mode compatibility // Create a drag handler using pointer events for Vue DOM render mode compatibility
@@ -246,6 +266,7 @@ export function initHeaderDrag(headerEl, widget, renderFunction) {
})); }));
isDragging = true; isDragging = true;
hasMoved = false;
activePointerId = e.pointerId; activePointerId = e.pointerId;
currentHeaderElement = e.currentTarget; currentHeaderElement = e.currentTarget;
@@ -253,20 +274,30 @@ export function initHeaderDrag(headerEl, widget, renderFunction) {
const target = e.currentTarget; const target = e.currentTarget;
target.setPointerCapture(e.pointerId); target.setPointerCapture(e.pointerId);
// Add class to body to enforce cursor style globally // Prevent text selection
document.body.classList.add('lm-lora-strength-dragging');
// Prevent text selection and default behavior
e.preventDefault(); e.preventDefault();
e.stopPropagation();
}); });
// Handle pointer move for dragging // Handle pointer move for dragging
headerEl.addEventListener('pointermove', (e) => { headerEl.addEventListener('pointermove', (e) => {
if (!isDragging) return; if (!isDragging) return;
e.stopPropagation(); // Track if pointer moved significantly (more than 3 pixels)
if (Math.abs(e.clientX - initialX) > 3) {
hasMoved = true;
}
// Only stop propagation if we've started dragging (moved beyond threshold)
if (hasMoved) {
e.stopPropagation();
}
// Only process drag if we've moved beyond threshold
if (!hasMoved) return;
// Add class to body to enforce cursor style globally only after drag starts
document.body.classList.add('lm-lora-strength-dragging');
// Call the strength adjustment function without updating widget.value during drag // Call the strength adjustment function without updating widget.value during drag
handleAllStrengthsDrag(initialStrengths, initialX, e, widget, false); handleAllStrengthsDrag(initialStrengths, initialX, e, widget, false);
@@ -282,9 +313,12 @@ export function initHeaderDrag(headerEl, widget, renderFunction) {
const endDrag = (e) => { const endDrag = (e) => {
if (!isDragging) return; if (!isDragging) return;
e.stopPropagation(); // Only stop propagation if we actually dragged
if (hasMoved) {
e.stopPropagation();
}
// Release pointer capture if still have the element // Release pointer capture if still have the element
if (currentHeaderElement && activePointerId !== null) { if (currentHeaderElement && activePointerId !== null) {
try { try {
@@ -293,16 +327,18 @@ export function initHeaderDrag(headerEl, widget, renderFunction) {
// Ignore errors if element is no longer in DOM // Ignore errors if element is no longer in DOM
} }
} }
const wasDragging = hasMoved;
isDragging = false; isDragging = false;
hasMoved = false;
activePointerId = null; activePointerId = null;
currentHeaderElement = null; currentHeaderElement = null;
// Remove the class to restore normal cursor behavior // Remove the class to restore normal cursor behavior
document.body.classList.remove('lm-lora-strength-dragging'); document.body.classList.remove('lm-lora-strength-dragging');
// Now do a re-render after drag is complete // Only re-render if we actually dragged
if (renderFunction) { if (wasDragging && renderFunction) {
renderFunction(widget.value, widget); renderFunction(widget.value, widget);
} }
}; };
@@ -322,12 +358,13 @@ export function initReorderDrag(dragHandle, loraName, widget, renderFunction) {
let dropIndicator = null; let dropIndicator = null;
let container = null; let container = null;
let scale = 1; let scale = 1;
let hasMoved = false;
dragHandle.addEventListener('pointerdown', (e) => { dragHandle.addEventListener('pointerdown', (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
isDragging = true; isDragging = true;
hasMoved = false;
activePointerId = e.pointerId; activePointerId = e.pointerId;
draggedElement = dragHandle.closest('.lm-lora-entry'); draggedElement = dragHandle.closest('.lm-lora-entry');
container = draggedElement.parentElement; container = draggedElement.parentElement;
@@ -335,32 +372,43 @@ export function initReorderDrag(dragHandle, loraName, widget, renderFunction) {
// Capture pointer to receive all subsequent events regardless of stopPropagation // Capture pointer to receive all subsequent events regardless of stopPropagation
const target = e.currentTarget; const target = e.currentTarget;
target.setPointerCapture(e.pointerId); target.setPointerCapture(e.pointerId);
// Add dragging class and visual feedback
draggedElement.classList.add('lm-lora-entry--dragging');
// Create single drop indicator with absolute positioning
dropIndicator = createDropIndicator();
// Make container relatively positioned for absolute indicator
const originalPosition = container.style.position;
container.style.position = 'relative';
container.appendChild(dropIndicator);
// Store original position for cleanup
container._originalPosition = originalPosition;
// Add global cursor style
document.body.classList.add('lm-lora-reordering');
// Store workflow scale for accurate positioning
scale = app.canvas.ds.scale;
}); });
dragHandle.addEventListener('pointermove', (e) => { dragHandle.addEventListener('pointermove', (e) => {
if (!isDragging || !draggedElement || !dropIndicator) return; if (!isDragging || !draggedElement) return;
// Track if pointer moved significantly (more than 3 pixels vertically)
if (Math.abs(e.movementY) > 3) {
hasMoved = true;
}
// Only stop propagation and process drag if we've moved beyond threshold
if (!hasMoved) return;
// Stop propagation and start drag visuals
e.stopPropagation(); e.stopPropagation();
// Add dragging class and visual feedback only after drag starts
if (!dropIndicator) {
draggedElement.classList.add('lm-lora-entry--dragging');
// Create single drop indicator with absolute positioning
dropIndicator = createDropIndicator();
// Make container relatively positioned for absolute indicator
const originalPosition = container.style.position;
container.style.position = 'relative';
container.appendChild(dropIndicator);
// Store original position for cleanup
container._originalPosition = originalPosition;
// Add global cursor style
document.body.classList.add('lm-lora-reordering');
// Store workflow scale for accurate positioning
scale = app.canvas.ds.scale;
}
const targetIndex = getDropTargetIndex(container, e.clientY); const targetIndex = getDropTargetIndex(container, e.clientY);
const entries = container.querySelectorAll('.lm-lora-entry, .lm-lora-clip-entry'); const entries = container.querySelectorAll('.lm-lora-entry, .lm-lora-clip-entry');
@@ -396,60 +444,79 @@ export function initReorderDrag(dragHandle, loraName, widget, renderFunction) {
}); });
dragHandle.addEventListener('pointerup', (e) => { dragHandle.addEventListener('pointerup', (e) => {
e.stopPropagation(); // Only stop propagation if we actually dragged
if (hasMoved) {
e.stopPropagation();
}
// Always reset cursor regardless of isDragging state // Always reset cursor regardless of isDragging state
document.body.classList.remove('lm-lora-reordering'); document.body.classList.remove('lm-lora-reordering');
if (!isDragging || !draggedElement) return; if (!isDragging || !draggedElement) {
// Release pointer capture even if not dragging
const target = e.currentTarget;
if (activePointerId !== null) {
target.releasePointerCapture(activePointerId);
}
isDragging = false;
hasMoved = false;
activePointerId = null;
return;
}
// Release pointer capture // Release pointer capture
const target = e.currentTarget; const target = e.currentTarget;
if (activePointerId !== null) { if (activePointerId !== null) {
target.releasePointerCapture(activePointerId); target.releasePointerCapture(activePointerId);
} }
const targetIndex = getDropTargetIndex(container, e.clientY); const wasDragging = hasMoved;
isDragging = false;
// Get current LoRA data hasMoved = false;
const lorasData = parseLoraValue(widget.value); activePointerId = null;
const currentIndex = lorasData.findIndex(l => l.name === loraName);
// Only process reordering if we actually dragged
if (currentIndex !== -1 && currentIndex !== targetIndex) { if (wasDragging) {
// Calculate actual target index (excluding clip entries from count) const targetIndex = getDropTargetIndex(container, e.clientY);
const loraEntries = container.querySelectorAll('.lm-lora-entry');
let actualTargetIndex = targetIndex; // Get current LoRA data
const lorasData = parseLoraValue(widget.value);
// Adjust target index if it's beyond the number of actual LoRA entries const currentIndex = lorasData.findIndex(l => l.name === loraName);
if (actualTargetIndex > loraEntries.length) {
actualTargetIndex = loraEntries.length; if (currentIndex !== -1 && currentIndex !== targetIndex) {
} // Calculate actual target index (excluding clip entries from count)
const loraEntries = container.querySelectorAll('.lm-lora-entry');
// Move the LoRA let actualTargetIndex = targetIndex;
const newLoras = [...lorasData];
const [moved] = newLoras.splice(currentIndex, 1); // Adjust target index if it's beyond the number of actual LoRA entries
newLoras.splice(actualTargetIndex > currentIndex ? actualTargetIndex - 1 : actualTargetIndex, 0, moved); if (actualTargetIndex > loraEntries.length) {
actualTargetIndex = loraEntries.length;
widget.value = formatLoraValue(newLoras); }
if (widget.callback) { // Move the LoRA
widget.callback(widget.value); const newLoras = [...lorasData];
} const [moved] = newLoras.splice(currentIndex, 1);
newLoras.splice(actualTargetIndex > currentIndex ? actualTargetIndex - 1 : actualTargetIndex, 0, moved);
// Re-render
if (renderFunction) { widget.value = formatLoraValue(newLoras);
renderFunction(widget.value, widget);
if (widget.callback) {
widget.callback(widget.value);
}
// Re-render
if (renderFunction) {
renderFunction(widget.value, widget);
}
} }
} }
// Cleanup // Cleanup
isDragging = false;
activePointerId = null;
if (draggedElement) { if (draggedElement) {
draggedElement.classList.remove('lm-lora-entry--dragging'); draggedElement.classList.remove('lm-lora-entry--dragging');
draggedElement = null; draggedElement = null;
} }
if (dropIndicator && container) { if (dropIndicator && container) {
container.removeChild(dropIndicator); container.removeChild(dropIndicator);
// Restore original position // Restore original position
@@ -457,32 +524,47 @@ export function initReorderDrag(dragHandle, loraName, widget, renderFunction) {
delete container._originalPosition; delete container._originalPosition;
dropIndicator = null; dropIndicator = null;
} }
container = null; container = null;
}); });
dragHandle.addEventListener('pointercancel', (e) => { dragHandle.addEventListener('pointercancel', (e) => {
e.stopPropagation(); // Only stop propagation if we actually dragged
if (hasMoved) {
e.stopPropagation();
}
// Always reset cursor regardless of isDragging state // Always reset cursor regardless of isDragging state
document.body.classList.remove('lm-lora-reordering'); document.body.classList.remove('lm-lora-reordering');
if (!isDragging || !draggedElement) return; if (!isDragging || !draggedElement) {
// Release pointer capture even if not dragging
const target = e.currentTarget;
if (activePointerId !== null) {
target.releasePointerCapture(activePointerId);
}
isDragging = false;
hasMoved = false;
activePointerId = null;
return;
}
// Release pointer capture // Release pointer capture
const target = e.currentTarget; const target = e.currentTarget;
if (activePointerId !== null) { if (activePointerId !== null) {
target.releasePointerCapture(activePointerId); target.releasePointerCapture(activePointerId);
} }
// Cleanup without reordering
isDragging = false; isDragging = false;
hasMoved = false;
activePointerId = null; activePointerId = null;
// Cleanup without reordering
if (draggedElement) { if (draggedElement) {
draggedElement.classList.remove('lm-lora-entry--dragging'); draggedElement.classList.remove('lm-lora-entry--dragging');
draggedElement = null; draggedElement = null;
} }
if (dropIndicator && container) { if (dropIndicator && container) {
container.removeChild(dropIndicator); container.removeChild(dropIndicator);
// Restore original position // Restore original position
@@ -490,7 +572,7 @@ export function initReorderDrag(dragHandle, loraName, widget, renderFunction) {
delete container._originalPosition; delete container._originalPosition;
dropIndicator = null; dropIndicator = null;
} }
container = null; container = null;
}); });
} }