diff --git a/ui/index.html b/ui/index.html index 734bedf9..a5c2687e 100644 --- a/ui/index.html +++ b/ui/index.html @@ -127,7 +127,7 @@ - + Click to learn more about custom models @@ -136,7 +136,7 @@ --> - + Click to learn more about VAEs @@ -208,7 +208,7 @@
- + diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 7ffb4a5a..d28bbcdf 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -12,7 +12,7 @@ Merely calling getModels() makes all the magic happen behind the scene to refres 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. - + 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') @@ -37,6 +37,7 @@ class ModelDropdown modelKey //= undefined flatModelList //= [] noneEntry //= '' + modelFilterInitialized //= undefined /* MIMIC A REGULAR INPUT FIELD */ get parentElement() { @@ -84,6 +85,14 @@ class ModelDropdown this.inputModels = modelsOptions[this.modelKey] this.populateModels() }, this)) + document.addEventListener("collapsibleClick", this.bind(function(e) { + // update the input size when the element becomes visible + this.updateInputSize() + }, this)) + document.addEventListener("tabClick", this.bind(function(e) { + // update the input size when the tab changes + this.updateInputSize() + }, this)) } saveCurrentSelection(elem, value, path) { @@ -105,9 +114,24 @@ class ModelDropdown } } + getPreviousVisibleSibling(elem) { + let prevSibling = elem.previousElementSibling + while (prevSibling && prevSibling.classList.contains('model-file')) { + if (prevSibling.style.display == 'list-item') return prevSibling + prevSibling = prevSibling.previousElementSibling + } + if (prevSibling && prevSibling.style.display == 'list-item') return prevSibling + } + + getLastVisibleChild(elem) { + let lastElementChild = elem.lastElementChild + if (lastElementChild.style.display == 'list-item') return lastElementChild + return this.getPreviousVisibleSibling(lastElementChild) + } + findPreviousSibling(elem) { // is there an immediate sibling? - let prevSibling = elem.previousElementSibling + let prevSibling = this.getPreviousVisibleSibling(elem) if (prevSibling) { // if the previous sibling is a model file, just select it if (prevSibling.classList.contains('model-file')) return prevSibling @@ -117,19 +141,34 @@ class ModelDropdown } // no sibling model file and no sibling model folder. look for siblings around the parent element. - prevSibling = elem.parentElement.parentElement.previousElementSibling + prevSibling = this.getPreviousVisibleSibling(elem.parentElement.parentElement) if (prevSibling) { // if the previous entry is a model file, select it if (prevSibling.classList.contains('model-file')) return prevSibling // is there another model folder to jump to before the current one? - if (prevSibling.classList.contains('model-folder')) return prevSibling.firstElementChild.lastElementChild + if (prevSibling.classList.contains('model-folder')) return this.getLastVisibleChild(prevSibling.firstElementChild) } } + getNextVisibleSibling(elem) { + let nextSibling = elem.nextElementSibling + while (nextSibling && nextSibling.classList.contains('model-file')) { + if (nextSibling.style.display == 'list-item') return nextSibling + nextSibling = nextSibling.nextElementSibling + } + if (nextSibling && nextSibling.style.display == 'list-item') return nextSibling + } + + getFirstVisibleChild(elem) { + let firstElementChild = elem.firstElementChild + if (firstElementChild.style.display == 'list-item') return firstElementChild + return this.getNextVisibleSibling(firstElementChild) + } + findNextSibling(elem) { // is there an immediate sibling? - let nextSibling = elem.nextElementSibling + let nextSibling = this.getNextVisibleSibling(elem) if (nextSibling) { // if the next sibling is a model file, just select it if (nextSibling.classList.contains('model-file')) return nextSibling @@ -139,13 +178,13 @@ class ModelDropdown } // no sibling model file and no sibling model folder. look for siblings around the parent element. - nextSibling = elem.parentElement.parentElement.nextElementSibling + nextSibling = this.getNextVisibleSibling(elem.parentElement.parentElement) if (nextSibling) { // if the next entry is a model file, select it if (nextSibling.classList.contains('model-file')) return nextSibling // is there another model folder to jump to after the current one? - if (nextSibling.classList.contains('model-folder')) return nextSibling.firstElementChild.firstElementChild + if (nextSibling.classList.contains('model-folder')) return this.getFirstVisibleChild(nextSibling.firstElementChild) } } @@ -219,6 +258,7 @@ class ModelDropdown { this.saveCurrentSelection(this.highlightedModelEntry, this.highlightedModelEntry.innerText, this.highlightedModelEntry.dataset.path) this.hideModelList() + this.showAllEntries() } this.modelFilter.focus() } @@ -423,6 +463,47 @@ class ModelDropdown } /* MODEL LOADER */ + getElementDimensions(element) { + // Clone the element + const clone = element.cloneNode(true) + + // 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) + } + + // Set its visibility to hidden and display to inline-block + clone.style.visibility = "hidden" + clone.style.display = "inline-block" + + // Put the cloned element next to the original element + element.parentNode.insertBefore(clone, element.nextSibling) + + // Get its width and height + const width = clone.offsetWidth + const height = clone.offsetHeight + + // Remove it from the DOM + clone.remove() + + // Return its width and height + return { width, height } + } + + updateInputSize() { + if (this.modelList !== undefined) { + const dimensions = this.getElementDimensions(this.modelList) + this.modelFilter.style.width = dimensions.width + 'px' + this.modelList.style.width = dimensions.width + 'px' + this.modelFilterArrow.style.height = dimensions.height + 'px' + if (this.modelFilter.offsetLeft > 0) { + this.modelList.style.left = this.modelFilter.offsetLeft + 'px' + } + } + } + flattenModelList(models, path) { models.forEach(entry => { if (Array.isArray(entry)) { @@ -489,16 +570,17 @@ class ModelDropdown 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`) - this.modelList.style.display = 'block' - this.modelFilter.style.width = this.modelList.offsetWidth + 'px' - this.modelFilterArrow.style.height = this.modelFilter.offsetHeight + 'px' - this.modelList.style.display = 'none' - - 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)) + this.updateInputSize() + + if (this.modelFilterInitialized !== true) { + 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)) + + this.modelFilterInitialized = true + } 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))