mirror of
https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
synced 2026-02-03 06:13:06 -08:00
Finish initial conversion to clusterize using data loader. Need to fix bugs.
This commit is contained in:
parent
fc7a8a41e5
commit
5e4dfee153
9 changed files with 643 additions and 566 deletions
|
|
@ -11,15 +11,300 @@ const re_extranet = /<([^:^>]+:[^:]+):[\d.]+>(.*)/;
|
|||
const re_extranet_g = /<([^:^>]+:[^:]+):[\d.]+>/g;
|
||||
const re_extranet_neg = /\(([^:^>]+:[\d.]+)\)/;
|
||||
const re_extranet_g_neg = /\(([^:^>]+:[\d.]+)\)/g;
|
||||
const activePromptTextarea = {};
|
||||
const clusterizers = {};
|
||||
var globalPopup = null;
|
||||
var globalPopupInner = null;
|
||||
const storedPopupIds = {};
|
||||
const extraPageUserMetadataEditors = {};
|
||||
const extra_networks_tabs = {};
|
||||
// A flag used by the `waitForBool` promise to determine when we first load Ui Options.
|
||||
const initialUiOptionsLoaded = {state: false};
|
||||
|
||||
class ExtraNetworksTab {
|
||||
tree_list;
|
||||
cards_list;
|
||||
container_elem;
|
||||
controls_elem;
|
||||
txt_search_elem;
|
||||
prompt_container_elem;
|
||||
prompts_elem;
|
||||
prompt_row_elem;
|
||||
neg_prompt_row_elem;
|
||||
txt_prompt_elem;
|
||||
txt_neg_prompt_elem;
|
||||
active_prompt_elem;
|
||||
show_prompt = true;
|
||||
show_neg_prompt = true;
|
||||
compact_prompt_en = false;
|
||||
constructor({tabname, extra_networks_tabname}) {
|
||||
this.tabname = tabname;
|
||||
this.extra_networks_tabname = extra_networks_tabname;
|
||||
this.tabname_full = `${tabname}_${extra_networks_tabname}`;
|
||||
}
|
||||
|
||||
async setup(pane, controls_div) {
|
||||
this.container_elem = pane;
|
||||
|
||||
// get page elements
|
||||
await Promise.all([
|
||||
waitForElement(`#${this.tabname_full}_pane .extra-network-controls`).then(elem => this.controls_elem = elem),
|
||||
waitForElement(`#${this.tabname}_prompt_container`).then(elem => this.prompt_container_elem = elem),
|
||||
waitForElement(`#${this.tabname_full}_prompts`).then(elem => this.prompts_elem = elem),
|
||||
waitForElement(`#${this.tabname}_prompt_row`).then(elem => this.prompt_row_elem = elem),
|
||||
waitForElement(`#${this.tabname}_neg_prompt_row`).then(elem => this.neg_prompt_row_elem = elem),
|
||||
waitForElement(`#${this.tabname_full}_tree_list_scroll_area`),
|
||||
waitForElement(`#${this.tabname_full}_tree_list_content_area`),
|
||||
waitForElement(`#${this.tabname_full}_cards_list_scroll_area`),
|
||||
waitForElement(`#${this.tabname_full}_cards_list_content_area`),
|
||||
]);
|
||||
|
||||
this.txt_search_elem = this.controls_elem.querySelector(".extra-network-control--search-text");
|
||||
|
||||
// determine whether compact prompt mode is enabled.
|
||||
// cannot await this since it may not exist on page depending on user setting.
|
||||
this.compact_prompt_en = isElement(gradioApp().querySelector(".toprow-compact-tools"));
|
||||
|
||||
// setup this tab's controls
|
||||
this.controls_elem.id = `${this.tabname_full}_controls`;
|
||||
controls_div.insertBefore(this.controls_elem, null);
|
||||
|
||||
await this.setupTreeList();
|
||||
await this.setupCardsList();
|
||||
|
||||
this.registerPrompt();
|
||||
|
||||
if (this.container_elem.style.display === "none") {
|
||||
this.hideControls();
|
||||
} else {
|
||||
this.showControls();
|
||||
}
|
||||
}
|
||||
|
||||
async registerPrompt() {
|
||||
await Promise.all([
|
||||
waitForElement(`#${this.tabname}_prompt > label > textarea`).then(elem => this.txt_prompt_elem = elem),
|
||||
waitForElement(`#${this.tabname}_neg_prompt > label > textarea`).then(elem => this.txt_neg_prompt_elem = elem),
|
||||
]);
|
||||
this.active_prompt_elem = this.txt_prompt_elem;
|
||||
this.txt_prompt_elem.addEventListener("focus", () => this.active_prompt_elem = this.txt_prompt_elem);
|
||||
this.txt_neg_prompt_elem.addEventListener("focus", () => this.active_prompt_elem = this.txt_neg_prompt_elem);
|
||||
}
|
||||
|
||||
async setupTreeList() {
|
||||
if (this.tree_list instanceof ExtraNetworksClusterizeTreeList) {
|
||||
this.tree_list.destroy();
|
||||
}
|
||||
this.tree_list = new ExtraNetworksClusterizeTreeList({
|
||||
tabname: this.tabname,
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
scrollId: `${this.tabname_full}_tree_list_scroll_area`,
|
||||
contentId: `${this.tabname_full}_tree_list_content_area`,
|
||||
tag: "button",
|
||||
callbacks: {
|
||||
initData: this.onInitTreeData,
|
||||
fetchData: this.onFetchTreeData,
|
||||
},
|
||||
});
|
||||
await this.tree_list.setup();
|
||||
}
|
||||
|
||||
async setupCardsList() {
|
||||
if (this.cards_list instanceof ExtraNetworksClusterizeCardsList) {
|
||||
this.cards_list.destroy();
|
||||
}
|
||||
this.cards_list = new ExtraNetworksClusterizeCardsList({
|
||||
tabname: this.tabname,
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
scrollId: `${this.tabname_full}_cards_list_scroll_area`,
|
||||
contentId: `${this.tabname_full}_cards_list_content_area`,
|
||||
tag: "div",
|
||||
callbacks: {
|
||||
initData: this.onInitCardsData,
|
||||
fetchData: this.onFetchCardsData,
|
||||
},
|
||||
});
|
||||
await this.cards_list.setup();
|
||||
}
|
||||
|
||||
movePrompt(show_prompt=true, show_neg_prompt=true) {
|
||||
// This function only applies when compact prompt mode is enabled.
|
||||
if (!this.compact_prompt_en) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (show_neg_prompt) {
|
||||
this.prompts_elem.insertBefore(this.neg_prompt_row_elem, this.prompts_elem.firstChild);
|
||||
}
|
||||
|
||||
if (show_prompt) {
|
||||
this.prompts_elem.insertBefore(this.prompt_row_elem, this.prompts_elem.firstChild);
|
||||
}
|
||||
|
||||
this.prompts_elem.classList.toggle("extra-page-prompts-active", show_neg_prompt || show_prompt);
|
||||
}
|
||||
|
||||
async refreshSingleCard(name) {
|
||||
await requestGetPromise(
|
||||
"./sd_extra_networks/get-single-card",
|
||||
{
|
||||
tabname: this.tabname,
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
name: name,
|
||||
},
|
||||
(data) => {
|
||||
if (data && data.html) {
|
||||
const card = this.cards_list.content_elem.querySelector(`.card[data-name="${name}"]`);
|
||||
const new_div = document.createElement("div");
|
||||
new_div.innerHTML = data.html;
|
||||
const new_card = new_div.firstElementChild;
|
||||
new_card.style.display = "";
|
||||
card.parentElement.insertBefore(new_card, card);
|
||||
card.parentElement.removeChild(card);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
showControls() {
|
||||
this.controls_elem.classList.remove("hidden");
|
||||
}
|
||||
|
||||
hideControls() {
|
||||
this.controls_elem.classList.add("hidden");
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
const btn_dirs_view = this.controls_elem.querySelector(".extra-network-control--dirs-view");
|
||||
const btn_tree_view = this.controls_elem.querySelector(".extra-network-control--tree-view");
|
||||
const div_dirs = this.container_elem.querySelector(".extra-network-content--dirs-view");
|
||||
const div_tree = this.container_elem.querySelector(
|
||||
`.extra-network-content.resize-handle-col:has(> #${this.tabname_full}_tree_list_scroll_area)`
|
||||
);
|
||||
|
||||
// Remove "hidden" class if button is enabled, otherwise add it.
|
||||
div_dirs.classList.toggle("hidden", !("selected" in btn_dirs_view.dataset));
|
||||
div_tree.classList.toggle("hidden", !("selected" in btn_tree_view.dataset));
|
||||
|
||||
await Promise.all([this.setupTreeList(), this.setupCardsList()]);
|
||||
this.tree_list.enable();
|
||||
this.cards_list.enable();
|
||||
await Promise.all([this.tree_list.load(true), this.cards_list.load(true)]);
|
||||
}
|
||||
|
||||
async load(show_prompt, show_neg_prompt) {
|
||||
this.movePrompt(show_prompt=show_prompt, show_neg_prompt=show_neg_prompt);
|
||||
this.showControls();
|
||||
this.tree_list.enable(true);
|
||||
this.cards_list.enable(true);
|
||||
await Promise.all([this.tree_list.load(), this.cards_list.load()]);
|
||||
}
|
||||
|
||||
unload() {
|
||||
this.movePrompt(false, false);
|
||||
this.hideControls();
|
||||
this.tree_list.enable(false);
|
||||
this.cards_list.enable(false);
|
||||
}
|
||||
|
||||
applyFilter() {
|
||||
// We only want to filter/sort the cards list.
|
||||
this.cards_list.setFilterStr(this.txt_search_elem.value.toLowerCase());
|
||||
|
||||
// If the search input has changed since selecting a button to populate it
|
||||
// then we want to disable the button that previously populated the search input.
|
||||
|
||||
// tree view buttons
|
||||
let btn = this.container_elem.querySelector(".tree-list-item[data-selected='']");
|
||||
if (isElement(btn) && btn.dataset.path !== this.txt_search_elem.value && "selected" in btn.dataset) {
|
||||
this.tree_list.onRowSelected(btn.dataset.divId, btn, false);
|
||||
}
|
||||
// dirs view buttons
|
||||
btn = this.container_elem.querySelector(".extra-network-dirs-view-button[data-selected='']");
|
||||
if (isElement(btn) && btn.textContent.trim() !== this.txt_search_elem.value) {
|
||||
delete btn.dataset.selected;
|
||||
}
|
||||
}
|
||||
|
||||
async onInitCardsData() {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/init-cards-data",
|
||||
{
|
||||
tabname: this.tabname,
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async onInitTreeData() {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/init-tree-data",
|
||||
{
|
||||
tabname: this.tabname,
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async onFetchCardsData(div_ids) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/fetch-cards-data",
|
||||
{
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
div_ids: div_ids,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async onFetchTreeData(div_ids) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/fetch-tree-data",
|
||||
{
|
||||
extra_networks_tabname: this.extra_networks_tabname,
|
||||
div_ids: div_ids,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
updateSearch(text) {
|
||||
this.txt_search_elem.value = text;
|
||||
updateInput(this.txt_search_elem);
|
||||
this.applyFilter();
|
||||
}
|
||||
|
||||
autoSetTreeWidth() {
|
||||
const row = this.container_elem.querySelector(".resize-handle-row");
|
||||
if (!isElementLogError(row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const left_col = row.firstElementChild;
|
||||
if (!isElementLogError(left_col)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the left column is hidden then we don't want to do anything.
|
||||
if (left_col.classList.contains("hidden")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pad = parseFloat(row.style.gridTemplateColumns.split(" ")[1]);
|
||||
const min_left_col_width = parseFloat(left_col.style.flexBasis.slice(0, -2));
|
||||
// We know that the tree list is the left column. That is the only one we want to resize.
|
||||
let max_width = this.tree_list.getMaxRowWidth();
|
||||
if (!isNumber(max_width)) {
|
||||
return;
|
||||
}
|
||||
// Add the resize handle's padding to the result and default to minLeftColWidth if necessary.
|
||||
max_width = Math.max(max_width + pad, min_left_col_width);
|
||||
|
||||
// Mimicks resizeHandle.js::setLeftColGridTemplate().
|
||||
row.style.gridTemplateColumns = `${max_width}px ${pad}px 1fr`;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function popup(contents) {
|
||||
|
|
@ -62,77 +347,6 @@ function closePopup() {
|
|||
|
||||
// ==== GENERAL EXTRA NETWORKS FUNCTIONS ====
|
||||
|
||||
function extraNetworksClusterizersEnable(tabname_full) {
|
||||
for (const [_tabname_full, tab_clusterizers] of Object.entries(clusterizers)) {
|
||||
for (const v of Object.values(tab_clusterizers)) {
|
||||
v.enable(_tabname_full === tabname_full);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function extraNetworksClusterizersLoadTab({
|
||||
tabname_full,
|
||||
selected = false,
|
||||
fetch_data = false,
|
||||
}) {
|
||||
if (!keyExistsLogError(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
extraNetworksClusterizersEnable(tabname_full);
|
||||
}
|
||||
|
||||
for (const v of Object.values(clusterizers[tabname_full])) {
|
||||
await v.load(fetch_data);
|
||||
await v.refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksRegisterPromptForTab(tabname, id) {
|
||||
var textarea = gradioApp().querySelector(`#${id} > label > textarea`);
|
||||
|
||||
if (!activePromptTextarea[tabname]) {
|
||||
activePromptTextarea[tabname] = textarea;
|
||||
}
|
||||
|
||||
textarea.addEventListener("focus", function() {
|
||||
activePromptTextarea[tabname] = textarea;
|
||||
});
|
||||
}
|
||||
|
||||
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-network-controls-div > div`).forEach((elem) => {
|
||||
let show = `${tabname_full}_controls` === elem.id;
|
||||
elem.classList.toggle("hidden", !show);
|
||||
});
|
||||
}
|
||||
|
||||
function extraNetworksRemoveFromPrompt(textarea, text, is_neg) {
|
||||
let match = text.match(is_neg ? re_extranet_neg : re_extranet);
|
||||
let replaced = false;
|
||||
|
|
@ -164,7 +378,7 @@ function extraNetworksRemoveFromPrompt(textarea, text, is_neg) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
res = textarea.value.replaceAll(new RegExp(`((?:${extraTextBeforeNet})?${text})`, "g"), "");
|
||||
res = textarea.value.replaceAll(new RegExp(`((?:${prefix})?${text})`, "g"), "");
|
||||
replaced = (res !== textarea.value);
|
||||
}
|
||||
|
||||
|
|
@ -290,162 +504,11 @@ function extraNetworksRefreshSingleCard(tabname, extra_networks_tabname, name) {
|
|||
|
||||
async function extraNetworksRefreshTab(tabname_full) {
|
||||
/** called from python when user clicks the extra networks refresh tab button */
|
||||
// Reapply controls since they don't change on refresh.
|
||||
const controls = gradioApp().getElementById(`${tabname_full}_controls`);
|
||||
let btn_dirs_view = controls.querySelector(".extra-network-control--dirs-view");
|
||||
let btn_tree_view = controls.querySelector(".extra-network-control--tree-view");
|
||||
|
||||
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
|
||||
let div_dirs = pane.querySelector(".extra-network-content--dirs-view");
|
||||
let div_tree = pane.querySelector(`.extra-network-content.resize-handle-col:has(> #${tabname_full}_tree_list_scroll_area)`);
|
||||
|
||||
// Remove "hidden" class if button is enabled, otherwise add it.
|
||||
div_dirs.classList.toggle("hidden", !("selected" in btn_dirs_view.dataset));
|
||||
div_tree.classList.toggle("hidden", !("selected" in btn_tree_view.dataset));
|
||||
|
||||
await waitForKeyInObject({k: tabname_full, obj: clusterizers});
|
||||
for (const _tabname_full of Object.keys(clusterizers)) {
|
||||
let selected = _tabname_full == tabname_full;
|
||||
await extraNetworksClusterizersLoadTab({
|
||||
tabname_full: _tabname_full,
|
||||
selected: selected,
|
||||
fetch_data: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksAutoSetTreeWidth(pane) {
|
||||
if (!isElementLogError(pane)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tabname_full = pane.dataset.tabnameFull;
|
||||
|
||||
// This event is only applied to the currently selected tab if has clusterize lists.
|
||||
if (!keyExists(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const row = pane.querySelector(".resize-handle-row");
|
||||
if (!isElementLogError(row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const left_col = row.firstElementChild;
|
||||
if (!isElementLogError(left_col)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the left column is hidden then we don't want to do anything.
|
||||
if (left_col.classList.contains("hidden")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pad = parseFloat(row.style.gridTemplateColumns.split(" ")[1]);
|
||||
const min_left_col_width = parseFloat(left_col.style.flexBasis.slice(0, -2));
|
||||
// We know that the tree list is the left column. That is the only one we want to resize.
|
||||
let max_width = clusterizers[tabname_full].tree_list.getMaxRowWidth();
|
||||
// Add the resize handle's padding to the result and default to minLeftColWidth if necessary.
|
||||
max_width = Math.max(max_width + pad, min_left_col_width);
|
||||
|
||||
// Mimicks resizeHandle.js::setLeftColGridTemplate().
|
||||
row.style.gridTemplateColumns = `${max_width}px ${pad}px 1fr`;
|
||||
}
|
||||
|
||||
function extraNetworksApplyFilter(tabname_full) {
|
||||
if (!keyExistsLogError(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
|
||||
if (!isElementLogError(pane)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const txt_search = gradioApp().querySelector(`#${tabname_full}_controls .extra-network-control--search-text`);
|
||||
if (!isElementLogError(txt_search)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only want to filter/sort the cards list.
|
||||
clusterizers[tabname_full].cards_list.setFilterStr(txt_search.value.toLowerCase());
|
||||
|
||||
// If the search input has changed since selecting a button to populate it
|
||||
// then we want to disable the button that previously populated the search input.
|
||||
// tree view buttons
|
||||
let btn = pane.querySelector(".tree-list-item[data-selected='']");
|
||||
if (isElement(btn) && btn.dataset.path !== txt_search.value && "selected" in btn.dataset) {
|
||||
clusterizers[tabname_full].tree_list.onRowSelected(btn.dataset.divId, btn, false);
|
||||
}
|
||||
// dirs view buttons
|
||||
btn = pane.querySelector(".extra-network-dirs-view-button[data-selected='']");
|
||||
if (isElement(btn) && btn.textContent.trim() !== txt_search.value) {
|
||||
delete btn.dataset.selected;
|
||||
}
|
||||
extra_networks_tabs[tabname_full].refresh();
|
||||
}
|
||||
|
||||
// ==== EVENT HANDLING ====
|
||||
|
||||
async function extraNetworksInitCardsData(tabname, extra_networks_tabname) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/init-cards-data",
|
||||
{
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async function extraNetworksInitTreeData(tabname, extra_networks_tabname) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/init-tree-data",
|
||||
{
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async function extraNetworksOnInitData(tabname, extra_networks_tabname, class_name) {
|
||||
if (class_name === "ExtraNetworksClusterizeTreeList") {
|
||||
return await extraNetworksInitTreeData(tabname, extra_networks_tabname);
|
||||
} else if (class_name === "ExtraNetworksClusterizeCardsList") {
|
||||
return await extraNetworksInitCardsData(tabname, extra_networks_tabname);
|
||||
}
|
||||
}
|
||||
|
||||
async function extraNetworksFetchCardsData(extra_networks_tabname, div_ids) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/fetch-cards-data",
|
||||
{
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
div_ids: div_ids,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async function extraNetworksFetchTreeData(extra_networks_tabname, div_ids) {
|
||||
const res = await requestGetPromise(
|
||||
"./sd_extra_networks/fetch-tree-data",
|
||||
{
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
div_ids: div_ids,
|
||||
},
|
||||
);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async function extraNetworksOnFetchData(class_name, extra_networks_tabname, div_ids) {
|
||||
if (class_name === "ExtraNetworksClusterizeTreeList") {
|
||||
return await extraNetworksFetchTreeData(extra_networks_tabname, div_ids);
|
||||
} else if (class_name === "ExtraNetworksClusterizeCardsList") {
|
||||
return await extraNetworksFetchCardsData(extra_networks_tabname, div_ids);
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksFetchMetadata(extra_networks_tabname, card_name) {
|
||||
const _showError = () => { extraNetworksShowMetadata("there was an error getting metadata"); };
|
||||
|
||||
|
|
@ -463,51 +526,48 @@ function extraNetworksFetchMetadata(extra_networks_tabname, card_name) {
|
|||
);
|
||||
}
|
||||
|
||||
function extraNetworksUnrelatedTabSelected(tabname) {
|
||||
function extraNetworksUnrelatedTabSelected() {
|
||||
/** called from python when user selects an unrelated tab (generate) */
|
||||
extraNetworksMovePromptToTab(tabname, '', false, false);
|
||||
extraNetworksShowControlsForPage(tabname, null);
|
||||
for (const [k, v] of Object.entries(extra_networks_tabs)) {
|
||||
v.unload();
|
||||
}
|
||||
}
|
||||
|
||||
async function extraNetworksTabSelected(
|
||||
tabname,
|
||||
id,
|
||||
showPrompt,
|
||||
showNegativePrompt,
|
||||
tabname_full,
|
||||
) {
|
||||
async function extraNetworksTabSelected(tabname_full, show_prompt, show_neg_prompt) {
|
||||
/** called from python when user selects an extra networks tab */
|
||||
extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePrompt);
|
||||
extraNetworksShowControlsForPage(tabname, tabname_full);
|
||||
|
||||
await waitForKeyInObject({k: tabname_full, obj: clusterizers});
|
||||
await extraNetworksClusterizersLoadTab({
|
||||
tabname_full: tabname_full,
|
||||
selected: true,
|
||||
fetch_data: false,
|
||||
});
|
||||
for (const [k, v] of Object.entries(extra_networks_tabs)) {
|
||||
if (k === tabname_full) {
|
||||
v.load(show_prompt=show_prompt, show_neg_prompt=show_neg_prompt);
|
||||
} else {
|
||||
v.unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksBtnDirsViewItemOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for buttons in the directory view. */
|
||||
const txt_search = gradioApp().querySelector(`#${tabname_full}_controls .extra-network-control--search-text`);
|
||||
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
const container_elem = tab.container_elem;
|
||||
const txt_search_elem = tab.txt_search_elem;
|
||||
|
||||
const _deselect_all_buttons = () => {
|
||||
gradioApp().querySelectorAll(".extra-network-dirs-view-button").forEach((elem) => {
|
||||
container_elem.querySelectorAll(
|
||||
".extra-network-dirs-view-button[data-selected='']"
|
||||
).forEach(elem => {
|
||||
delete elem.dataset.selected;
|
||||
});
|
||||
};
|
||||
|
||||
const _select_button = (elem) => {
|
||||
_deselect_all_buttons();
|
||||
// Update search input with select button's path.
|
||||
// update search input with selected button's path.
|
||||
elem.dataset.selected = "";
|
||||
txt_search.value = elem.textContent.trim();
|
||||
txt_search_elem.value = elem.textContent.trim();
|
||||
};
|
||||
|
||||
const _deselect_button = (elem) => {
|
||||
delete elem.dataset.selected;
|
||||
txt_search.value = "";
|
||||
txt_search_elem.value = "";
|
||||
};
|
||||
|
||||
if ("selected" in event.target.dataset) {
|
||||
|
|
@ -516,16 +576,15 @@ function extraNetworksBtnDirsViewItemOnClick(event, tabname_full) {
|
|||
_select_button(event.target);
|
||||
}
|
||||
|
||||
updateInput(txt_search);
|
||||
extraNetworksApplyFilter(tabname_full);
|
||||
updateInput(txt_search_elem);
|
||||
tab.applyFilter();
|
||||
}
|
||||
|
||||
function extraNetworksControlSearchClearOnClick(event, tabname_full) {
|
||||
/** Dispatches custom event when the `clear` button in a search input is clicked. */
|
||||
let clear_btn = event.target.closest(".extra-network-control--search-clear");
|
||||
let txt_search = clear_btn.previousElementSibling;
|
||||
txt_search.value = "";
|
||||
txt_search.dispatchEvent(
|
||||
const txt_search_elem = extra_networks_tabs[tabname_full].txt_search_elem;
|
||||
txt_search_elem.value = "";
|
||||
txt_search_elem.dispatchEvent(
|
||||
new CustomEvent(
|
||||
"extra-network-control--search-clear",
|
||||
{bubbles: true, detail: {tabname_full: tabname_full}},
|
||||
|
|
@ -535,18 +594,16 @@ function extraNetworksControlSearchClearOnClick(event, tabname_full) {
|
|||
|
||||
function extraNetworksControlSortModeOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for Sort Mode buttons. */
|
||||
event.currentTarget.parentElement.querySelectorAll('.extra-network-control--sort-mode').forEach(elem => {
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
tab.controls_elem.querySelectorAll(".extra-network-control--sort-mode").forEach(elem => {
|
||||
delete elem.dataset.selected;
|
||||
});
|
||||
|
||||
event.currentTarget.dataset.selected = "";
|
||||
|
||||
if (!keyExists(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sort_mode_str = event.currentTarget.dataset.sortMode.toLowerCase();
|
||||
clusterizers[tabname_full].cards_list.setSortMode(sort_mode_str);
|
||||
|
||||
tab.cards_list.setSortMode(sort_mode_str);
|
||||
}
|
||||
|
||||
function extraNetworksControlSortDirOnClick(event, tabname_full) {
|
||||
|
|
@ -555,6 +612,8 @@ function extraNetworksControlSortDirOnClick(event, tabname_full) {
|
|||
* Modifies the data attributes of the Sort Direction button to cycle between
|
||||
* ascending and descending sort directions.
|
||||
*/
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
|
||||
const curr_sort_dir_str = event.currentTarget.dataset.sortDir.toLowerCase();
|
||||
if (!["ascending", "descending"].includes(curr_sort_dir_str)) {
|
||||
console.error(`Invalid sort_dir_str: ${curr_sort_dir_str}`);
|
||||
|
|
@ -565,11 +624,7 @@ function extraNetworksControlSortDirOnClick(event, tabname_full) {
|
|||
event.currentTarget.dataset.sortDir = sort_dir_str;
|
||||
event.currentTarget.setAttribute("title", `Sort ${sort_dir_str}`);
|
||||
|
||||
if (!keyExists(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clusterizers[tabname_full].cards_list.setSortDir(sort_dir_str);
|
||||
tab.cards_list.setSortDir(sort_dir_str);
|
||||
}
|
||||
|
||||
function extraNetworksControlTreeViewOnClick(event, tabname_full) {
|
||||
|
|
@ -586,11 +641,9 @@ function extraNetworksControlTreeViewOnClick(event, tabname_full) {
|
|||
show = true;
|
||||
}
|
||||
|
||||
if (!keyExists(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
clusterizers[tabname_full].tree_list.scroll_elem.parentElement.classList.toggle("hidden", !show);
|
||||
clusterizers[tabname_full].tree_list.enable(show);
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
tab.tree_list.scroll_elem.parentElement.classList.toggle("hidden", !show);
|
||||
tab.tree_list.enable(show);
|
||||
}
|
||||
|
||||
function extraNetworksControlDirsViewOnClick(event, tabname_full) {
|
||||
|
|
@ -605,8 +658,10 @@ function extraNetworksControlDirsViewOnClick(event, tabname_full) {
|
|||
delete event.currentTarget.dataset.selected;
|
||||
}
|
||||
|
||||
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
|
||||
pane.querySelector(".extra-network-content--dirs-view").classList.toggle("hidden", !show);
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
tab.container_elem.querySelector(
|
||||
".extra-network-content--dirs-view"
|
||||
).classList.toggle("hidden", !show);
|
||||
}
|
||||
|
||||
function extraNetworksControlRefreshOnClick(event, tabname_full) {
|
||||
|
|
@ -620,29 +675,27 @@ function extraNetworksControlRefreshOnClick(event, tabname_full) {
|
|||
// reset states
|
||||
initialUiOptionsLoaded.state = false;
|
||||
|
||||
// We want to reset all clusterizers on refresh click so that the viewing area
|
||||
// We want to reset all tabs lists on refresh click so that the viewing area
|
||||
// shows that it is loading new data.
|
||||
for (const _tabname_full of Object.keys(clusterizers)) {
|
||||
for (const v of Object.values(clusterizers[_tabname_full])) {
|
||||
v.clear();
|
||||
}
|
||||
for (tab of Object.values(extra_networks_tabs)) {
|
||||
tab.tree_list.destroy();
|
||||
tab.cards_list.destroy();
|
||||
}
|
||||
|
||||
// Fire an event for this button click.
|
||||
gradioApp().getElementById(`${tabname_full}_extra_refresh_internal`).dispatchEvent(new Event("click"));
|
||||
}
|
||||
|
||||
function extraNetworksCardOnClick(event, tabname) {
|
||||
function extraNetworksCardOnClick(event, tabname_full) {
|
||||
const elem = event.currentTarget;
|
||||
const prompt_elem = gradioApp().querySelector(`#${tabname}_prompt > label > textarea`);
|
||||
const neg_prompt_elem = gradioApp().querySelector(`#${tabname}_neg_prompt > label > textarea`);
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
if ("negPrompt" in elem.dataset) {
|
||||
extraNetworksUpdatePrompt(prompt_elem, elem.dataset.prompt);
|
||||
extraNetworksUpdatePrompt(neg_prompt_elem, elem.dataset.negPrompt);
|
||||
extraNetworksUpdatePrompt(tab.txt_prompt_elem, elem.dataset.prompt);
|
||||
extraNetworksUpdatePrompt(tab.txt_neg_prompt_elem, elem.dataset.negPrompt);
|
||||
} else if ("allowNeg" in elem.dataset) {
|
||||
extraNetworksUpdatePrompt(activePromptTextarea[tabname], elem.dataset.prompt);
|
||||
extraNetworksUpdatePrompt(tab.active_prompt_elem, elem.dataset.prompt);
|
||||
} else {
|
||||
extraNetworksUpdatePrompt(prompt_elem, elem.dataset.prompt);
|
||||
extraNetworksUpdatePrompt(tab.txt_prompt_elem, elem.dataset.prompt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -651,7 +704,25 @@ function extraNetworksTreeFileOnClick(event, btn, tabname_full) {
|
|||
}
|
||||
|
||||
function extraNetworksTreeDirectoryOnClick(event, btn, tabname_full) {
|
||||
return;
|
||||
const true_targ = event.target;
|
||||
const div_id = btn.dataset.divId;
|
||||
|
||||
const tab = extra_networks_tabs[tabname_full];
|
||||
|
||||
if (true_targ.matches(".tree-list-item-action--leading, .tree-list-item-action-chevron")) {
|
||||
// If user clicks on the chevron, then we do not select the folder.
|
||||
const prev_selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
|
||||
tab.tree_list.onRowExpandClick(div_id, btn);
|
||||
const selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
|
||||
if (isElement(prev_selected_elem) && !isElement(selected_elem)) {
|
||||
// is a selected element was removed, clear filter.
|
||||
tab.updateSearch("");
|
||||
}
|
||||
} else {
|
||||
// user clicked anywhere else on the row
|
||||
tab.tree_list.onRowSelected(div_id, btn);
|
||||
tab.updateSearch("selected" in btn.dataset ? btn.dataset.path : "");
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksTreeOnClick(event, tabname_full) {
|
||||
|
|
@ -712,18 +783,19 @@ function extraNetworksSetupEventDelegators() {
|
|||
window.addEventListener("resizeHandleDblClick", event => {
|
||||
// See resizeHandle.js::onDoubleClick() for event detail.
|
||||
event.stopPropagation();
|
||||
extraNetworksAutoSetTreeWidth(event.target.closest(".extra-network-pane"));
|
||||
const pane = event.target.closest(".extra-network-pane");
|
||||
extra_networks_tabs[pane.dataset.tabnameFull].autoSetTreeWidth();
|
||||
});
|
||||
|
||||
// Update search filter whenever the search input's clear button is pressed.
|
||||
window.addEventListener("extra-network-control--search-clear", event => {
|
||||
event.stopPropagation();
|
||||
extraNetworksApplyFilter(event.detail.tabname_full);
|
||||
extra_networks_tabs[event.detail.tabname_full].applyFilter();
|
||||
});
|
||||
|
||||
// Debounce search text input. This way we only search after user is done typing.
|
||||
const search_input_debounce = debounce((tabname_full) => {
|
||||
extraNetworksApplyFilter(tabname_full);
|
||||
const search_input_debounce = debounce(tabname_full => {
|
||||
extra_networks_tabs[tabname_full].applyFilter();
|
||||
}, SEARCH_INPUT_DEBOUNCE_TIME_MS);
|
||||
|
||||
window.addEventListener("keyup", event => {
|
||||
|
|
@ -744,72 +816,35 @@ function extraNetworksSetupEventDelegators() {
|
|||
});
|
||||
}
|
||||
|
||||
async function extraNetworksSetupTabContent(tabname, pane, controls_div) {
|
||||
const tabname_full = pane.id;
|
||||
const extra_networks_tabname = tabname_full.replace(`${tabname}_`, "");
|
||||
|
||||
const controls = await waitForElement(`#${tabname_full}_pane .extra-network-controls`);
|
||||
await waitForElement(`#${tabname_full}_pane .extra-network-content--dirs-view`);
|
||||
|
||||
controls.id = `${tabname_full}_controls`;
|
||||
controls_div.insertBefore(controls, null);
|
||||
|
||||
clusterizers[tabname_full] = {
|
||||
tree_list: new ExtraNetworksClusterizeTreeList({
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
scrollId: `${tabname_full}_tree_list_scroll_area`,
|
||||
contentId: `${tabname_full}_tree_list_content_area`,
|
||||
tag: "div",
|
||||
callbacks: {
|
||||
initData: extraNetworksOnInitData,
|
||||
fetchData: extraNetworksOnFetchData,
|
||||
},
|
||||
}),
|
||||
cards_list: new ExtraNetworksClusterizeCardsList({
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
scrollId: `${tabname_full}_cards_list_scroll_area`,
|
||||
contentId: `${tabname_full}_cards_list_content_area`,
|
||||
tag: "div",
|
||||
callbacks: {
|
||||
initData: extraNetworksOnInitData,
|
||||
fetchData: extraNetworksOnFetchData,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
await clusterizers[tabname_full].tree_list.setup();
|
||||
await clusterizers[tabname_full].cards_list.setup();
|
||||
|
||||
if (pane.style.display !== "none") {
|
||||
extraNetworksShowControlsForPage(tabname, tabname_full);
|
||||
}
|
||||
}
|
||||
|
||||
async function extraNetworksSetupTab(tabname) {
|
||||
let controls_div;
|
||||
|
||||
const this_tab = await waitForElement(`#${tabname}_extra_tabs`);
|
||||
const tab_nav = await waitForElement(`#${tabname}_extra_tabs > div.tab-nav`);
|
||||
|
||||
controls_div = document.createElement("div");
|
||||
const controls_div = document.createElement("div");
|
||||
|
||||
controls_div.id = `${tabname}_extra_network_controls_div`;
|
||||
controls_div.classList.add("extra-network-controls-div");
|
||||
tab_nav.appendChild(controls_div);
|
||||
tab_nav.insertBefore(controls_div, null);
|
||||
|
||||
const panes = this_tab.querySelectorAll(`:scope > .tabitem[id^="${tabname}_"]`);
|
||||
for (const pane of panes) {
|
||||
await extraNetworksSetupTabContent(tabname, pane, controls_div);
|
||||
const tabname_full = pane.id;
|
||||
const extra_networks_tabname = tabname_full.replace(`${tabname}_`, "");
|
||||
extra_networks_tabs[tabname_full] = new ExtraNetworksTab({
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
});
|
||||
await extra_networks_tabs[tabname_full].setup(pane, controls_div);
|
||||
}
|
||||
extraNetworksRegisterPromptForTab(tabname, `${tabname}_prompt`);
|
||||
extraNetworksRegisterPromptForTab(tabname, `${tabname}_neg_prompt`);
|
||||
}
|
||||
|
||||
async function extraNetworksSetup() {
|
||||
await waitForBool(initialUiOptionsLoaded);
|
||||
|
||||
extraNetworksSetupTab('txt2img');
|
||||
extraNetworksSetupTab('img2img');
|
||||
await Promise.all([
|
||||
extraNetworksSetupTab('txt2img'),
|
||||
extraNetworksSetupTab('img2img'),
|
||||
]);
|
||||
extraNetworksSetupEventDelegators();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue