Files
JaredTherriault-ComfyUI-JNodes/web/js/ImageDrawer/BasicOptionManagerButtons/BatchSelectionManager.js
T

187 lines
6.0 KiB
JavaScript

// Provides select-all / deselect-all functionality for batch operations in the Image Drawer.
// Tracks checked item count and notifies listeners via multicast callbacks.
import { $el } from "/scripts/ui.js";
import { ContextModel } from "../Contexts.js";
import { ClassInstanceFactory } from "../Core/ImageDrawerModule.js";
import { BatchOptionManagerButton } from "./BatchOptionManagerButton.js";
class BatchSelectionManager extends BatchOptionManagerButton {
constructor(args) {
super(args);
this.selectionCheckbox = null;
this.countText = null;
this.lastCheckedItemCount = {};
this.onCheckedItemCountUpdatedMulticastFunctions = [];
}
makeWidget() {
const superWidget = super.makeWidget();
{
this.selectionCheckbox = $el("input.JNodes-image-drawer-menu-selection-manager-checkbox", {
title: "Toggle select/deselect all",
type: "checkbox",
checked: false,
style: {
pointerEvents: "none"
}
});
superWidget.button.appendChild(this.selectionCheckbox);
}
{
this.countText = $el("label", {
textContent: "(0)",
style: {
color: "white",
pointerEvents: "none"
}
});
superWidget.button.appendChild(this.countText)
}
this.updateWidget();
// Subscribe to imageList Changes
const imageDrawerListInstance = this.imageDrawerInstance.getComponentByName("ImageDrawerList");
imageDrawerListInstance.registerStartChangingImageListMulticastFunction(() => {
this.lastCheckedItemCount = { selectedCount: 0, totalItems: 0 };
this.notifyCheckedItemCountUpdatedMulticastDelegate();
});
imageDrawerListInstance.registerFinishChangingImageListMulticastFunction(() => {
requestAnimationFrame(() => this.updateWidget());
});
return superWidget;
}
onClickButton() {
const counts = this.countCheckedItems();
let bNewCheckedState = true; // Default to select all
if (counts.selectedCount == counts.totalItems) {
// Deselect all
bNewCheckedState = false;
}
this.setSelectedStateOnAll(bNewCheckedState);
}
setSelectedStateOnAll(bNewCheckedState) {
const imageDrawerListInstance = this.imageDrawerInstance.getComponentByName("ImageDrawerList");
const listChildren = imageDrawerListInstance.getImageListChildren();
for (const child of listChildren) {
if (child.setSelected) {
child.setSelected(bNewCheckedState, false); // Don't update this widget after each item, update it after all selections are changed
}
}
this.updateWidget();
}
getValidSelectedItems() {
const imageDrawerListInstance = this.imageDrawerInstance.getComponentByName("ImageDrawerList");
const listChildren = imageDrawerListInstance.getVisibleImageListChildren();
// Count up selected items in the current view
let selectedItems = [];
for (const child of listChildren) {
if (child.bIsCheckboxSelectorChecked && child.bIsCheckboxSelectorChecked == true) {
selectedItems.push(child);
}
}
return selectedItems;
}
countCheckedItems() {
const imageDrawerListInstance = this.imageDrawerInstance.getComponentByName("ImageDrawerList");
const listChildren = imageDrawerListInstance.getVisibleImageListChildren();
const selectedCount = this.getValidSelectedItems().length;
this.lastCheckedItemCount = { selectedCount: selectedCount, totalItems: listChildren.length };
this.notifyCheckedItemCountUpdatedMulticastDelegate();
return this.lastCheckedItemCount;
}
registerCheckedItemCountUpdatedMulticastFunction(inFunction) {
if (typeof inFunction == "function") {
this.onCheckedItemCountUpdatedMulticastFunctions.push(inFunction);
}
}
notifyCheckedItemCountUpdatedMulticastDelegate() {
// Filter out invalid delegates
this.onCheckedItemCountUpdatedMulticastFunctions = this.onCheckedItemCountUpdatedMulticastFunctions.filter(func => func !== null && func !== undefined);
for (const func of this.onCheckedItemCountUpdatedMulticastFunctions) {
func(this.lastCheckedItemCount);
}
}
updateWidget(bUpdateCount = true) {
if (bUpdateCount) {
this.countCheckedItems();
}
// Set widget visibilities and text
this.selectionCheckbox.indeterminate = false;
if (this.lastCheckedItemCount.selectedCount == 0) {
this.selectionCheckbox.checked = false;
} else if (this.lastCheckedItemCount.selectedCount == this.lastCheckedItemCount.totalItems) {
this.selectionCheckbox.checked = true;
} else { // selectedCount < listChildren.length or perhaps some kind of computer rogue state
this.selectionCheckbox.indeterminate = true;
}
const newText =
`(${this.lastCheckedItemCount.selectedCount}/${this.lastCheckedItemCount.totalItems})`;
if (this.countText.textContent !== newText) {
this.countText.textContent = newText;
}
// Hide selector for model contexts as it's not currently implemented
const imageDrawerContextSelectorInstance = this.imageDrawerInstance.getComponentByName("ImageDrawerContextSelector");
const currentContext = imageDrawerContextSelectorInstance.getCurrentContextObject();
const bIsContextModel = currentContext instanceof ContextModel;
this.setWidgetVisible(!bIsContextModel);
}
}
const factoryInstance = new ClassInstanceFactory(BatchSelectionManager, {
tooltipText: "Toggle select/deselect all", buttonClass: "JNodes-image-drawer-menu-selection-manager-button"
});