Spaces:
Sleeping
Sleeping
| function toggleCss(key, css, enable) { | |
| var style = document.getElementById(key); | |
| if (enable && !style) { | |
| style = document.createElement('style'); | |
| style.id = key; | |
| style.type = 'text/css'; | |
| document.head.appendChild(style); | |
| } | |
| if (style && !enable) { | |
| document.head.removeChild(style); | |
| } | |
| if (style) { | |
| style.innerHTML == ''; | |
| style.appendChild(document.createTextNode(css)); | |
| } | |
| } | |
| function setupExtraNetworksForTab(tabname) { | |
| function registerPrompt(tabname, id) { | |
| var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); | |
| if (!activePromptTextarea[tabname]) { | |
| activePromptTextarea[tabname] = textarea; | |
| } | |
| textarea.addEventListener("focus", function() { | |
| activePromptTextarea[tabname] = textarea; | |
| }); | |
| } | |
| var tabnav = gradioApp().querySelector('#' + tabname + '_extra_tabs > div.tab-nav'); | |
| var controlsDiv = document.createElement('DIV'); | |
| controlsDiv.classList.add('extra-networks-controls-div'); | |
| tabnav.appendChild(controlsDiv); | |
| tabnav.insertBefore(controlsDiv, null); | |
| var this_tab = gradioApp().querySelector('#' + tabname + '_extra_tabs'); | |
| this_tab.querySelectorAll(":scope > [id^='" + tabname + "_']").forEach(function(elem) { | |
| // tabname_full = {tabname}_{extra_networks_tabname} | |
| var tabname_full = elem.id; | |
| var search = gradioApp().querySelector("#" + tabname_full + "_extra_search"); | |
| var sort_dir = gradioApp().querySelector("#" + tabname_full + "_extra_sort_dir"); | |
| var refresh = gradioApp().querySelector("#" + tabname_full + "_extra_refresh"); | |
| var currentSort = ''; | |
| // If any of the buttons above don't exist, we want to skip this iteration of the loop. | |
| if (!search || !sort_dir || !refresh) { | |
| return; // `return` is equivalent of `continue` but for forEach loops. | |
| } | |
| var applyFilter = function(force) { | |
| var searchTerm = search.value.toLowerCase(); | |
| gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card').forEach(function(elem) { | |
| var searchOnly = elem.querySelector('.search_only'); | |
| var text = Array.prototype.map.call(elem.querySelectorAll('.search_terms, .description'), function(t) { | |
| return t.textContent.toLowerCase(); | |
| }).join(" "); | |
| var visible = text.indexOf(searchTerm) != -1; | |
| if (searchOnly && searchTerm.length < 4) { | |
| visible = false; | |
| } | |
| if (visible) { | |
| elem.classList.remove("hidden"); | |
| } else { | |
| elem.classList.add("hidden"); | |
| } | |
| }); | |
| applySort(force); | |
| }; | |
| var applySort = function(force) { | |
| var cards = gradioApp().querySelectorAll('#' + tabname_full + ' div.card'); | |
| var parent = gradioApp().querySelector('#' + tabname_full + "_cards"); | |
| var reverse = sort_dir.dataset.sortdir == "Descending"; | |
| var activeSearchElem = gradioApp().querySelector('#' + tabname_full + "_controls .extra-network-control--sort.extra-network-control--enabled"); | |
| var sortKey = activeSearchElem ? activeSearchElem.dataset.sortkey : "default"; | |
| var sortKeyDataField = "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1); | |
| var sortKeyStore = sortKey + "-" + sort_dir.dataset.sortdir + "-" + cards.length; | |
| if (sortKeyStore == currentSort && !force) { | |
| return; | |
| } | |
| currentSort = sortKeyStore; | |
| var sortedCards = Array.from(cards); | |
| sortedCards.sort(function(cardA, cardB) { | |
| var a = cardA.dataset[sortKeyDataField]; | |
| var b = cardB.dataset[sortKeyDataField]; | |
| if (!isNaN(a) && !isNaN(b)) { | |
| return parseInt(a) - parseInt(b); | |
| } | |
| return (a < b ? -1 : (a > b ? 1 : 0)); | |
| }); | |
| if (reverse) { | |
| sortedCards.reverse(); | |
| } | |
| parent.innerHTML = ''; | |
| var frag = document.createDocumentFragment(); | |
| sortedCards.forEach(function(card) { | |
| frag.appendChild(card); | |
| }); | |
| parent.appendChild(frag); | |
| }; | |
| search.addEventListener("input", function() { | |
| applyFilter(); | |
| }); | |
| applySort(); | |
| applyFilter(); | |
| extraNetworksApplySort[tabname_full] = applySort; | |
| extraNetworksApplyFilter[tabname_full] = applyFilter; | |
| var controls = gradioApp().querySelector("#" + tabname_full + "_controls"); | |
| controlsDiv.insertBefore(controls, null); | |
| if (elem.style.display != "none") { | |
| extraNetworksShowControlsForPage(tabname, tabname_full); | |
| } | |
| }); | |
| registerPrompt(tabname, tabname + "_prompt"); | |
| registerPrompt(tabname, tabname + "_neg_prompt"); | |
| } | |
| function extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePrompt) { | |
| if (!gradioApp().querySelector('.toprow-compact-tools')) return; // only applicable for compact prompt layout | |
| var promptContainer = gradioApp().getElementById(tabname + '_prompt_container'); | |
| var prompt = gradioApp().getElementById(tabname + '_prompt_row'); | |
| var negPrompt = gradioApp().getElementById(tabname + '_neg_prompt_row'); | |
| var elem = id ? gradioApp().getElementById(id) : null; | |
| if (showNegativePrompt && elem) { | |
| elem.insertBefore(negPrompt, elem.firstChild); | |
| } else { | |
| promptContainer.insertBefore(negPrompt, promptContainer.firstChild); | |
| } | |
| if (showPrompt && elem) { | |
| elem.insertBefore(prompt, elem.firstChild); | |
| } else { | |
| promptContainer.insertBefore(prompt, promptContainer.firstChild); | |
| } | |
| if (elem) { | |
| elem.classList.toggle('extra-page-prompts-active', showNegativePrompt || showPrompt); | |
| } | |
| } | |
| function extraNetworksShowControlsForPage(tabname, tabname_full) { | |
| gradioApp().querySelectorAll('#' + tabname + '_extra_tabs .extra-networks-controls-div > div').forEach(function(elem) { | |
| var targetId = tabname_full + "_controls"; | |
| elem.style.display = elem.id == targetId ? "" : "none"; | |
| }); | |
| } | |
| function extraNetworksUnrelatedTabSelected(tabname) { // called from python when user selects an unrelated tab (generate) | |
| extraNetworksMovePromptToTab(tabname, '', false, false); | |
| extraNetworksShowControlsForPage(tabname, null); | |
| } | |
| function extraNetworksTabSelected(tabname, id, showPrompt, showNegativePrompt, tabname_full) { // called from python when user selects an extra networks tab | |
| extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePrompt); | |
| extraNetworksShowControlsForPage(tabname, tabname_full); | |
| } | |
| function applyExtraNetworkFilter(tabname_full) { | |
| var doFilter = function() { | |
| var applyFunction = extraNetworksApplyFilter[tabname_full]; | |
| if (applyFunction) { | |
| applyFunction(true); | |
| } | |
| }; | |
| setTimeout(doFilter, 1); | |
| } | |
| function applyExtraNetworkSort(tabname_full) { | |
| var doSort = function() { | |
| extraNetworksApplySort[tabname_full](true); | |
| }; | |
| setTimeout(doSort, 1); | |
| } | |
| var extraNetworksApplyFilter = {}; | |
| var extraNetworksApplySort = {}; | |
| var activePromptTextarea = {}; | |
| function setupExtraNetworks() { | |
| setupExtraNetworksForTab('txt2img'); | |
| setupExtraNetworksForTab('img2img'); | |
| } | |
| var re_extranet = /<([^:^>]+:[^:]+):[\d.]+>(.*)/; | |
| var re_extranet_g = /<([^:^>]+:[^:]+):[\d.]+>/g; | |
| var re_extranet_neg = /\(([^:^>]+:[\d.]+)\)/; | |
| var re_extranet_g_neg = /\(([^:^>]+:[\d.]+)\)/g; | |
| function tryToRemoveExtraNetworkFromPrompt(textarea, text, isNeg) { | |
| var m = text.match(isNeg ? re_extranet_neg : re_extranet); | |
| var replaced = false; | |
| var newTextareaText; | |
| var extraTextBeforeNet = opts.extra_networks_add_text_separator; | |
| if (m) { | |
| var extraTextAfterNet = m[2]; | |
| var partToSearch = m[1]; | |
| var foundAtPosition = -1; | |
| newTextareaText = textarea.value.replaceAll(isNeg ? re_extranet_g_neg : re_extranet_g, function(found, net, pos) { | |
| m = found.match(isNeg ? re_extranet_neg : re_extranet); | |
| if (m[1] == partToSearch) { | |
| replaced = true; | |
| foundAtPosition = pos; | |
| return ""; | |
| } | |
| return found; | |
| }); | |
| if (foundAtPosition >= 0) { | |
| if (extraTextAfterNet && newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) { | |
| newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length); | |
| } | |
| if (newTextareaText.substr(foundAtPosition - extraTextBeforeNet.length, extraTextBeforeNet.length) == extraTextBeforeNet) { | |
| newTextareaText = newTextareaText.substr(0, foundAtPosition - extraTextBeforeNet.length) + newTextareaText.substr(foundAtPosition); | |
| } | |
| } | |
| } else { | |
| newTextareaText = textarea.value.replaceAll(new RegExp(`((?:${extraTextBeforeNet})?${text})`, "g"), ""); | |
| replaced = (newTextareaText != textarea.value); | |
| } | |
| if (replaced) { | |
| textarea.value = newTextareaText; | |
| return true; | |
| } | |
| return false; | |
| } | |
| function updatePromptArea(text, textArea, isNeg) { | |
| if (!tryToRemoveExtraNetworkFromPrompt(textArea, text, isNeg)) { | |
| textArea.value = textArea.value + opts.extra_networks_add_text_separator + text; | |
| } | |
| updateInput(textArea); | |
| } | |
| function cardClicked(tabname, textToAdd, textToAddNegative, allowNegativePrompt) { | |
| if (textToAddNegative.length > 0) { | |
| updatePromptArea(textToAdd, gradioApp().querySelector("#" + tabname + "_prompt > label > textarea")); | |
| updatePromptArea(textToAddNegative, gradioApp().querySelector("#" + tabname + "_neg_prompt > label > textarea"), true); | |
| } else { | |
| var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea"); | |
| updatePromptArea(textToAdd, textarea); | |
| } | |
| } | |
| function saveCardPreview(event, tabname, filename) { | |
| var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea'); | |
| var button = gradioApp().getElementById(tabname + '_save_preview'); | |
| textarea.value = filename; | |
| updateInput(textarea); | |
| button.click(); | |
| event.stopPropagation(); | |
| event.preventDefault(); | |
| } | |
| function extraNetworksSearchButton(tabname, extra_networks_tabname, event) { | |
| var searchTextarea = gradioApp().querySelector("#" + tabname + "_" + extra_networks_tabname + "_extra_search"); | |
| var button = event.target; | |
| var text = button.classList.contains("search-all") ? "" : button.textContent.trim(); | |
| searchTextarea.value = text; | |
| updateInput(searchTextarea); | |
| } | |
| function extraNetworksTreeProcessFileClick(event, btn, tabname, extra_networks_tabname) { | |
| /** | |
| * Processes `onclick` events when user clicks on files in tree. | |
| * | |
| * @param event The generated event. | |
| * @param btn The clicked `tree-list-item` button. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| // NOTE: Currently unused. | |
| return; | |
| } | |
| function extraNetworksTreeProcessDirectoryClick(event, btn, tabname, extra_networks_tabname) { | |
| /** | |
| * Processes `onclick` events when user clicks on directories in tree. | |
| * | |
| * Here is how the tree reacts to clicks for various states: | |
| * unselected unopened directory: Directory is selected and expanded. | |
| * unselected opened directory: Directory is selected. | |
| * selected opened directory: Directory is collapsed and deselected. | |
| * chevron is clicked: Directory is expanded or collapsed. Selected state unchanged. | |
| * | |
| * @param event The generated event. | |
| * @param btn The clicked `tree-list-item` button. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| var ul = btn.nextElementSibling; | |
| // This is the actual target that the user clicked on within the target button. | |
| // We use this to detect if the chevron was clicked. | |
| var true_targ = event.target; | |
| function _expand_or_collapse(_ul, _btn) { | |
| // Expands <ul> if it is collapsed, collapses otherwise. Updates button attributes. | |
| if (_ul.hasAttribute("hidden")) { | |
| _ul.removeAttribute("hidden"); | |
| _btn.dataset.expanded = ""; | |
| } else { | |
| _ul.setAttribute("hidden", ""); | |
| delete _btn.dataset.expanded; | |
| } | |
| } | |
| function _remove_selected_from_all() { | |
| // Removes the `selected` attribute from all buttons. | |
| var sels = document.querySelectorAll("div.tree-list-content"); | |
| [...sels].forEach(el => { | |
| delete el.dataset.selected; | |
| }); | |
| } | |
| function _select_button(_btn) { | |
| // Removes `data-selected` attribute from all buttons then adds to passed button. | |
| _remove_selected_from_all(); | |
| _btn.dataset.selected = ""; | |
| } | |
| function _update_search(_tabname, _extra_networks_tabname, _search_text) { | |
| // Update search input with select button's path. | |
| var search_input_elem = gradioApp().querySelector("#" + tabname + "_" + extra_networks_tabname + "_extra_search"); | |
| search_input_elem.value = _search_text; | |
| updateInput(search_input_elem); | |
| } | |
| // If user clicks on the chevron, then we do not select the folder. | |
| if (true_targ.matches(".tree-list-item-action--leading, .tree-list-item-action-chevron")) { | |
| _expand_or_collapse(ul, btn); | |
| } else { | |
| // User clicked anywhere else on the button. | |
| if ("selected" in btn.dataset && !(ul.hasAttribute("hidden"))) { | |
| // If folder is select and open, collapse and deselect button. | |
| _expand_or_collapse(ul, btn); | |
| delete btn.dataset.selected; | |
| _update_search(tabname, extra_networks_tabname, ""); | |
| } else if (!(!("selected" in btn.dataset) && !(ul.hasAttribute("hidden")))) { | |
| // If folder is open and not selected, then we don't collapse; just select. | |
| // NOTE: Double inversion sucks but it is the clearest way to show the branching here. | |
| _expand_or_collapse(ul, btn); | |
| _select_button(btn, tabname, extra_networks_tabname); | |
| _update_search(tabname, extra_networks_tabname, btn.dataset.path); | |
| } else { | |
| // All other cases, just select the button. | |
| _select_button(btn, tabname, extra_networks_tabname); | |
| _update_search(tabname, extra_networks_tabname, btn.dataset.path); | |
| } | |
| } | |
| } | |
| function extraNetworksTreeOnClick(event, tabname, extra_networks_tabname) { | |
| /** | |
| * Handles `onclick` events for buttons within an `extra-network-tree .tree-list--tree`. | |
| * | |
| * Determines whether the clicked button in the tree is for a file entry or a directory | |
| * then calls the appropriate function. | |
| * | |
| * @param event The generated event. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| var btn = event.currentTarget; | |
| var par = btn.parentElement; | |
| if (par.dataset.treeEntryType === "file") { | |
| extraNetworksTreeProcessFileClick(event, btn, tabname, extra_networks_tabname); | |
| } else { | |
| extraNetworksTreeProcessDirectoryClick(event, btn, tabname, extra_networks_tabname); | |
| } | |
| } | |
| function extraNetworksControlSortOnClick(event, tabname, extra_networks_tabname) { | |
| /** Handles `onclick` events for Sort Mode buttons. */ | |
| var self = event.currentTarget; | |
| var parent = event.currentTarget.parentElement; | |
| parent.querySelectorAll('.extra-network-control--sort').forEach(function(x) { | |
| x.classList.remove('extra-network-control--enabled'); | |
| }); | |
| self.classList.add('extra-network-control--enabled'); | |
| applyExtraNetworkSort(tabname + "_" + extra_networks_tabname); | |
| } | |
| function extraNetworksControlSortDirOnClick(event, tabname, extra_networks_tabname) { | |
| /** | |
| * Handles `onclick` events for the Sort Direction button. | |
| * | |
| * Modifies the data attributes of the Sort Direction button to cycle between | |
| * ascending and descending sort directions. | |
| * | |
| * @param event The generated event. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| if (event.currentTarget.dataset.sortdir == "Ascending") { | |
| event.currentTarget.dataset.sortdir = "Descending"; | |
| event.currentTarget.setAttribute("title", "Sort descending"); | |
| } else { | |
| event.currentTarget.dataset.sortdir = "Ascending"; | |
| event.currentTarget.setAttribute("title", "Sort ascending"); | |
| } | |
| applyExtraNetworkSort(tabname + "_" + extra_networks_tabname); | |
| } | |
| function extraNetworksControlTreeViewOnClick(event, tabname, extra_networks_tabname) { | |
| /** | |
| * Handles `onclick` events for the Tree View button. | |
| * | |
| * Toggles the tree view in the extra networks pane. | |
| * | |
| * @param event The generated event. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| var button = event.currentTarget; | |
| button.classList.toggle("extra-network-control--enabled"); | |
| var show = !button.classList.contains("extra-network-control--enabled"); | |
| var pane = gradioApp().getElementById(tabname + "_" + extra_networks_tabname + "_pane"); | |
| pane.classList.toggle("extra-network-dirs-hidden", show); | |
| } | |
| function extraNetworksControlRefreshOnClick(event, tabname, extra_networks_tabname) { | |
| /** | |
| * Handles `onclick` events for the Refresh Page button. | |
| * | |
| * In order to actually call the python functions in `ui_extra_networks.py` | |
| * to refresh the page, we created an empty gradio button in that file with an | |
| * event handler that refreshes the page. So what this function here does | |
| * is it manually raises a `click` event on that button. | |
| * | |
| * @param event The generated event. | |
| * @param tabname The name of the active tab in the sd webui. Ex: txt2img, img2img, etc. | |
| * @param extra_networks_tabname The id of the active extraNetworks tab. Ex: lora, checkpoints, etc. | |
| */ | |
| var btn_refresh_internal = gradioApp().getElementById(tabname + "_" + extra_networks_tabname + "_extra_refresh_internal"); | |
| btn_refresh_internal.dispatchEvent(new Event("click")); | |
| } | |
| var globalPopup = null; | |
| var globalPopupInner = null; | |
| function closePopup() { | |
| if (!globalPopup) return; | |
| globalPopup.style.display = "none"; | |
| } | |
| function popup(contents) { | |
| if (!globalPopup) { | |
| globalPopup = document.createElement('div'); | |
| globalPopup.classList.add('global-popup'); | |
| var close = document.createElement('div'); | |
| close.classList.add('global-popup-close'); | |
| close.addEventListener("click", closePopup); | |
| close.title = "Close"; | |
| globalPopup.appendChild(close); | |
| globalPopupInner = document.createElement('div'); | |
| globalPopupInner.classList.add('global-popup-inner'); | |
| globalPopup.appendChild(globalPopupInner); | |
| gradioApp().querySelector('.main').appendChild(globalPopup); | |
| } | |
| globalPopupInner.innerHTML = ''; | |
| globalPopupInner.appendChild(contents); | |
| globalPopup.style.display = "flex"; | |
| } | |
| var storedPopupIds = {}; | |
| function popupId(id) { | |
| if (!storedPopupIds[id]) { | |
| storedPopupIds[id] = gradioApp().getElementById(id); | |
| } | |
| popup(storedPopupIds[id]); | |
| } | |
| function extraNetworksFlattenMetadata(obj) { | |
| const result = {}; | |
| // Convert any stringified JSON objects to actual objects | |
| for (const key of Object.keys(obj)) { | |
| if (typeof obj[key] === 'string') { | |
| try { | |
| const parsed = JSON.parse(obj[key]); | |
| if (parsed && typeof parsed === 'object') { | |
| obj[key] = parsed; | |
| } | |
| } catch (error) { | |
| continue; | |
| } | |
| } | |
| } | |
| // Flatten the object | |
| for (const key of Object.keys(obj)) { | |
| if (typeof obj[key] === 'object' && obj[key] !== null) { | |
| const nested = extraNetworksFlattenMetadata(obj[key]); | |
| for (const nestedKey of Object.keys(nested)) { | |
| result[`${key}/${nestedKey}`] = nested[nestedKey]; | |
| } | |
| } else { | |
| result[key] = obj[key]; | |
| } | |
| } | |
| // Special case for handling modelspec keys | |
| for (const key of Object.keys(result)) { | |
| if (key.startsWith("modelspec.")) { | |
| result[key.replaceAll(".", "/")] = result[key]; | |
| delete result[key]; | |
| } | |
| } | |
| // Add empty keys to designate hierarchy | |
| for (const key of Object.keys(result)) { | |
| const parts = key.split("/"); | |
| for (let i = 1; i < parts.length; i++) { | |
| const parent = parts.slice(0, i).join("/"); | |
| if (!result[parent]) { | |
| result[parent] = ""; | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| function extraNetworksShowMetadata(text) { | |
| try { | |
| let parsed = JSON.parse(text); | |
| if (parsed && typeof parsed === 'object') { | |
| parsed = extraNetworksFlattenMetadata(parsed); | |
| const table = createVisualizationTable(parsed, 0); | |
| popup(table); | |
| return; | |
| } | |
| } catch (error) { | |
| console.error(error); | |
| } | |
| var elem = document.createElement('pre'); | |
| elem.classList.add('popup-metadata'); | |
| elem.textContent = text; | |
| popup(elem); | |
| return; | |
| } | |
| function requestGet(url, data, handler, errorHandler) { | |
| var xhr = new XMLHttpRequest(); | |
| var args = Object.keys(data).map(function(k) { | |
| return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]); | |
| }).join('&'); | |
| xhr.open("GET", url + "?" + args, true); | |
| xhr.onreadystatechange = function() { | |
| if (xhr.readyState === 4) { | |
| if (xhr.status === 200) { | |
| try { | |
| var js = JSON.parse(xhr.responseText); | |
| handler(js); | |
| } catch (error) { | |
| console.error(error); | |
| errorHandler(); | |
| } | |
| } else { | |
| errorHandler(); | |
| } | |
| } | |
| }; | |
| var js = JSON.stringify(data); | |
| xhr.send(js); | |
| } | |
| function extraNetworksCopyCardPath(event) { | |
| navigator.clipboard.writeText(event.target.getAttribute("data-clipboard-text")); | |
| event.stopPropagation(); | |
| } | |
| function extraNetworksRequestMetadata(event, extraPage) { | |
| var showError = function() { | |
| extraNetworksShowMetadata("there was an error getting metadata"); | |
| }; | |
| var cardName = event.target.parentElement.parentElement.getAttribute("data-name"); | |
| requestGet("./sd_extra_networks/metadata", {page: extraPage, item: cardName}, function(data) { | |
| if (data && data.metadata) { | |
| extraNetworksShowMetadata(data.metadata); | |
| } else { | |
| showError(); | |
| } | |
| }, showError); | |
| event.stopPropagation(); | |
| } | |
| var extraPageUserMetadataEditors = {}; | |
| function extraNetworksEditUserMetadata(event, tabname, extraPage) { | |
| var id = tabname + '_' + extraPage + '_edit_user_metadata'; | |
| var editor = extraPageUserMetadataEditors[id]; | |
| if (!editor) { | |
| editor = {}; | |
| editor.page = gradioApp().getElementById(id); | |
| editor.nameTextarea = gradioApp().querySelector("#" + id + "_name" + ' textarea'); | |
| editor.button = gradioApp().querySelector("#" + id + "_button"); | |
| extraPageUserMetadataEditors[id] = editor; | |
| } | |
| var cardName = event.target.parentElement.parentElement.getAttribute("data-name"); | |
| editor.nameTextarea.value = cardName; | |
| updateInput(editor.nameTextarea); | |
| editor.button.click(); | |
| popup(editor.page); | |
| event.stopPropagation(); | |
| } | |
| function extraNetworksRefreshSingleCard(page, tabname, name) { | |
| requestGet("./sd_extra_networks/get-single-card", {page: page, tabname: tabname, name: name}, function(data) { | |
| if (data && data.html) { | |
| var card = gradioApp().querySelector(`#${tabname}_${page.replace(" ", "_")}_cards > .card[data-name="${name}"]`); | |
| var newDiv = document.createElement('DIV'); | |
| newDiv.innerHTML = data.html; | |
| var newCard = newDiv.firstElementChild; | |
| newCard.style.display = ''; | |
| card.parentElement.insertBefore(newCard, card); | |
| card.parentElement.removeChild(card); | |
| } | |
| }); | |
| } | |
| window.addEventListener("keydown", function(event) { | |
| if (event.key == "Escape") { | |
| closePopup(); | |
| } | |
| }); | |
| /** | |
| * Setup custom loading for this script. | |
| * We need to wait for all of our HTML to be generated in the extra networks tabs | |
| * before we can actually run the `setupExtraNetworks` function. | |
| * The `onUiLoaded` function actually runs before all of our extra network tabs are | |
| * finished generating. Thus we needed this new method. | |
| * | |
| */ | |
| var uiAfterScriptsCallbacks = []; | |
| var uiAfterScriptsTimeout = null; | |
| var executedAfterScripts = false; | |
| function scheduleAfterScriptsCallbacks() { | |
| clearTimeout(uiAfterScriptsTimeout); | |
| uiAfterScriptsTimeout = setTimeout(function() { | |
| executeCallbacks(uiAfterScriptsCallbacks); | |
| }, 200); | |
| } | |
| onUiLoaded(function() { | |
| var mutationObserver = new MutationObserver(function(m) { | |
| let existingSearchfields = gradioApp().querySelectorAll("[id$='_extra_search']").length; | |
| let neededSearchfields = gradioApp().querySelectorAll("[id$='_extra_tabs'] > .tab-nav > button").length - 2; | |
| if (!executedAfterScripts && existingSearchfields >= neededSearchfields) { | |
| mutationObserver.disconnect(); | |
| executedAfterScripts = true; | |
| scheduleAfterScriptsCallbacks(); | |
| } | |
| }); | |
| mutationObserver.observe(gradioApp(), {childList: true, subtree: true}); | |
| }); | |
| uiAfterScriptsCallbacks.push(setupExtraNetworks); | |