From 1caab1da85cd52b0e9bd630665e72ebced5768b3 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Fri, 17 Feb 2023 00:54:41 +0100 Subject: [PATCH 1/5] Only confirm image deletion once The previous code added an event listener per preview image (if live preview is enabled), so that multiple confirmations were required. --- ui/media/js/main.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index db913a2a..2d99e341 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -270,6 +270,22 @@ function showImages(reqBody, res, outputContainer, livePreview) { ` outputContainer.appendChild(imageItemElem) + const imageRemoveBtn = imageItemElem.querySelector('.imgPreviewItemClearBtn') + let parentTaskContainer = imageRemoveBtn.closest('.imageTaskContainer') + imageRemoveBtn.addEventListener('click', (e) => { + shiftOrConfirm(e, "Remove the image from the results?", () => { + imageItemElem.style.display = 'none' + let allHidden = true; + let children = parentTaskContainer.querySelectorAll('.imgItem'); + for(let x = 0; x < children.length; x++) { + let child = children[x]; + if(child.style.display != "none") { + allHidden = false; + } + } + if(allHidden === true) {parentTaskContainer.classList.add("displayNone")} + }) + }) } const imageElem = imageItemElem.querySelector('img') imageElem.src = imageData @@ -279,23 +295,6 @@ function showImages(reqBody, res, outputContainer, livePreview) { imageElem.setAttribute('data-steps', imageInferenceSteps) imageElem.setAttribute('data-guidance', imageGuidanceScale) - const imageRemoveBtn = imageItemElem.querySelector('.imgPreviewItemClearBtn') - let parentTaskContainer = imageRemoveBtn.closest('.imageTaskContainer') - imageRemoveBtn.addEventListener('click', (e) => { - console.log(e) - shiftOrConfirm(e, "Remove the image from the results?", () => { - imageItemElem.style.display = 'none' - let allHidden = true; - let children = parentTaskContainer.querySelectorAll('.imgItem'); - for(let x = 0; x < children.length; x++) { - let child = children[x]; - if(child.style.display != "none") { - allHidden = false; - } - } - if(allHidden === true) {parentTaskContainer.classList.add("displayNone")} - }) - }) const imageInfo = imageItemElem.querySelector('.imgItemInfo') imageInfo.style.visibility = (livePreview ? 'hidden' : 'visible') From 9bec441e94bcc7169fb2ac4cccb456e05cd09203 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Thu, 16 Feb 2023 21:03:02 -0500 Subject: [PATCH 2/5] Fix model folders being split up by child folders --- ui/media/js/searchable-models.js | 199 +++++++++++++++++++------------ 1 file changed, 124 insertions(+), 75 deletions(-) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 1e02cb98..4896a4cb 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -494,45 +494,16 @@ class ModelDropdown // Return its width and height return { width, height } } - - flattenModelList(models, path) { - models.forEach(entry => { - if (Array.isArray(entry)) { - this.flattenModelList(entry[1], path + '/' + entry[0]) - } - else - { - this.flatModelList.push(path == '' ? entry : path + '/' + entry) - } - }) - } - // sort models getFolder(model) { return model.substring(0, model.lastIndexOf('/') + 1) } - sortModels(models) { - // sort the models in alphabetical order, root folder models last - models.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) - - /* - // sort the models in alphabetical order, root folder models first - models = models.sort() - let found - do { - found = false - for (let i = 0; i < models.length - 1; i++) { - if ( - (this.getFolder(models[i]) === this.getFolder(models[i+1]) && models[i].toLowerCase().localeCompare(models[i+1].toLowerCase()) > 0) // same folder, sort by alphabetical order - || (this.getFolder(models[i]).toLowerCase().localeCompare(this.getFolder(models[i+1]).toLowerCase()) > 0) // L1 folder > L2 folder - ) { - [models[i], models[i+1]] = [models[i+1], models[i]] - found = true - } - } - } while (found) - */ + /** + * @param {Array} models + */ + sortStringArray(models) { + models.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' })) } populateModels() { @@ -550,12 +521,16 @@ class ModelDropdown } createDropdown() { - // prepare to sort the models - this.flattenModelList(this.inputModels, '') - this.sortModels(this.flatModelList) - // create dropdown entries - this.modelFilter.insertAdjacentHTML('afterend', this.parseModels(this.flatModelList)) + this.modelFilter.insertAdjacentElement( + 'afterend', + this.createElement( + 'a', + { id: `${this.modelFilter.id}-model-filter-arrow` }, + ['models-selector-arrow', 'fa-solid', 'fa-angle-down'], + ), + ) + this.modelFilter.insertAdjacentElement('afterend', this.createRootModelList(this.inputModels)) this.modelFilter.classList.add('model-selector') this.modelFilterArrow = document.querySelector(`#${this.modelFilter.id}-model-filter-arrow`) // if (this.modelFilterArrow) { @@ -581,47 +556,121 @@ class ModelDropdown this.selectEntry(this.activeModel) } - parseModels(models) { - let html = ` -
    -
  • No result
  • -
  • -
      - ` - if (this.noneEntry != '') { - html += `
    • ${this.noneEntry}
    • ` + /** + * + * @param {string} tag + * @param {object} attributes + * @param {Array} classes + * @returns {HTMLElement} + */ + createElement(tagName, attributes, classes, text) { + const element = document.createElement(tagName) + if (attributes) { + Object.entries(attributes).forEach(([key, value]) => { + element.setAttribute(key, value) + }) } - - let currentFolder = '' - models.forEach(entry => { - const folder = entry.substring(0, 1) == '/' ? entry.substring(1, entry.lastIndexOf('/')) : '' - if (folder !== '' && folder !== currentFolder) { - if (currentFolder != '') { - html += '
  • ' + if (classes) { + classes.forEach(className => element.classList.add(className)) + } + if (text) { + element.appendChild(document.createTextNode(text)) + } + return element + } + + /** + * @param {Array { + if (Array.isArray(model)) { + const [childFolderName, childModels] = model + foldersMap.set( + childFolderName, + this.createModelNodeList( + `${folderName || '/'}${childFolderName}/`, + childModels, + false, + ), + ) + } else { + const classes = ['model-file'] + if (isRootFolder) { + classes.push('in-root-folder') } - html += `
  • /${folder}
      ` - currentFolder = folder + const fullPath = `${folderName || ''}${model}` + modelsMap.set( + model, + this.createElement('li', { 'data-path': fullPath }, classes, model), + ) } - else if (folder == '' && currentFolder !== '') { - currentFolder = '' - html += '
  • ' - } - const modelName = entry.substring(entry.lastIndexOf('/') + 1) - if (entry.substring(0, 1) == '/') { - entry = entry.substring(1) - } - html += `
  • ${modelName}
  • ` }) - if (currentFolder != '') { - html += '
' + + const childFolderNames = Array.from(foldersMap.keys()) + this.sortStringArray(childFolderNames) + const folderElements = childFolderNames.map(name => foldersMap.get(name)) + + const modelNames = Array.from(modelsMap.keys()) + this.sortStringArray(modelNames) + const modelElements = modelNames.map(name => modelsMap.get(name)) + + if (modelElements.length && folderName) { + listElement.appendChild(this.createElement('li', undefined, ['model-folder'], folderName)) } - - html += ` - - - - ` - return html + + const allModelElements = isRootFolder ? [...folderElements, ...modelElements] : [...modelElements, ...folderElements] + allModelElements.forEach(e => listElement.appendChild(e)) + return listElement + } + + /** + * @param {object} modelTree + * @returns {HTMLElement} + */ + createRootModelList(modelTree) { + const rootList = this.createElement( + 'ul', + { id: `${this.modelFilter.id}-model-list` }, + ['model-list'], + ) + rootList.appendChild( + this.createElement( + 'li', + { id: `${this.modelFilter.id}-model-no-result` }, + ['model-no-result'], + 'No result' + ), + ) + + if (this.noneEntry) { + rootList.appendChild( + this.createElement( + 'li', + { 'data-path': '' }, + ['model-file', 'in-root-folder'], + this.noneEntry, + ), + ) + } + + const containerListItem = this.createElement( + 'li', + { id: `${this.modelFilter.id}-model-result` }, + ['model-result'], + ) + containerListItem.appendChild(this.createModelNodeList(undefined, modelTree, true)) + rootList.appendChild(containerListItem) + + return rootList } } From fc2cf742c8a0276a15a48d6f09fa2d677c858662 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Thu, 16 Feb 2023 21:08:41 -0500 Subject: [PATCH 3/5] Remove trailing slash --- ui/media/js/searchable-models.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 4896a4cb..68383621 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -597,7 +597,7 @@ class ModelDropdown foldersMap.set( childFolderName, this.createModelNodeList( - `${folderName || '/'}${childFolderName}/`, + `${folderName || ''}/${childFolderName}`, childModels, false, ), @@ -607,7 +607,7 @@ class ModelDropdown if (isRootFolder) { classes.push('in-root-folder') } - const fullPath = `${folderName || ''}${model}` + const fullPath = `${folderName || ''}/${model}` modelsMap.set( model, this.createElement('li', { 'data-path': fullPath }, classes, model), From df93fee034a81b265409bcde6be9f1f6136071cd Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Thu, 16 Feb 2023 21:16:19 -0500 Subject: [PATCH 4/5] Fix model dropdown icon --- ui/media/js/searchable-models.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 68383621..737c7ee5 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -522,15 +522,15 @@ class ModelDropdown createDropdown() { // create dropdown entries + this.modelFilter.insertAdjacentElement('afterend', this.createRootModelList(this.inputModels)) this.modelFilter.insertAdjacentElement( 'afterend', this.createElement( - 'a', + 'i', { id: `${this.modelFilter.id}-model-filter-arrow` }, - ['models-selector-arrow', 'fa-solid', 'fa-angle-down'], + ['model-selector-arrow', 'fa-solid', 'fa-angle-down'], ), ) - this.modelFilter.insertAdjacentElement('afterend', this.createRootModelList(this.inputModels)) this.modelFilter.classList.add('model-selector') this.modelFilterArrow = document.querySelector(`#${this.modelFilter.id}-model-filter-arrow`) // if (this.modelFilterArrow) { From 09c1dfd92b54c3c29ce00db8c9b959b88828ec79 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Thu, 16 Feb 2023 23:29:32 -0500 Subject: [PATCH 5/5] Remove leading slash from data-path attributes --- ui/media/js/searchable-models.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 737c7ee5..86c5c068 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -494,10 +494,6 @@ class ModelDropdown // Return its width and height return { width, height } } - - getFolder(model) { - return model.substring(0, model.lastIndexOf('/') + 1) - } /** * @param {Array} models @@ -607,7 +603,8 @@ class ModelDropdown if (isRootFolder) { classes.push('in-root-folder') } - const fullPath = `${folderName || ''}/${model}` + // Remove the leading slash from the model path + const fullPath = folderName ? `${folderName.substring(1)}/${model}` : model modelsMap.set( model, this.createElement('li', { 'data-path': fullPath }, classes, model),