1+ import { app } from "/scripts/app.js" ;
2+ import { ComfyWidgets } from "/scripts/widgets.js" ;
3+
4+ app . registerExtension ( {
5+ name : "Comfy.IFDisplayTextWildcardNode" ,
6+ async beforeRegisterNodeDef ( nodeType , nodeData , app ) {
7+ if ( nodeData . name === "IF_DisplayTextWildcard" ) {
8+ // Store original node methods
9+ const onNodeCreated = nodeType . prototype . onNodeCreated ;
10+ const onExecuted = nodeType . prototype . onExecuted ;
11+ const onDrawForeground = nodeType . prototype . onDrawForeground ;
12+ const getExtraMenuOptions = nodeType . prototype . getExtraMenuOptions ;
13+
14+ // Add counter status display
15+ nodeType . prototype . counterStatus = {
16+ count : - 1 ,
17+ blocked : false
18+ } ;
19+
20+ nodeType . prototype . onNodeCreated = function ( ) {
21+ const ret = onNodeCreated ?. apply ( this , arguments ) ;
22+
23+ // Set output labels
24+ if ( this . outputs ) {
25+ this . outputs [ 0 ] . name = "text" ;
26+ this . outputs [ 1 ] . name = "text_list" ;
27+ this . outputs [ 2 ] . name = "count" ;
28+ this . outputs [ 3 ] . name = "selected" ;
29+
30+ // Set the text_list output to use grid shape
31+ this . outputs [ 1 ] . shape = LiteGraph . GRID_SHAPE ;
32+ }
33+
34+ // Create unique name for node instance
35+ let nodeName = `${ nodeData . name } _${ app . graph . _nodes . filter ( n => n . type === nodeData . name ) . length } ` ;
36+ console . log ( `Create ${ nodeData . name } : ${ nodeName } ` ) ;
37+
38+ // Create text display widget
39+ const wi = ComfyWidgets . STRING (
40+ this ,
41+ nodeName ,
42+ [ "STRING" , {
43+ default : "" ,
44+ placeholder : "Message will appear here ..." ,
45+ multiline : true ,
46+ } ] ,
47+ app
48+ ) ;
49+ wi . widget . inputEl . readOnly = true ;
50+
51+ return ret ;
52+ } ;
53+
54+ // Handle counter status updates
55+ nodeType . prototype . onExecuted = function ( message ) {
56+ const ret = onExecuted ?. apply ( this , arguments ) ;
57+
58+ // Update counter status
59+ const widgets = this . widgets || [ ] ;
60+ const counterWidget = widgets . find ( w => w . name === "counter" ) ;
61+
62+ if ( counterWidget ) {
63+ // Get counter value from widget
64+ this . counterStatus . count = counterWidget . value ;
65+
66+ // Check if execution was blocked
67+ if ( message ?. error ?. includes ( "Counter reached 0" ) ) {
68+ this . counterStatus . blocked = true ;
69+ } else {
70+ this . counterStatus . blocked = false ;
71+ }
72+ }
73+
74+ // Update text display
75+ if ( message ?. string ) {
76+ const widget_id = this . widgets . findIndex ( w => w . type === "customtext" ) ;
77+ if ( widget_id !== - 1 ) {
78+ let texts = message . string ;
79+ if ( Array . isArray ( texts ) ) {
80+ texts = texts
81+ . filter ( text => text != null )
82+ . map ( text => String ( text ) . trim ( ) )
83+ . join ( "\n" ) ;
84+ } else {
85+ texts = String ( texts ) . trim ( ) ;
86+ }
87+ this . widgets [ widget_id ] . value = texts ;
88+ }
89+ }
90+
91+ app . graph . setDirtyCanvas ( true ) ;
92+ return ret ;
93+ } ;
94+
95+ // Enhanced node drawing
96+ nodeType . prototype . onDrawForeground = function ( ctx ) {
97+ const ret = onDrawForeground ?. apply ( this , arguments ) ;
98+
99+ // Add tooltips to outputs
100+ if ( this . outputs ) {
101+ const outputLabels = [
102+ "Complete Text" ,
103+ "List of Lines" ,
104+ "Line Count" ,
105+ "Selected Line"
106+ ] ;
107+ const outputTooltips = [
108+ "Full text content" ,
109+ "Individual lines as separate outputs" ,
110+ "Total number of non-empty lines" ,
111+ "Currently selected line based on select input"
112+ ] ;
113+
114+ for ( let i = 0 ; i < this . outputs . length ; i ++ ) {
115+ const output = this . outputs [ i ] ;
116+ output . tooltip = outputTooltips [ i ] ;
117+ }
118+ }
119+
120+ // Draw counter status
121+ if ( this . counterStatus . count !== - 1 ) {
122+ ctx . save ( ) ;
123+ ctx . font = "12px Arial" ;
124+ ctx . textAlign = "right" ;
125+
126+ // Position in top-right corner
127+ const text = `Counter: ${ this . counterStatus . count } ` ;
128+ const x = this . size [ 0 ] - 5 ;
129+ const y = 20 ;
130+
131+ // Draw counter value with color based on status
132+ if ( this . counterStatus . blocked ) {
133+ ctx . fillStyle = "#ff4444" ;
134+ this . boxcolor = "#442222" ;
135+ } else if ( this . counterStatus . count === 0 ) {
136+ ctx . fillStyle = "#ffaa44" ;
137+ this . boxcolor = "#443322" ;
138+ } else {
139+ ctx . fillStyle = "#66ff66" ;
140+ this . boxcolor = null ; // Reset to default
141+ }
142+
143+ ctx . fillText ( text , x , y ) ;
144+ ctx . restore ( ) ;
145+ }
146+
147+ return ret ;
148+ } ;
149+
150+ // Add counter reset option to context menu
151+ nodeType . prototype . getExtraMenuOptions = function ( _ , options ) {
152+ const ret = getExtraMenuOptions ?. apply ( this , arguments ) ;
153+
154+ options . push (
155+ null , // separator
156+ {
157+ content : "Reset Counter" ,
158+ callback : ( ) => {
159+ const counterWidget = this . widgets . find ( w => w . name === "counter" ) ;
160+ if ( counterWidget ) {
161+ // Reset to widget's original value
162+ counterWidget . value = counterWidget . options . default ;
163+ this . counterStatus . count = counterWidget . value ;
164+ this . counterStatus . blocked = false ;
165+ app . graph . setDirtyCanvas ( true ) ;
166+ }
167+ }
168+ }
169+ ) ;
170+
171+ return ret ;
172+ } ;
173+ }
174+ } ,
175+ } ) ;
0 commit comments