From 0afae99b3016d5fafbbb0ea481ce2f20fcd0f6fc Mon Sep 17 00:00:00 2001 From: ausboss <102309304+ausboss@users.noreply.github.com> Date: Sat, 24 Oct 2026 14:58:33 -0500 Subject: [PATCH] LoRA Loader: Shift-click ticks a run in the picker Shift-click a tick box or name ticks every file from the last one ticked. Ctrl+Enter ticks the highlighted file and Shift+Enter ticks the run up to it. --- CHANGELOG.md | 4 ++-- js/docs/AUSBOSS_NODES_LoraLoader.md | 8 ++++--- js/lora_loader/index.js | 33 +++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d114d48..8b685a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ All notable changes to ComfyUI-AusBoss are documented here. ## Unreleased - **LoRA Loader 🆎 can add several LoRAs at once.** In the **+ LoRA** list, - tick the box beside each file you want (or Ctrl-click its name), then - click **Add N LoRAs** or press Enter. Ticks stay while you search, and + tick the box beside each file you want (or Ctrl-click its name; Shift-click + ticks a whole run), then click **Add N LoRAs** or press Enter. Ticks stay while you search, and files already in the stack are marked "in stack". One click on a file still adds just that file, and a folder name still adds the whole folder. diff --git a/js/docs/AUSBOSS_NODES_LoraLoader.md b/js/docs/AUSBOSS_NODES_LoraLoader.md index 68d5b13..af3649c 100644 --- a/js/docs/AUSBOSS_NODES_LoraLoader.md +++ b/js/docs/AUSBOSS_NODES_LoraLoader.md @@ -157,11 +157,13 @@ its height on rows, not chrome. Left to right: **+ LoRA** opens one list of files grouped by folder. Click a file to add one LoRA, or click a folder name to add all its LoRAs, including nested folders. To add several files from different folders, tick the box beside -each one (or **Ctrl**/**Shift**-click its name), then click **Add N LoRAs** -at the bottom or press **Enter**. Ticks stay while you search, so you can +each one (or **Ctrl**-click its name), then click **Add N LoRAs** at the +bottom or press **Enter**. **Shift**-click ticks every file between the +last one you ticked and the one you click. Ticks stay while you search, so you can gather files from several searches; **Clear** unticks them all. Files that are already in the stack say **in stack** and have no box. With the -keyboard, **Ctrl+Enter** or **Shift+Enter** ticks the highlighted file. Use the arrow beside a folder to collapse or expand it without +keyboard, **Ctrl+Enter** ticks the highlighted file and **Shift+Enter** +ticks the run up to it. Use the arrow beside a folder to collapse or expand it without adding anything. Folded folders are remembered in this browser. Search reveals matching files; clearing it brings back your folded view. You can also fold folders while searching. diff --git a/js/lora_loader/index.js b/js/lora_loader/index.js index 29e9dc6..b2b5889 100644 --- a/js/lora_loader/index.js +++ b/js/lora_loader/index.js @@ -1144,13 +1144,37 @@ function openPicker(state, index, anchor, { keyboard = false } = {}) { updateTickBar(); }; + // The last file ticked or unticked one by one: Shift ticks the run of + // files shown between it and the next one, as Shift-click does on rows. + let tickAnchor = null; const toggleTick = (name) => { const at = ticked.indexOf(name); if (at >= 0) ticked.splice(at, 1); else ticked.push(name); + tickAnchor = name; renderTicks(); }; + const tickRun = (name) => { + const shown = [...list.querySelectorAll(".ausboss-lora-option.tickable:not(.instack)")] + .map((option) => option.title); + const from = shown.indexOf(tickAnchor); + const to = shown.indexOf(name); + if (from < 0 || to < 0) { + toggleTick(name); + return; + } + for (const file of shown.slice(Math.min(from, to), Math.max(from, to) + 1)) { + if (!ticked.includes(file)) ticked.push(file); + } + tickAnchor = name; + renderTicks(); + }; + const tickWith = (event, name) => { + if (event.shiftKey && !event.ctrlKey && !event.metaKey) tickRun(name); + else toggleTick(name); + }; + let lastPointer = null; const pointerMoved = (event) => { const moved = !lastPointer || lastPointer.x !== event.clientX || lastPointer.y !== event.clientY; @@ -1192,7 +1216,7 @@ function openPicker(state, index, anchor, { keyboard = false } = {}) { } tick.addEventListener("click", (event) => { event.stopPropagation(); - toggleTick(name); + tickWith(event, name); search.focus({ preventScroll: true }); }); option.prepend(tick); @@ -1232,7 +1256,7 @@ function openPicker(state, index, anchor, { keyboard = false } = {}) { option.addEventListener("pointerleave", hideHoverThumb); option.addEventListener("click", (event) => { if (tickable && (event.ctrlKey || event.metaKey || event.shiftKey)) { - toggleTick(name); + tickWith(event, name); search.focus({ preventScroll: true }); return; } @@ -1293,10 +1317,11 @@ function openPicker(state, index, anchor, { keyboard = false } = {}) { highlight = event.key === "Home" ? 0 : options.length - 1; renderList(); } else if (event.key === "Enter" && adding && (event.ctrlKey || event.metaKey || event.shiftKey)) { - // Ctrl/Shift+Enter ticks the highlighted file, as Ctrl-click does. + // Ctrl+Enter ticks the highlighted file and Shift+Enter the run up + // to it, as Ctrl-click and Shift-click do. event.preventDefault(); const entry = options[highlight]; - if (entry?.kind === "file" && !entry.inStack) toggleTick(entry.name); + if (entry?.kind === "file" && !entry.inStack) tickWith(event, entry.name); } else if (event.key === "Enter") { event.preventDefault(); // With files ticked, Enter adds them all.