From a4d1f67502cd642d8fa8f3fee775b82aa731f65d Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Sat, 30 May 2026 11:42:46 +0300 Subject: [PATCH] Fix rating picker clicks: use canvas button widget instead of DOM element addDOMWidget clicks were swallowed by the canvas. Switched to addWidget button which ComfyUI routes correctly. Picker now positions at mouse coords from the widget callback event. Co-Authored-By: Claude Sonnet 4.6 --- web/funpack_rating_picker.js | 71 +++++++++++------------------------- 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/web/funpack_rating_picker.js b/web/funpack_rating_picker.js index 39e857be..892908b1 100644 --- a/web/funpack_rating_picker.js +++ b/web/funpack_rating_picker.js @@ -109,14 +109,6 @@ function injectStyles() { .fp-picker-opt-hint { font-size: 9px; color: #888; line-height: 1.3; } .fp-picker-opt:hover .fp-picker-opt-hint { color: #aaa; } .fp-picker-nuclear { padding: 8px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 5px; } - .fp-picker-btn-label { - text-align: left; width: 100%; padding: 4px 8px; - background: rgba(255,255,255,0.05); - border: 1px solid rgba(255,255,255,0.12); - border-radius: 5px; color: #bbb; cursor: pointer; - font: 11px sans-serif; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - } - .fp-picker-btn-label:hover { background: rgba(255,255,255,0.09); color: #eee; } `; document.head.append(s); } @@ -165,7 +157,7 @@ function makeOption(r, currentValue, accent, onPick) { return btn; } -function openPicker(ratingWidget, buttonEl, onPick) { +function openPicker(ratingWidget, event, onPick) { closePicker(); injectStyles(); @@ -213,20 +205,18 @@ function openPicker(ratingWidget, buttonEl, onPick) { document.body.append(picker); - // Position: below the button, clamped to viewport - const rect = buttonEl.getBoundingClientRect(); + // Position at mouse, clamped to viewport + const cx = event?.clientX ?? window.innerWidth / 2; + const cy = event?.clientY ?? window.innerHeight / 2; requestAnimationFrame(() => { const ph = picker.offsetHeight, pw = picker.offsetWidth; - let top = rect.bottom + 4, left = rect.left; - if (top + ph > window.innerHeight - 8) top = rect.top - ph - 4; - if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8; - picker.style.top = Math.max(8, top) + "px"; - picker.style.left = Math.max(8, left) + "px"; + picker.style.left = Math.max(8, Math.min(cx, window.innerWidth - pw - 8)) + "px"; + picker.style.top = Math.max(8, Math.min(cy, window.innerHeight - ph - 8)) + "px"; }); // Close on outside click const onOutside = (e) => { - if (!picker.contains(e.target) && e.target !== buttonEl) { + if (!picker.contains(e.target)) { closePicker(); document.removeEventListener("mousedown", onOutside, true); } @@ -251,7 +241,6 @@ function hideWidget(widget) { } function setupRatingPicker(node) { - // Avoid double-setup if (node.__fpPickerSetup) return; node.__fpPickerSetup = true; @@ -260,40 +249,24 @@ function setupRatingPicker(node) { hideWidget(ratingWidget); - // DOM button that lives outside the canvas - let buttonEl = node.__fpPickerBtn; - if (!buttonEl) { - buttonEl = document.createElement("button"); - buttonEl.className = "fp-picker-btn-label"; - node.__fpPickerBtn = buttonEl; - } - - const updateBtn = (label) => { - const current = label || ratingWidget.value || FORGET_LABEL; - const waiting = current === FORGET_LABEL; - buttonEl.textContent = waiting ? "Waiting for rating..." : `Rating: ${current}`; - buttonEl.style.opacity = waiting ? "0.5" : "1"; + const getLabel = () => { + const v = ratingWidget.value; + return (!v || v === FORGET_LABEL) ? "Waiting for rating..." : `Rating: ${v}`; }; - updateBtn(ratingWidget.value); - buttonEl.addEventListener("click", () => { - openPicker(ratingWidget, buttonEl, (label) => { + node.widgets = (node.widgets || []).filter((w) => w.__fpPickerWidget !== true); + + const pickerWidget = node.addWidget("button", getLabel(), null, (value, canvas, n, pos, event) => { + openPicker(ratingWidget, event, (label) => { ratingWidget.value = label; ratingWidget.callback?.(label); - updateBtn(label); - closePicker(); + pickerWidget.name = getLabel(); + node.setDirtyCanvas?.(true, true); }); - }); - - // Attach button below the node using a custom DOM widget - node.widgets = (node.widgets || []).filter((w) => w.__fpPickerWidget !== true); - const domWidget = node.addDOMWidget("fp_rating_picker", "div", buttonEl, { - getValue: () => ratingWidget.value, - setValue: (v) => { ratingWidget.value = v; updateBtn(v); }, - serialize: false, - }); - if (domWidget) domWidget.__fpPickerWidget = true; + }, { serialize: false }); + pickerWidget.__fpPickerWidget = true; + node.__fpPickerWidgetRef = pickerWidget; node.setDirtyCanvas?.(true, true); } @@ -302,9 +275,9 @@ function resetRating(node) { if (!ratingWidget) return; ratingWidget.value = FORGET_LABEL; ratingWidget.callback?.(FORGET_LABEL); - if (node.__fpPickerBtn) { - node.__fpPickerBtn.textContent = "Waiting for rating..."; - node.__fpPickerBtn.style.opacity = "0.5"; + if (node.__fpPickerWidgetRef) { + node.__fpPickerWidgetRef.name = "Waiting for rating..."; + node.setDirtyCanvas?.(true, true); } }