@@ -5,6 +5,8 @@ import { api } from "../../../scripts/api.js";
55
66const CHECKPOINT_LOADER = "CheckpointLoader|pysssss" ;
77const LORA_LOADER = "LoraLoader|pysssss" ;
8+ const IMAGE_WIDTH = 384 ;
9+ const IMAGE_HEIGHT = 384 ;
810
911function getType ( node ) {
1012 if ( node . comfyClass === CHECKPOINT_LOADER ) {
@@ -13,6 +15,50 @@ function getType(node) {
1315 return "loras" ;
1416}
1517
18+ const getImage = ( imageId ) => document . querySelector ( `#${ CSS . escape ( imageId ) } ` ) ;
19+
20+ const calculateImagePosition = ( el , rootRect , bodyRect ) => {
21+ const { x } = el . getBoundingClientRect ( ) ;
22+ let { top, left } = rootRect ;
23+ const { width : bodyWidth , height : bodyHeight } = bodyRect ;
24+
25+ const isSpaceRight = x + IMAGE_WIDTH <= bodyWidth ;
26+ if ( isSpaceRight ) {
27+ left += rootRect . width + IMAGE_WIDTH ;
28+ }
29+
30+ const isSpaceBelow = rootRect . top + IMAGE_HEIGHT <= bodyHeight ;
31+ if ( ! isSpaceBelow ) {
32+ top = bodyHeight - IMAGE_HEIGHT ;
33+ }
34+
35+ return { left : Math . round ( left ) , top : Math . round ( top ) } ;
36+ } ;
37+
38+ function showImage ( el , imageId , getRootRect ) {
39+ const img = getImage ( imageId ) ;
40+ if ( img ) {
41+ const rootRect = getRootRect ( ) ;
42+ if ( ! rootRect ) return ;
43+
44+ const bodyRect = document . body . getBoundingClientRect ( ) ;
45+ if ( ! bodyRect ) return ;
46+
47+ const { left, top } = calculateImagePosition ( el , rootRect , bodyRect ) ;
48+
49+ img . style . display = "block" ;
50+ img . style . left = `${ left } px` ;
51+ img . style . top = `${ top } px` ;
52+ }
53+ }
54+
55+ function closeImage ( imageId ) {
56+ const img = getImage ( imageId ) ;
57+ if ( img ) {
58+ img . style . display = "none" ;
59+ }
60+ }
61+
1662app . registerExtension ( {
1763 name : "pysssss.Combo++" ,
1864 init ( ) {
@@ -27,8 +73,8 @@ app.registerExtension({
2773 left: 0;
2874 top: 0;
2975 transform: translate(-100%, 0);
30- width: 384px ;
31- height: 384px ;
76+ width: ${ IMAGE_WIDTH } px ;
77+ height: ${ IMAGE_HEIGHT } px ;
3278 background-size: contain;
3379 background-position: top right;
3480 background-repeat: no-repeat;
@@ -81,13 +127,23 @@ app.registerExtension({
81127 // After an element is created for an item, add an image if it has one
82128 contextMenuHook [ "addItem" ] . push ( function ( el , menu , [ name , value , options ] ) {
83129 if ( el && isCustomItem ( value ) && value ?. image && ! value . submenu ) {
130+ const key = `pysssss-image-combo-${ name } ` ;
84131 el . textContent += " *" ;
85- $el ( "div.pysssss-combo-image" , {
86- parent : el ,
132+ $el ( `div.pysssss-combo-image` , {
133+ id : key ,
134+ parent : document . body ,
87135 style : {
88136 backgroundImage : `url(/pysssss/view/${ encodeRFC3986URIComponent ( value . image ) } )` ,
89137 } ,
90138 } ) ;
139+
140+ const getRootRect = ( ) => menu . root ?. getBoundingClientRect ( ) ;
141+ const showHandler = ( ) => showImage ( el , key , getRootRect ) ;
142+ const closeHandler = ( ) => closeImage ( key ) ;
143+
144+ el . addEventListener ( "mouseenter" , showHandler , { passive : true } ) ;
145+ el . addEventListener ( "mouseleave" , closeHandler , { passive : true } ) ;
146+ el . addEventListener ( "click" , closeHandler , { passive : true } ) ;
91147 }
92148 } ) ;
93149
0 commit comments