# JavaScript Annotated Examples ## Summary A growing collection of fragments of example code for ComfyUI custom nodes JavaScript development. ## Right Click Menus ### Background Menu The main background menu (right-click on the canvas) is generated by a call to `LGraph.getCanvasMenuOptions`. One way to add your own menu options is to hijack this call: ```javascript /* in setup() */ const original_getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions; LGraphCanvas.prototype.getCanvasMenuOptions = function () { // get the basic options const options = original_getCanvasMenuOptions.apply(this, arguments); options.push(null); // inserts a divider options.push({ content: "The text for the menu", callback: async () => { // do whatever } }) return options; } ``` ### Node Menu When you right click on a node, the menu is similarly generated by `node.getExtraMenuOptions`. But instead of returning an options object, this one gets it passed in… ```javascript /* in beforeRegisterNodeDef() */ if (nodeType?.comfyClass=="MyNodeClass") { const original_getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions; nodeType.prototype.getExtraMenuOptions = function(_, options) { original_getExtraMenuOptions?.apply(this, arguments); options.push({ content: "Do something fun", callback: async () => { // fun thing } }) } } ``` ### Submenus If you want a submenu, provide a callback which uses `LiteGraph.ContextMenu` to create it: ```javascript function make_submenu(value, options, e, menu, node) { const submenu = new LiteGraph.ContextMenu( ["option 1", "option 2", "option 3"], { event: e, callback: function (v) { // do something with v (=="option x") }, parentMenu: menu, node:node } ) } /* ... */ options.push( { content: "Menu with options", has_submenu: true, callback: make_submenu, } ) ``` ## Capture UI Events This works just like you'd expect - find the UI element in the DOM and add an eventListener. `setup()` is a good place to do this, since the page has fully loaded. For instance, to detect a click on the 'Queue' button: ```javascript function queue_button_pressed() { console.log("Queue button was pressed!") } document.getElementById("queue-button").addEventListener("click", queue_button_pressed); ``` ## Detect When a Workflow Starts This is one of many `api` events: ```javascript import { api } from "../../scripts/api.js"; /* in setup() */ function on_execution_start() { /* do whatever */ } api.addEventListener("execution_start", on_execution_start); ``` ## Detect an Interrupted Workflow A simple example of hijacking the api: ```javascript import { api } from "../../scripts/api.js"; /* in setup() */ const original_api_interrupt = api.interrupt; api.interrupt = function () { /* Do something before the original method is called */ original_api_interrupt.apply(this, arguments); /* Or after */ } ``` ## Catch Clicks on Your Node `node` has a mouseDown method you can hijack. This time we're careful to pass on any return value. ```javascript async nodeCreated(node) { if (node?.comfyClass === "My Node Name") { const original_onMouseDown = node.onMouseDown; node.onMouseDown = function( e, pos, canvas ) { alert("ouch!"); return original_onMouseDown?.apply(this, arguments); } } } ``` ## Key Concepts ### Method Hijacking Many of these examples use a common pattern of "hijacking" existing methods: 1. Save a reference to the original method 2. Replace the method with your own implementation 3. Call the original method from within your implementation 4. Add your custom logic before or after the original call ### Event Handling ComfyUI provides several event systems: - **DOM Events**: Standard browser events on UI elements - **API Events**: Custom events fired by the ComfyUI API - **Node Events**: Events specific to node interactions - **Graph Events**: Events related to workflow changes ### Common Patterns - **Menu Extension**: Adding custom options to context menus - **Event Interception**: Capturing and responding to user actions - **UI Enhancement**: Adding functionality to existing interface elements - **Workflow Monitoring**: Tracking workflow execution state ## Usage Notes - These examples assume you're working within the ComfyUI extension system - Most hijacking should be done in the `setup()` method after the page loads - Always preserve the original method's behavior unless you specifically need to change it - Be careful with event listeners to avoid memory leaks - Test thoroughly as hijacking can affect other extensions