diff --git a/ui/media/js/auto-save.js b/ui/media/js/auto-save.js
index 5ada13d5..bcfd4bc6 100644
--- a/ui/media/js/auto-save.js
+++ b/ui/media/js/auto-save.js
@@ -56,6 +56,7 @@ const SETTINGS_IDS_LIST = [
"tree_toggle",
"json_toggle",
"extract_lora_from_prompt",
+ "embedding-card-size-selector",
]
const IGNORE_BY_DEFAULT = ["prompt"]
diff --git a/ui/media/js/main.js b/ui/media/js/main.js
index 30ed6012..b440e794 100644
--- a/ui/media/js/main.js
+++ b/ui/media/js/main.js
@@ -141,6 +141,7 @@ let embeddingsDialogCloseBtn = embeddingsDialog.querySelector("#embeddings-dialo
let embeddingsSearchBox = document.querySelector("#embeddings-search-box")
let embeddingsList = document.querySelector("#embeddings-list")
let embeddingsModeField = document.querySelector("#embeddings-mode")
+let embeddingsCardSizeSelector = document.querySelector("#embedding-card-size-selector")
let positiveEmbeddingText = document.querySelector("#positive-embedding-text")
let negativeEmbeddingText = document.querySelector("#negative-embedding-text")
@@ -684,6 +685,7 @@ function onMakeSimilarClick(req, img) {
createTask(newTaskRequest)
}
+// gets a flat list of all models of a certain type, ignoring directories
function getAllModelNames(type) {
function f(tree) {
if (tree == undefined) {
@@ -808,7 +810,6 @@ useAsThumbSaveBtn.addEventListener("click", (e) => {
})
})
-
function enqueueImageVariationTask(req, img, reqDiff) {
const imageSeed = img.getAttribute("data-seed")
@@ -2645,43 +2646,50 @@ let icl = []
function updateEmbeddingsList(filter = "") {
function html(model, iconlist = [], prefix = "", filter = "") {
filter = filter.toLowerCase()
- let toplevel = ""
- let folders = ""
- console.log(iconlist)
+ let toplevel = document.createElement("div")
+ let folders = document.createElement("div")
let embIcon = Object.assign({}, ...iconlist.map( x=> ({[x.toLowerCase().split('.').slice(0,-1).join('.')]:x})))
- console.log(embIcon)
let profileName = profileNameField.value
model?.forEach((m) => {
if (typeof m == "string") {
let token=m.toLowerCase()
if (token.search(filter) != -1) {
- let img = '/media/images/noimg.png'
- if (token in embIcon) {
- img = `/bucket/${profileName}/embeddings/${embIcon[token]}`
- }
+ let button
if (iconlist.length==0) {
- img=""
+ button = document.createElement("button")
+ button.innerText="m"
} else {
- img=`

`
+ let img = '/media/images/noimg.png'
+ if (token in embIcon) {
+ img = `/bucket/${profileName}/embeddings/${embIcon[token]}`
+ }
+ button = createModifierCard(m, [img,img], true)
}
- toplevel += `
`
+ button.dataset["embedding"] = m
+ button.addEventListener("click", onButtonClick)
+ toplevel.appendChild(button)
}
} else {
let subdir = html(m[1], iconlist, prefix + m[0] + "/", filter)
- if (subdir != "") {
- folders +=
- `
${prefix}${m[0]}
` +
- subdir +
- "
"
+ if (typeof(subdir) == "object") {
+ let div1 = document.createElement("div")
+ let div2 = document.createElement("div")
+ div1.classList.add("collapsible-content")
+ div1.classList.add("embedding-category")
+ div1.appendChild(subdir)
+ div2.replaceChildren(htmlToElement(`
${prefix}${m[0]}
`), div1)
+ folders.appendChild(div2)
}
}
})
- return toplevel + folders
+ let result = document.createElement("div")
+ result.replaceChildren(toplevel, htmlToElement('
'), folders)
+ return result
}
function onButtonClick(e) {
- let text = e.target.closest("button").dataset["embedding"]
+ let text = e.target.closest("[data-embedding]").dataset["embedding"]
const insertIntoNegative = e.shiftKey || positiveEmbeddingText.classList.contains("displayNone")
if (embeddingsModeField.value == "insert") {
@@ -2717,7 +2725,7 @@ function updateEmbeddingsList(filter = "") {
`
// Remove after fixing https://github.com/huggingface/diffusers/issues/3922
- let warning = ""
+ let warning = "
"
if (vramUsageLevelField.value == "low") {
warning = `
@@ -2731,14 +2739,12 @@ function updateEmbeddingsList(filter = "") {
.then(response => response.status==200 ? response.json(): [])
.then(async function(iconlist) {
- embeddingsList.innerHTML = warning + html(modelsOptions.embeddings, iconlist, "", filter)
- embeddingsList.querySelectorAll("button").forEach((b) => {
- b.addEventListener("click", onButtonClick)
- })
+ embeddingsList.replaceChildren(htmlToElement(warning), html(modelsOptions.embeddings, iconlist, "", filter))
createCollapsibles(embeddingsList)
if (filter != "") {
embeddingsExpandAll()
}
+ resizeModifierCards(embeddingsCardSizeSelector.value)
})
}
@@ -2747,23 +2753,33 @@ function showEmbeddingDialog() {
embeddingsSearchBox.value = ""
embeddingsDialog.showModal()
}
+
embeddingsButton.addEventListener("click", () => {
positiveEmbeddingText.classList.remove("displayNone")
negativeEmbeddingText.classList.add("displayNone")
showEmbeddingDialog()
})
+
negativeEmbeddingsButton.addEventListener("click", () => {
positiveEmbeddingText.classList.add("displayNone")
negativeEmbeddingText.classList.remove("displayNone")
showEmbeddingDialog()
})
+
embeddingsDialogCloseBtn.addEventListener("click", (e) => {
embeddingsDialog.close()
})
+
embeddingsSearchBox.addEventListener("input", (e) => {
updateEmbeddingsList(embeddingsSearchBox.value)
})
+embeddingsCardSizeSelector.addEventListener("change", (e) => {
+ resizeModifierCards(embeddingsCardSizeSelector.value)
+})
+
+
+
modalDialogCloseOnBackdropClick(embeddingsDialog)
makeDialogDraggable(embeddingsDialog)
diff --git a/ui/media/js/utils.js b/ui/media/js/utils.js
index 673ba3dd..8fef9450 100644
--- a/ui/media/js/utils.js
+++ b/ui/media/js/utils.js
@@ -1097,6 +1097,14 @@ async function deleteKeys(keyToDelete) {
}
}
+/**
+ * @param {String} Data URL of the image
+ * @param {Integer} Top left X-coordinate of the crop area
+ * @param {Integer} Top left Y-coordinate of the crop area
+ * @param {Integer} Width of the crop area
+ * @param {Integer} Height of the crop area
+ * @return {String}
+ */
function cropImageDataUrl(dataUrl, x, y, width, height) {
return new Promise((resolve, reject) => {
const image = new Image()
@@ -1120,6 +1128,16 @@ function cropImageDataUrl(dataUrl, x, y, width, height) {
})
}
+/**
+ * @param {String} HTML representing a single element
+ * @return {Element}
+ */
+function htmlToElement(html) {
+ var template = document.createElement('template');
+ html = html.trim(); // Never return a text node of whitespace as the result
+ template.innerHTML = html;
+ return template.content.firstChild;
+}
function modalDialogCloseOnBackdropClick(dialog) {
dialog.addEventListener('mousedown', function (event) {