2023-02-12 10:18:09 +01:00
"use strict"
let modelsCache
let modelsOptions
/ *
* * * SEARCHABLE MODELS * * *
Creates searchable dropdowns for SD , VAE , or HN models .
Also adds a reload models button ( placed next to SD models , reloads everything including VAE and HN models ) .
More reload buttons may be added at strategic UI locations as needed .
Merely calling getModels ( ) makes all the magic happen behind the scene to refresh the dropdowns .
HOW TO CREATE A MODEL DROPDOWN :
1 ) Create an input element . Make sure to add a data - path property , as this is how model dropdowns are identified in auto - save . js .
2023-02-13 07:31:40 +01:00
< input id = "stable_diffusion_model" type = "text" spellcheck = "false" autocomplete = "off" class = "model-filter" data - path = "" / >
2023-02-12 10:18:09 +01:00
2 ) Just declare one of these for your own dropdown ( remember to change the element id , e . g . # stable _diffusion _models to your own input ' s id ) .
let stableDiffusionModelField = new ModelDropdown ( document . querySelector ( '#stable_diffusion_model' ) , 'stable-diffusion' )
let vaeModelField = new ModelDropdown ( document . querySelector ( '#vae_model' ) , 'vae' , 'None' )
let hypernetworkModelField = new ModelDropdown ( document . querySelector ( '#hypernetwork_model' ) , 'hypernetwork' , 'None' )
3 ) Model dropdowns will be refreshed automatically when the reload models button is invoked .
* /
2023-04-27 19:56:56 +02:00
class ModelDropdown {
2023-02-12 10:18:09 +01:00
modelFilter //= document.querySelector("#model-filter")
modelFilterArrow //= document.querySelector("#model-filter-arrow")
modelList //= document.querySelector("#model-list")
modelResult //= document.querySelector("#model-result")
modelNoResult //= document.querySelector("#model-no-result")
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
currentSelection //= { elem: undefined, value: '', path: ''}
highlightedModelEntry //= undefined
activeModel //= undefined
inputModels //= undefined
modelKey //= undefined
flatModelList //= []
noneEntry //= ''
2023-02-13 07:31:40 +01:00
modelFilterInitialized //= undefined
2023-02-12 10:18:09 +01:00
2023-06-08 12:39:11 +02:00
sorted //= true
2023-02-12 10:18:09 +01:00
/* MIMIC A REGULAR INPUT FIELD */
get parentElement ( ) {
return this . modelFilter . parentElement
}
get parentNode ( ) {
return this . modelFilter . parentNode
}
get value ( ) {
return this . modelFilter . dataset . path
}
set value ( path ) {
this . modelFilter . dataset . path = path
this . selectEntry ( path )
}
2023-02-16 14:59:08 +01:00
get disabled ( ) {
return this . modelFilter . disabled
}
set disabled ( state ) {
this . modelFilter . disabled = state
if ( this . modelFilterArrow ) {
2023-04-27 19:56:56 +02:00
this . modelFilterArrow . style . color = state ? "dimgray" : ""
2023-02-16 14:59:08 +01:00
}
2023-02-23 00:18:06 +01:00
}
get modelElements ( ) {
2023-04-27 19:56:56 +02:00
return this . modelList . querySelectorAll ( ".model-file" )
2023-02-23 00:18:06 +01:00
}
2023-02-12 10:18:09 +01:00
addEventListener ( type , listener , options ) {
return this . modelFilter . addEventListener ( type , listener , options )
}
dispatchEvent ( event ) {
return this . modelFilter . dispatchEvent ( event )
}
appendChild ( option ) {
// do nothing
}
// remember 'this' - http://blog.niftysnippets.org/2008/04/you-must-remember-this.html
bind ( f , obj ) {
return function ( ) {
return f . apply ( obj , arguments )
}
}
2023-04-27 19:56:56 +02:00
/* SEARCHABLE INPUT */
2023-06-08 12:39:11 +02:00
constructor ( input , modelKey , noneEntry = "" , sorted = true ) {
2023-02-12 10:18:09 +01:00
this . modelFilter = input
this . noneEntry = noneEntry
this . modelKey = modelKey
2023-06-08 12:39:11 +02:00
this . sorted = sorted
2023-02-12 10:18:09 +01:00
2023-04-27 19:56:56 +02:00
if ( modelsOptions !== undefined ) {
// reuse models from cache (only useful for plugins, which are loaded after models)
2023-06-01 13:20:01 +02:00
this . inputModels = [ ]
let modelKeys = Array . isArray ( this . modelKey ) ? this . modelKey : [ this . modelKey ]
for ( let i = 0 ; i < modelKeys . length ; i ++ ) {
let key = modelKeys [ i ]
2023-06-05 05:30:50 +02:00
let k = Array . isArray ( modelsOptions [ key ] ) ? modelsOptions [ key ] : [ modelsOptions [ key ] ]
this . inputModels . push ( ... k )
2023-06-01 13:20:01 +02:00
}
2023-02-12 10:18:09 +01:00
this . populateModels ( )
}
2023-04-27 19:56:56 +02:00
document . addEventListener (
"refreshModels" ,
this . bind ( function ( e ) {
// reload the models
2023-06-01 13:20:01 +02:00
this . inputModels = [ ]
let modelKeys = Array . isArray ( this . modelKey ) ? this . modelKey : [ this . modelKey ]
for ( let i = 0 ; i < modelKeys . length ; i ++ ) {
let key = modelKeys [ i ]
2023-06-05 05:30:50 +02:00
let k = Array . isArray ( modelsOptions [ key ] ) ? modelsOptions [ key ] : [ modelsOptions [ key ] ]
this . inputModels . push ( ... k )
2023-06-01 13:20:01 +02:00
}
2023-04-27 19:56:56 +02:00
this . populateModels ( )
} , this )
)
2023-02-12 10:18:09 +01:00
}
2023-08-18 09:48:06 +02:00
saveCurrentSelection ( elem , value , path , dispatchEvent = true ) {
2023-02-12 10:18:09 +01:00
this . currentSelection . elem = elem
this . currentSelection . value = value
this . currentSelection . path = path
this . modelFilter . dataset . path = path
this . modelFilter . value = value
2023-08-18 09:48:06 +02:00
if ( dispatchEvent ) {
this . modelFilter . dispatchEvent ( new Event ( "change" ) )
}
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
processClick ( e ) {
e . preventDefault ( )
2023-04-27 19:56:56 +02:00
if ( e . srcElement . classList . contains ( "model-file" ) || e . srcElement . classList . contains ( "fa-file" ) ) {
const elem = e . srcElement . classList . contains ( "model-file" ) ? e . srcElement : e . srcElement . parentElement
2023-02-27 02:26:22 +01:00
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path )
2023-02-12 10:18:09 +01:00
this . hideModelList ( )
this . modelFilter . focus ( )
this . modelFilter . select ( )
}
}
2023-02-13 07:31:40 +01:00
getPreviousVisibleSibling ( elem ) {
2023-02-23 00:18:06 +01:00
const modelElements = Array . from ( this . modelElements )
const index = modelElements . indexOf ( elem )
if ( index <= 0 ) {
return undefined
2023-02-13 07:31:40 +01:00
}
2023-02-23 00:18:06 +01:00
2023-04-27 19:56:56 +02:00
return modelElements
. slice ( 0 , index )
. reverse ( )
. find ( ( e ) => e . style . display === "list-item" )
2023-02-13 07:31:40 +01:00
}
getLastVisibleChild ( elem ) {
let lastElementChild = elem . lastElementChild
2023-04-27 19:56:56 +02:00
if ( lastElementChild . style . display == "list-item" ) return lastElementChild
2023-02-13 07:31:40 +01:00
return this . getPreviousVisibleSibling ( lastElementChild )
}
2023-04-27 19:56:56 +02:00
2023-02-13 07:31:40 +01:00
getNextVisibleSibling ( elem ) {
2023-02-23 00:18:06 +01:00
const modelElements = Array . from ( this . modelElements )
const index = modelElements . indexOf ( elem )
2023-04-27 19:56:56 +02:00
return modelElements . slice ( index + 1 ) . find ( ( e ) => e . style . display === "list-item" )
2023-02-13 07:31:40 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-13 07:31:40 +01:00
getFirstVisibleChild ( elem ) {
let firstElementChild = elem . firstElementChild
2023-04-27 19:56:56 +02:00
if ( firstElementChild . style . display == "list-item" ) return firstElementChild
2023-02-13 07:31:40 +01:00
return this . getNextVisibleSibling ( firstElementChild )
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
selectModelEntry ( elem ) {
if ( elem ) {
if ( this . highlightedModelEntry !== undefined ) {
2023-04-27 19:56:56 +02:00
this . highlightedModelEntry . classList . remove ( "selected" )
2023-02-12 10:18:09 +01:00
}
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path )
2023-04-27 19:56:56 +02:00
elem . classList . add ( "selected" )
elem . scrollIntoView ( { block : "nearest" } )
2023-02-12 10:18:09 +01:00
this . highlightedModelEntry = elem
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
selectPreviousFile ( ) {
2023-02-23 00:18:06 +01:00
const elem = this . getPreviousVisibleSibling ( this . highlightedModelEntry )
2023-02-12 10:18:09 +01:00
if ( elem ) {
this . selectModelEntry ( elem )
2023-04-27 19:56:56 +02:00
} else {
2023-02-12 10:18:09 +01:00
//this.highlightedModelEntry.parentElement.parentElement.scrollIntoView({block: 'nearest'})
2023-04-27 19:56:56 +02:00
this . highlightedModelEntry . closest ( ".model-list" ) . scrollTop = 0
2023-02-12 10:18:09 +01:00
}
this . modelFilter . select ( )
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
selectNextFile ( ) {
2023-02-23 00:18:06 +01:00
this . selectModelEntry ( this . getNextVisibleSibling ( this . highlightedModelEntry ) )
2023-02-12 10:18:09 +01:00
this . modelFilter . select ( )
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
selectFirstFile ( ) {
2023-04-27 19:56:56 +02:00
this . selectModelEntry ( this . modelList . querySelector ( ".model-file" ) )
this . highlightedModelEntry . scrollIntoView ( { block : "nearest" } )
2023-02-12 10:18:09 +01:00
this . modelFilter . select ( )
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
selectLastFile ( ) {
2023-04-27 19:56:56 +02:00
const elems = this . modelList . querySelectorAll ( ".model-file:last-child" )
this . selectModelEntry ( elems [ elems . length - 1 ] )
2023-02-12 10:18:09 +01:00
this . modelFilter . select ( )
}
resetSelection ( ) {
this . hideModelList ( )
this . showAllEntries ( )
this . modelFilter . value = this . currentSelection . value
this . modelFilter . focus ( )
this . modelFilter . select ( )
}
validEntrySelected ( ) {
2023-04-27 19:56:56 +02:00
return this . modelNoResult . style . display === "none"
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
processKey ( e ) {
switch ( e . key ) {
2023-04-27 19:56:56 +02:00
case "Escape" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
this . resetSelection ( )
break
2023-04-27 19:56:56 +02:00
case "Enter" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
2023-04-27 19:56:56 +02:00
if ( this . modelList . style . display != "block" ) {
2023-02-12 10:18:09 +01:00
this . showModelList ( )
2023-04-27 19:56:56 +02:00
} else {
this . saveCurrentSelection (
this . highlightedModelEntry ,
this . highlightedModelEntry . innerText ,
this . highlightedModelEntry . dataset . path
)
2023-02-12 10:18:09 +01:00
this . hideModelList ( )
2023-02-13 07:31:40 +01:00
this . showAllEntries ( )
2023-02-12 10:18:09 +01:00
}
this . modelFilter . focus ( )
2023-04-27 19:56:56 +02:00
} else {
2023-02-12 10:18:09 +01:00
this . resetSelection ( )
}
break
2023-04-27 19:56:56 +02:00
case "ArrowUp" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectPreviousFile ( )
}
break
2023-04-27 19:56:56 +02:00
case "ArrowDown" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectNextFile ( )
}
break
2023-04-27 19:56:56 +02:00
case "ArrowLeft" :
if ( this . modelList . style . display != "block" ) {
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
}
break
2023-04-27 19:56:56 +02:00
case "ArrowRight" :
if ( this . modelList . style . display != "block" ) {
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
}
break
2023-04-27 19:56:56 +02:00
case "PageUp" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
}
break
2023-04-27 19:56:56 +02:00
case "PageDown" :
2023-02-12 10:18:09 +01:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
}
break
2023-04-27 19:56:56 +02:00
case "Home" :
2023-02-12 10:18:09 +01:00
//if (this.modelList.style.display != 'block') {
2023-04-27 19:56:56 +02:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectFirstFile ( )
}
2023-02-12 10:18:09 +01:00
//}
break
2023-04-27 19:56:56 +02:00
case "End" :
2023-02-12 10:18:09 +01:00
//if (this.modelList.style.display != 'block') {
2023-04-27 19:56:56 +02:00
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectLastFile ( )
}
2023-02-12 10:18:09 +01:00
//}
break
default :
2023-04-27 19:56:56 +02:00
//console.log(e.key)
2023-02-12 10:18:09 +01:00
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
modelListFocus ( ) {
this . selectEntry ( )
this . showAllEntries ( )
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
showModelList ( ) {
2023-04-27 19:56:56 +02:00
this . modelList . style . display = "block"
2023-02-12 10:18:09 +01:00
this . selectEntry ( )
this . showAllEntries ( )
2023-02-18 08:26:17 +01:00
//this.modelFilter.value = ''
this . modelFilter . select ( ) // preselect the entire string so user can just start typing.
2023-02-12 10:18:09 +01:00
this . modelFilter . focus ( )
2023-04-27 19:56:56 +02:00
this . modelFilter . style . cursor = "auto"
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
hideModelList ( ) {
2023-04-27 19:56:56 +02:00
this . modelList . style . display = "none"
2023-02-12 10:18:09 +01:00
this . modelFilter . value = this . currentSelection . value
2023-04-27 19:56:56 +02:00
this . modelFilter . style . cursor = ""
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
toggleModelList ( e ) {
e . preventDefault ( )
2023-02-16 14:59:08 +01:00
if ( ! this . modelFilter . disabled ) {
2023-04-27 19:56:56 +02:00
if ( this . modelList . style . display != "block" ) {
2023-02-16 14:59:08 +01:00
this . showModelList ( )
2023-04-27 19:56:56 +02:00
} else {
2023-02-16 14:59:08 +01:00
this . hideModelList ( )
this . modelFilter . select ( )
}
2023-02-12 10:18:09 +01:00
}
}
2023-04-27 19:56:56 +02:00
2023-08-18 09:48:06 +02:00
selectEntry ( path , dispatchEvent = true ) {
2023-02-12 10:18:09 +01:00
if ( path !== undefined ) {
2023-04-27 19:56:56 +02:00
const entries = this . modelElements
2023-02-12 10:18:09 +01:00
2023-02-23 00:18:06 +01:00
for ( const elem of entries ) {
if ( elem . dataset . path == path ) {
2023-08-18 09:48:06 +02:00
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path , dispatchEvent )
2023-02-23 00:18:06 +01:00
this . highlightedModelEntry = elem
2023-04-27 19:56:56 +02:00
elem . scrollIntoView ( { block : "nearest" } )
2023-02-12 10:18:09 +01:00
break
}
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
if ( this . currentSelection . elem !== undefined ) {
// select the previous element
if ( this . highlightedModelEntry !== undefined && this . highlightedModelEntry != this . currentSelection . elem ) {
2023-04-27 19:56:56 +02:00
this . highlightedModelEntry . classList . remove ( "selected" )
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
this . currentSelection . elem . classList . add ( "selected" )
2023-02-12 10:18:09 +01:00
this . highlightedModelEntry = this . currentSelection . elem
2023-04-27 19:56:56 +02:00
this . currentSelection . elem . scrollIntoView ( { block : "nearest" } )
} else {
2023-02-12 10:18:09 +01:00
this . selectFirstFile ( )
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
highlightModelAtPosition ( e ) {
let elem = document . elementFromPoint ( e . clientX , e . clientY )
2023-04-27 19:56:56 +02:00
if ( elem . classList . contains ( "model-file" ) ) {
2023-02-12 10:18:09 +01:00
this . highlightModel ( elem )
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
highlightModel ( elem ) {
2023-04-27 19:56:56 +02:00
if ( elem . classList . contains ( "model-file" ) ) {
2023-02-12 10:18:09 +01:00
if ( this . highlightedModelEntry !== undefined && this . highlightedModelEntry != elem ) {
2023-04-27 19:56:56 +02:00
this . highlightedModelEntry . classList . remove ( "selected" )
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
elem . classList . add ( "selected" )
2023-02-12 10:18:09 +01:00
this . highlightedModelEntry = elem
}
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
showAllEntries ( ) {
2023-04-27 19:56:56 +02:00
this . modelList . querySelectorAll ( "li" ) . forEach ( function ( li ) {
if ( li . id !== "model-no-result" ) {
li . style . display = "list-item"
2023-02-12 10:18:09 +01:00
}
} )
2023-04-27 19:56:56 +02:00
this . modelNoResult . style . display = "none"
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
filterList ( e ) {
const filter = this . modelFilter . value . toLowerCase ( )
let found = false
let showAllChildren = false
2023-04-27 19:56:56 +02:00
this . modelList . querySelectorAll ( "li" ) . forEach ( function ( li ) {
if ( li . classList . contains ( "model-folder" ) ) {
2023-02-12 10:18:09 +01:00
showAllChildren = false
}
2023-04-27 19:56:56 +02:00
if ( filter == "" ) {
li . style . display = "list-item"
2023-02-12 10:18:09 +01:00
found = true
} else if ( showAllChildren || li . textContent . toLowerCase ( ) . match ( filter ) ) {
2023-04-27 19:56:56 +02:00
li . style . display = "list-item"
if ( li . classList . contains ( "model-folder" ) && li . firstChild . textContent . toLowerCase ( ) . match ( filter ) ) {
2023-02-12 10:18:09 +01:00
showAllChildren = true
}
found = true
} else {
2023-04-27 19:56:56 +02:00
li . style . display = "none"
2023-02-12 10:18:09 +01:00
}
} )
2023-04-27 19:56:56 +02:00
2023-02-12 10:18:09 +01:00
if ( found ) {
2023-04-27 19:56:56 +02:00
this . modelResult . style . display = "list-item"
this . modelNoResult . style . display = "none"
const elem = this . getNextVisibleSibling ( this . modelList . querySelector ( ".model-file" ) )
2023-02-12 10:18:09 +01:00
this . highlightModel ( elem )
2023-04-27 19:56:56 +02:00
elem . scrollIntoView ( { block : "nearest" } )
} else {
this . modelResult . style . display = "none"
this . modelNoResult . style . display = "list-item"
2023-02-12 10:18:09 +01:00
}
2023-04-27 19:56:56 +02:00
this . modelList . style . display = "block"
2023-02-12 10:18:09 +01:00
}
/* MODEL LOADER */
2023-02-13 10:37:00 +01:00
getElementDimensions ( element ) {
// Clone the element
const clone = element . cloneNode ( true )
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Copy the styles of the original element to the cloned element
const originalStyles = window . getComputedStyle ( element )
for ( let i = 0 ; i < originalStyles . length ; i ++ ) {
const property = originalStyles [ i ]
clone . style [ property ] = originalStyles . getPropertyValue ( property )
}
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Set its visibility to hidden and display to inline-block
clone . style . visibility = "hidden"
clone . style . display = "inline-block"
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Put the cloned element next to the original element
element . parentNode . insertBefore ( clone , element . nextSibling )
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Get its width and height
const width = clone . offsetWidth
const height = clone . offsetHeight
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Remove it from the DOM
clone . remove ( )
2023-04-27 19:56:56 +02:00
2023-02-13 10:37:00 +01:00
// Return its width and height
return { width , height }
}
2023-04-27 19:56:56 +02:00
2023-02-17 03:03:02 +01:00
/ * *
2023-04-27 19:56:56 +02:00
* @ param { Array < string > } models
2023-02-17 03:03:02 +01:00
* /
sortStringArray ( models ) {
2023-04-27 19:56:56 +02:00
models . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : "base" } ) )
2023-02-12 10:18:09 +01:00
}
populateModels ( ) {
this . activeModel = this . modelFilter . dataset . path
2023-04-27 19:56:56 +02:00
this . currentSelection = { elem : undefined , value : "" , path : "" }
2023-02-12 10:18:09 +01:00
this . highlightedModelEntry = undefined
this . flatModelList = [ ]
2023-04-27 19:56:56 +02:00
if ( this . modelList !== undefined ) {
2023-02-12 10:18:09 +01:00
this . modelList . remove ( )
this . modelFilterArrow . remove ( )
}
this . createDropdown ( )
}
createDropdown ( ) {
// create dropdown entries
2023-02-24 15:38:19 +01:00
let rootModelList = this . createRootModelList ( this . inputModels )
2023-04-27 19:56:56 +02:00
this . modelFilter . insertAdjacentElement ( "afterend" , rootModelList )
2023-02-17 03:03:02 +01:00
this . modelFilter . insertAdjacentElement (
2023-04-27 19:56:56 +02:00
"afterend" ,
createElement ( "i" , { id : ` ${ this . modelFilter . id } -model-filter-arrow ` } , [
"model-selector-arrow" ,
"fa-solid" ,
2023-04-28 12:20:44 +02:00
"fa-angle-down" ,
2023-04-27 19:56:56 +02:00
] )
2023-02-17 03:03:02 +01:00
)
2023-04-27 19:56:56 +02:00
this . modelFilter . classList . add ( "model-selector" )
2023-02-12 10:18:09 +01:00
this . modelFilterArrow = document . querySelector ( ` # ${ this . modelFilter . id } -model-filter-arrow ` )
2023-02-18 01:40:16 +01:00
if ( this . modelFilterArrow ) {
2023-04-27 19:56:56 +02:00
this . modelFilterArrow . style . color = this . modelFilter . disabled ? "dimgray" : ""
2023-02-18 01:40:16 +01:00
}
2023-02-12 10:18:09 +01:00
this . modelList = document . querySelector ( ` # ${ this . modelFilter . id } -model-list ` )
this . modelResult = document . querySelector ( ` # ${ this . modelFilter . id } -model-result ` )
this . modelNoResult = document . querySelector ( ` # ${ this . modelFilter . id } -model-no-result ` )
2023-04-27 19:56:56 +02:00
2023-02-13 07:31:40 +01:00
if ( this . modelFilterInitialized !== true ) {
2023-04-27 19:56:56 +02:00
this . modelFilter . addEventListener ( "input" , this . bind ( this . filterList , this ) )
this . modelFilter . addEventListener ( "focus" , this . bind ( this . modelListFocus , this ) )
this . modelFilter . addEventListener ( "blur" , this . bind ( this . hideModelList , this ) )
this . modelFilter . addEventListener ( "click" , this . bind ( this . showModelList , this ) )
this . modelFilter . addEventListener ( "keydown" , this . bind ( this . processKey , this ) )
2023-02-13 07:31:40 +01:00
this . modelFilterInitialized = true
}
2023-04-27 19:56:56 +02:00
this . modelFilterArrow . addEventListener ( "mousedown" , this . bind ( this . toggleModelList , this ) )
this . modelList . addEventListener ( "mousemove" , this . bind ( this . highlightModelAtPosition , this ) )
this . modelList . addEventListener ( "mousedown" , this . bind ( this . processClick , this ) )
2023-02-12 10:18:09 +01:00
2023-02-28 11:07:06 +01:00
let mf = this . modelFilter
2023-04-27 19:56:56 +02:00
this . modelFilter . addEventListener ( "focus" , function ( ) {
2023-02-28 11:07:06 +01:00
let modelFilterStyle = window . getComputedStyle ( mf )
rootModelList . style . minWidth = modelFilterStyle . width
} )
2023-02-24 15:38:19 +01:00
2023-08-18 09:48:06 +02:00
this . selectEntry ( this . activeModel , false )
2023-02-12 10:18:09 +01:00
}
2023-02-17 03:03:02 +01:00
/ * *
* @ param { Array < string | object } modelTree
2023-04-27 19:56:56 +02:00
* @ param { string } folderName
* @ param { boolean } isRootFolder
2023-02-17 03:03:02 +01:00
* @ returns { HTMLElement }
* /
createModelNodeList ( folderName , modelTree , isRootFolder ) {
2023-04-27 19:56:56 +02:00
const listElement = createElement ( "ul" )
2023-02-17 03:03:02 +01:00
const foldersMap = new Map ( )
const modelsMap = new Map ( )
2023-04-27 19:56:56 +02:00
modelTree . forEach ( ( model ) => {
2023-02-17 03:03:02 +01:00
if ( Array . isArray ( model ) ) {
const [ childFolderName , childModels ] = model
foldersMap . set (
childFolderName ,
2023-04-27 19:56:56 +02:00
this . createModelNodeList ( ` ${ folderName || "" } / ${ childFolderName } ` , childModels , false )
2023-02-17 03:03:02 +01:00
)
} else {
2023-08-01 12:46:38 +02:00
let modelId = model
let modelName = model
if ( typeof model === "object" ) {
modelId = Object . keys ( model ) [ 0 ]
modelName = model [ modelId ]
}
2023-04-27 19:56:56 +02:00
const classes = [ "model-file" ]
2023-02-17 03:03:02 +01:00
if ( isRootFolder ) {
2023-04-27 19:56:56 +02:00
classes . push ( "in-root-folder" )
2023-02-12 10:18:09 +01:00
}
2023-02-17 05:29:32 +01:00
// Remove the leading slash from the model path
2023-08-01 12:46:38 +02:00
const fullPath = folderName ? ` ${ folderName . substring ( 1 ) } / ${ modelId } ` : modelId
2023-02-17 03:03:02 +01:00
modelsMap . set (
2023-08-01 12:46:38 +02:00
modelId ,
2023-04-27 19:56:56 +02:00
createElement ( "li" , { "data-path" : fullPath } , classes , [
createElement ( "i" , undefined , [ "fa-regular" , "fa-file" , "icon" ] ) ,
2023-08-01 12:46:38 +02:00
modelName ,
2023-04-27 19:56:56 +02:00
] )
2023-02-17 03:03:02 +01:00
)
2023-02-12 10:18:09 +01:00
}
} )
2023-02-17 03:03:02 +01:00
const childFolderNames = Array . from ( foldersMap . keys ( ) )
2023-06-08 12:39:11 +02:00
if ( this . sorted ) {
this . sortStringArray ( childFolderNames )
}
2023-04-27 19:56:56 +02:00
const folderElements = childFolderNames . map ( ( name ) => foldersMap . get ( name ) )
2023-02-17 03:03:02 +01:00
const modelNames = Array . from ( modelsMap . keys ( ) )
2023-06-08 12:39:11 +02:00
if ( this . sorted ) {
this . sortStringArray ( modelNames )
}
2023-04-27 19:56:56 +02:00
const modelElements = modelNames . map ( ( name ) => modelsMap . get ( name ) )
2023-02-17 03:03:02 +01:00
if ( modelElements . length && folderName ) {
2023-03-15 02:43:49 +01:00
listElement . appendChild (
createElement (
2023-04-27 19:56:56 +02:00
"li" ,
2023-03-15 02:43:49 +01:00
undefined ,
2023-04-27 19:56:56 +02:00
[ "model-folder" ] ,
[ createElement ( "i" , undefined , [ "fa-regular" , "fa-folder-open" , "icon" ] ) , folderName . substring ( 1 ) ]
2023-03-15 02:43:49 +01:00
)
)
2023-02-12 10:18:09 +01:00
}
2023-02-17 03:03:02 +01:00
2023-02-24 14:24:47 +01:00
// const allModelElements = isRootFolder ? [...folderElements, ...modelElements] : [...modelElements, ...folderElements]
const allModelElements = [ ... modelElements , ... folderElements ]
2023-04-27 19:56:56 +02:00
allModelElements . forEach ( ( e ) => listElement . appendChild ( e ) )
2023-02-17 03:03:02 +01:00
return listElement
}
/ * *
* @ param { object } modelTree
* @ returns { HTMLElement }
* /
createRootModelList ( modelTree ) {
2023-04-27 19:56:56 +02:00
const rootList = createElement ( "ul" , { id : ` ${ this . modelFilter . id } -model-list ` } , [ "model-list" ] )
2023-02-17 03:03:02 +01:00
rootList . appendChild (
2023-04-27 19:56:56 +02:00
createElement ( "li" , { id : ` ${ this . modelFilter . id } -model-no-result ` } , [ "model-no-result" ] , "No result" )
2023-02-17 03:03:02 +01:00
)
if ( this . noneEntry ) {
rootList . appendChild (
2023-04-27 19:56:56 +02:00
createElement ( "li" , { "data-path" : "" } , [ "model-file" , "in-root-folder" ] , this . noneEntry )
2023-02-17 03:03:02 +01:00
)
}
2023-02-24 14:59:25 +01:00
if ( modelTree . length > 0 ) {
2023-04-27 19:56:56 +02:00
const containerListItem = createElement ( "li" , { id : ` ${ this . modelFilter . id } -model-result ` } , [
2023-04-28 12:20:44 +02:00
"model-result" ,
2023-04-27 19:56:56 +02:00
] )
2023-02-25 02:46:53 +01:00
//console.log(containerListItem)
2023-02-24 14:59:25 +01:00
containerListItem . appendChild ( this . createModelNodeList ( undefined , modelTree , true ) )
rootList . appendChild ( containerListItem )
}
2023-02-17 03:03:02 +01:00
return rootList
2023-02-12 10:18:09 +01:00
}
}
/* (RE)LOAD THE MODELS */
2023-07-08 19:58:47 +02:00
async function getModels ( scanForMalicious = true ) {
2023-02-12 10:18:09 +01:00
try {
2023-07-08 19:58:47 +02:00
modelsCache = await SD . getModels ( scanForMalicious )
2023-04-27 19:56:56 +02:00
modelsOptions = modelsCache [ "options" ]
2023-02-12 10:18:09 +01:00
if ( "scan-error" in modelsCache ) {
// let previewPane = document.getElementById('tab-content-wrapper')
2023-04-27 19:56:56 +02:00
let previewPane = document . getElementById ( "preview" )
previewPane . style . background = "red"
previewPane . style . textAlign = "center"
previewPane . innerHTML =
"<H1>🔥Malware alert!🔥</H1><h2>The file <i>" +
modelsCache [ "scan-error" ] +
'</i> in your <tt>models/stable-diffusion</tt> folder is probably malware infected.</h2><h2>Please delete this file from the folder before proceeding!</h2>After deleting the file, reload this page.<br><br><button onClick="window.location.reload();">Reload Page</button>'
2023-02-12 10:18:09 +01:00
makeImageBtn . disabled = true
}
// notify ModelDropdown objects to refresh
2023-04-27 19:56:56 +02:00
document . dispatchEvent ( new Event ( "refreshModels" ) )
2023-02-12 10:18:09 +01:00
} catch ( e ) {
2023-04-27 19:56:56 +02:00
console . log ( "get models error" , e )
2023-02-12 10:18:09 +01:00
}
}
// reload models button
2023-08-01 12:09:15 +02:00
document . querySelector ( "#reload-models" ) . addEventListener ( "click" , ( e ) => {
e . stopPropagation ( )
getModels ( )
} )