diff --git a/custom-nodes/js/javascript_selection_toolbox.mdx b/custom-nodes/js/javascript_selection_toolbox.mdx new file mode 100644 index 00000000..4903a6c0 --- /dev/null +++ b/custom-nodes/js/javascript_selection_toolbox.mdx @@ -0,0 +1,217 @@ +--- +title: "Selection Toolbox" +--- + +The Selection Toolbox API allows extensions to add custom action buttons that appear when nodes are selected on the canvas. This provides quick access to context-sensitive commands for selected items (nodes, groups, etc.). + +## Basic Usage + +To add commands to the selection toolbox, your extension needs to: +1. Define commands with the standard [command interface](https://docs.comfy.org/custom-nodes/js/javascript_commands_keybindings) +2. Implement the `getSelectionToolboxCommands` method to specify which commands appear in the toolbox + +Note: The `getSelectionToolboxCommands` method is called for each item in the selection set whenever a new selection is made. + +```javascript +app.registerExtension({ + name: "MyExtension", + commands: [ + { + id: "my-extension.duplicate-special", + label: "Duplicate Special", + icon: "pi pi-copy", + function: (selectedItem) => { + // Your command logic here + console.log("Duplicating selected nodes with special behavior"); + } + } + ], + getSelectionToolboxCommands: (selectedItem) => { + // Return array of command IDs to show in the toolbox + return ["my-extension.duplicate-special"]; + } +}); +``` + +## Command Definition + +Commands for the selection toolbox use the standard ComfyUI command interface: + +```javascript +{ + id: string, // Unique identifier for the command + label: string, // Display text for the button tooltip + icon?: string, // Icon class for the button (optional) + function: (selectedItem) => void // Function executed when clicked +} +``` + +The `function` receives the selected item(s) as a parameter, allowing you to perform actions on the current selection. + +## Icon Options + +Selection toolbox buttons support the same icon libraries as other UI elements: + +- PrimeVue icons: `pi pi-[icon-name]` (e.g., `pi pi-star`) +- Material Design icons: `mdi mdi-[icon-name]` (e.g., `mdi mdi-content-copy`) + +## Dynamic Command Visibility + +The `getSelectionToolboxCommands` method is called each time the selection changes, allowing you to show different commands based on what's selected: + +```javascript +app.registerExtension({ + name: "ContextualCommands", + commands: [ + { + id: "my-ext.align-nodes", + label: "Align Nodes", + icon: "pi pi-align-left", + function: () => { + // Align multiple nodes + } + }, + { + id: "my-ext.configure-single", + label: "Configure", + icon: "pi pi-cog", + function: () => { + // Configure single node + } + } + ], + getSelectionToolboxCommands: (selectedItem) => { + const selectedItems = app.canvas.selectedItems; + const itemCount = selectedItems ? selectedItems.size : 0; + + if (itemCount > 1) { + // Show alignment command for multiple items + return ["my-ext.align-nodes"]; + } else if (itemCount === 1) { + // Show configuration for single item + return ["my-ext.configure-single"]; + } + + return []; + } +}); +``` + +## Working with Selected Items + +Access information about selected items through the app's canvas object. The `selectedItems` property is a Set that includes nodes, groups, and other canvas elements: + +```javascript +app.registerExtension({ + name: "SelectionInfo", + commands: [ + { + id: "my-ext.show-info", + label: "Show Selection Info", + icon: "pi pi-info-circle", + function: () => { + const selectedItems = app.canvas.selectedItems; + + if (selectedItems && selectedItems.size > 0) { + console.log(`Selected ${selectedItems.size} items`); + + // Iterate through selected items + selectedItems.forEach(item => { + if (item.type) { + console.log(`Item: ${item.type} (ID: ${item.id})`); + } + }); + } + } + } + ], + getSelectionToolboxCommands: () => ["my-ext.show-info"] +}); +``` + +## Complete Example + +Here's a simple example showing various selection toolbox features: + +```javascript +app.registerExtension({ + name: "SelectionTools", + commands: [ + { + id: "selection-tools.count", + label: "Count Selection", + icon: "pi pi-hashtag", + function: () => { + const count = app.canvas.selectedItems?.size || 0; + app.extensionManager.toast.add({ + severity: "info", + summary: "Selection Count", + detail: `You have ${count} item${count !== 1 ? 's' : ''} selected`, + life: 3000 + }); + } + }, + { + id: "selection-tools.copy-ids", + label: "Copy IDs", + icon: "pi pi-copy", + function: () => { + const items = Array.from(app.canvas.selectedItems || []); + const ids = items.map(item => item.id).filter(id => id !== undefined); + + if (ids.length > 0) { + navigator.clipboard.writeText(ids.join(', ')); + app.extensionManager.toast.add({ + severity: "success", + summary: "Copied", + detail: `Copied ${ids.length} IDs to clipboard`, + life: 2000 + }); + } + } + }, + { + id: "selection-tools.log-types", + label: "Log Types", + icon: "pi pi-info-circle", + function: () => { + const items = Array.from(app.canvas.selectedItems || []); + const typeCount = {}; + + items.forEach(item => { + const type = item.type || 'unknown'; + typeCount[type] = (typeCount[type] || 0) + 1; + }); + + console.log("Selection types:", typeCount); + } + } + ], + + getSelectionToolboxCommands: (selectedItem) => { + const selectedItems = app.canvas.selectedItems; + const itemCount = selectedItems ? selectedItems.size : 0; + + if (itemCount === 0) return []; + + const commands = ["selection-tools.count", "selection-tools.log-types"]; + + // Only show copy command if items have IDs + const hasIds = Array.from(selectedItems).some(item => item.id !== undefined); + if (hasIds) { + commands.push("selection-tools.copy-ids"); + } + + return commands; + } +}); +``` + +## Notes + +- The selection toolbox must be enabled in settings: `Comfy.Canvas.SelectionToolbox` +- Commands must be defined in the `commands` array before being referenced in `getSelectionToolboxCommands` +- The toolbox automatically updates when the selection changes +- The `getSelectionToolboxCommands` method is called for each item in the selection set whenever a new selection is made +- Use `app.canvas.selectedItems` (a Set) to access all selected items including nodes, groups, and other canvas elements +- For backward compatibility, `app.canvas.selected_nodes` still exists but only contains nodes \ No newline at end of file diff --git a/docs.json b/docs.json index 48cd6fc5..67ae8001 100644 --- a/docs.json +++ b/docs.json @@ -515,6 +515,7 @@ "custom-nodes/js/javascript_about_panel_badges", "custom-nodes/js/javascript_bottom_panel_tabs", "custom-nodes/js/javascript_sidebar_tabs", + "custom-nodes/js/javascript_selection_toolbox", "custom-nodes/js/javascript_commands_keybindings", "custom-nodes/js/javascript_topbar_menu", "custom-nodes/js/javascript_examples" @@ -1067,6 +1068,7 @@ "zh-CN/custom-nodes/js/javascript_about_panel_badges", "zh-CN/custom-nodes/js/javascript_bottom_panel_tabs", "zh-CN/custom-nodes/js/javascript_sidebar_tabs", + "zh-CN/custom-nodes/js/javascript_selection_toolbox", "zh-CN/custom-nodes/js/javascript_commands_keybindings", "zh-CN/custom-nodes/js/javascript_topbar_menu", "zh-CN/custom-nodes/js/javascript_examples" diff --git a/zh-CN/custom-nodes/js/javascript_selection_toolbox.mdx b/zh-CN/custom-nodes/js/javascript_selection_toolbox.mdx new file mode 100644 index 00000000..d303b405 --- /dev/null +++ b/zh-CN/custom-nodes/js/javascript_selection_toolbox.mdx @@ -0,0 +1,217 @@ +--- +title: "选择工具箱" +--- + +Selection Toolbox API 允许扩展在画布上选择节点时添加自定义操作按钮。这为所选项目(节点、组等)提供了对上下文敏感命令的快速访问。 + +## 基本用法 + +要向选择工具箱添加命令,您的扩展需要: +1. 使用标准[命令接口](https://docs.comfy.org/custom-nodes/js/javascript_commands_keybindings)定义命令 +2. 实现 `getSelectionToolboxCommands` 方法来指定工具箱中显示哪些命令 + +注意:每当进行新选择时,`getSelectionToolboxCommands` 方法会为选择集中的每个项目调用。 + +```javascript +app.registerExtension({ + name: "MyExtension", + commands: [ + { + id: "my-extension.duplicate-special", + label: "特殊复制", + icon: "pi pi-copy", + function: (selectedItem) => { + // 您的命令逻辑 + console.log("使用特殊行为复制选定的节点"); + } + } + ], + getSelectionToolboxCommands: (selectedItem) => { + // 返回要在工具箱中显示的命令 ID 数组 + return ["my-extension.duplicate-special"]; + } +}); +``` + +## 命令定义 + +选择工具箱的命令使用标准的 ComfyUI 命令接口: + +```javascript +{ + id: string, // 命令的唯一标识符 + label: string, // 按钮工具提示的显示文本 + icon?: string, // 按钮的图标类(可选) + function: (selectedItem) => void // 单击时执行的函数 +} +``` + +`function` 接收选定的项作为参数,允许您对当前选择执行操作。 + +## 图标选项 + +选择工具箱按钮支持与其他 UI 元素相同的图标库: + +- PrimeVue 图标:`pi pi-[icon-name]`(例如 `pi pi-star`) +- Material Design 图标:`mdi mdi-[icon-name]`(例如 `mdi mdi-content-copy`) + +## 动态命令可见性 + +每次选择更改时都会调用 `getSelectionToolboxCommands` 方法,允许您根据选择的内容显示不同的命令: + +```javascript +app.registerExtension({ + name: "ContextualCommands", + commands: [ + { + id: "my-ext.align-nodes", + label: "对齐节点", + icon: "pi pi-align-left", + function: () => { + // 对齐多个节点 + } + }, + { + id: "my-ext.configure-single", + label: "配置", + icon: "pi pi-cog", + function: () => { + // 配置单个节点 + } + } + ], + getSelectionToolboxCommands: (selectedItem) => { + const selectedItems = app.canvas.selectedItems; + const itemCount = selectedItems ? selectedItems.size : 0; + + if (itemCount > 1) { + // 为多个项目显示对齐命令 + return ["my-ext.align-nodes"]; + } else if (itemCount === 1) { + // 为单个项目显示配置 + return ["my-ext.configure-single"]; + } + + return []; + } +}); +``` + +## 使用选定的项目 + +通过应用程序的画布对象访问有关选定项目的信息。`selectedItems` 属性是一个 Set,包含节点、组和其他画布元素: + +```javascript +app.registerExtension({ + name: "SelectionInfo", + commands: [ + { + id: "my-ext.show-info", + label: "显示选择信息", + icon: "pi pi-info-circle", + function: () => { + const selectedItems = app.canvas.selectedItems; + + if (selectedItems && selectedItems.size > 0) { + console.log(`选择了 ${selectedItems.size} 个项目`); + + // 遍历选定的项目 + selectedItems.forEach(item => { + if (item.type) { + console.log(`项目:${item.type}(ID: ${item.id})`); + } + }); + } + } + } + ], + getSelectionToolboxCommands: () => ["my-ext.show-info"] +}); +``` + +## 完整示例 + +这是一个展示各种选择工具箱功能的简单示例: + +```javascript +app.registerExtension({ + name: "SelectionTools", + commands: [ + { + id: "selection-tools.count", + label: "计数选择", + icon: "pi pi-hashtag", + function: () => { + const count = app.canvas.selectedItems?.size || 0; + app.extensionManager.toast.add({ + severity: "info", + summary: "选择计数", + detail: `您选择了 ${count} 个项目`, + life: 3000 + }); + } + }, + { + id: "selection-tools.copy-ids", + label: "复制 ID", + icon: "pi pi-copy", + function: () => { + const items = Array.from(app.canvas.selectedItems || []); + const ids = items.map(item => item.id).filter(id => id !== undefined); + + if (ids.length > 0) { + navigator.clipboard.writeText(ids.join(', ')); + app.extensionManager.toast.add({ + severity: "success", + summary: "已复制", + detail: `已复制 ${ids.length} 个 ID 到剪贴板`, + life: 2000 + }); + } + } + }, + { + id: "selection-tools.log-types", + label: "记录类型", + icon: "pi pi-info-circle", + function: () => { + const items = Array.from(app.canvas.selectedItems || []); + const typeCount = {}; + + items.forEach(item => { + const type = item.type || 'unknown'; + typeCount[type] = (typeCount[type] || 0) + 1; + }); + + console.log("选择类型:", typeCount); + } + } + ], + + getSelectionToolboxCommands: (selectedItem) => { + const selectedItems = app.canvas.selectedItems; + const itemCount = selectedItems ? selectedItems.size : 0; + + if (itemCount === 0) return []; + + const commands = ["selection-tools.count", "selection-tools.log-types"]; + + // 仅在项目有 ID 时显示复制命令 + const hasIds = Array.from(selectedItems).some(item => item.id !== undefined); + if (hasIds) { + commands.push("selection-tools.copy-ids"); + } + + return commands; + } +}); +``` + +## 注意事项 + +- 必须在设置中启用选择工具箱:`Comfy.Canvas.SelectionToolbox` +- 在 `getSelectionToolboxCommands` 中引用命令之前,必须在 `commands` 数组中定义命令 +- 选择更改时工具箱会自动更新 +- 每当进行新选择时,`getSelectionToolboxCommands` 方法会为选择集中的每个项目调用 +- 使用 `app.canvas.selectedItems`(一个 Set)来访问所有选定的项目,包括节点、组和其他画布元素 +- 为了向后兼容,`app.canvas.selected_nodes` 仍然存在,但只包含节点 \ No newline at end of file