mirror of
https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
synced 2026-02-01 21:32:01 -08:00
need to fix bug with row width.
This commit is contained in:
parent
ec80d57e8b
commit
fc7a8a41e5
8 changed files with 557 additions and 395 deletions
|
|
@ -17,12 +17,6 @@ class Clusterize {
|
|||
content_elem = null;
|
||||
scroll_id = null;
|
||||
content_id = null;
|
||||
default_sort_mode_str = "";
|
||||
default_sort_dir_str = "ascending";
|
||||
default_filter_str = "";
|
||||
sort_mode_str = this.default_sort_mode_str;
|
||||
sort_dir_str = this.default_sort_dir_str;
|
||||
filter_str = this.default_filter_str;
|
||||
options = {
|
||||
rows_in_block: 50,
|
||||
cols_in_block: 1,
|
||||
|
|
@ -32,13 +26,9 @@ class Clusterize {
|
|||
no_data_class: "clusterize-no-data",
|
||||
no_data_text: "No data",
|
||||
keep_parity: true,
|
||||
callbacks: {
|
||||
initData: this.initDataDefault,
|
||||
fetchData: this.fetchDataDefault,
|
||||
sortData: this.sortDataDefault,
|
||||
filterData: this.filterDataDefault,
|
||||
},
|
||||
callbacks: {},
|
||||
};
|
||||
setup_has_run = false;
|
||||
#is_mac = null;
|
||||
#ie = null;
|
||||
#max_items = null;
|
||||
|
|
@ -60,17 +50,17 @@ class Clusterize {
|
|||
}
|
||||
}
|
||||
|
||||
if (!isNullOrUndefined(this.options.callbacks.initData)) {
|
||||
this.options.callbacks.initData = this.initDataDefault;
|
||||
if (isNullOrUndefined(this.options.callbacks.initData)) {
|
||||
this.options.callbacks.initData = this.initDataDefaultCallback;
|
||||
}
|
||||
if (!isNullOrUndefined(this.options.callbacks.fetchData)) {
|
||||
this.options.callbacks.fetchData = this.fetchDataDefault;
|
||||
if (isNullOrUndefined(this.options.callbacks.fetchData)) {
|
||||
this.options.callbacks.fetchData = this.fetchDataDefaultCallback;
|
||||
}
|
||||
if (!isNullOrUndefined(this.options.callbacks.sortData)) {
|
||||
this.options.callbacks.sortData = this.sortDataDefault;
|
||||
if (isNullOrUndefined(this.options.callbacks.sortData)) {
|
||||
this.options.callbacks.sortData = this.sortDataDefaultCallback;
|
||||
}
|
||||
if (!isNullOrUndefined(this.options.callbacks.filterData)) {
|
||||
this.options.callbacks.filterData = this.filterDataDefault;
|
||||
if (isNullOrUndefined(this.options.callbacks.filterData)) {
|
||||
this.options.callbacks.filterData = this.filterDataDefaultCallback;
|
||||
}
|
||||
|
||||
// detect ie9 and lower
|
||||
|
|
@ -105,15 +95,25 @@ class Clusterize {
|
|||
|
||||
// ==== PUBLIC FUNCTIONS ====
|
||||
async setup() {
|
||||
if (this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.#insertToDOM();
|
||||
this.scroll_elem.scrollTop = this.#scroll_top;
|
||||
|
||||
this.#setupEvent("scroll", this.scroll_elem, this.#onScroll);
|
||||
this.#setupElementObservers();
|
||||
this.#setupResizeObservers();
|
||||
|
||||
this.setup_has_run = true;
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (!this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#html(this.#generateEmptyRow().join(""));
|
||||
}
|
||||
|
||||
|
|
@ -122,15 +122,25 @@ class Clusterize {
|
|||
this.#teardownElementObservers();
|
||||
this.#teardownResizeObservers();
|
||||
this.clear();
|
||||
|
||||
this.setup_has_run = false;
|
||||
}
|
||||
|
||||
async refresh(force) {
|
||||
if (!this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.#getRowsHeight() || force) {
|
||||
await this.update()
|
||||
}
|
||||
}
|
||||
|
||||
async update() {
|
||||
if (!this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#scroll_top = this.scroll_elem.scrollTop;
|
||||
// fixes #39
|
||||
if (this.#max_rows * this.options.item_height < this.#scroll_top) {
|
||||
|
|
@ -151,6 +161,11 @@ class Clusterize {
|
|||
}
|
||||
|
||||
async setMaxItems(max_items) {
|
||||
if (!this.setup_has_run) {
|
||||
this.#max_items = max_items;
|
||||
return;
|
||||
}
|
||||
|
||||
if (max_items === this.#max_items) {
|
||||
// No change. do nothing.
|
||||
return;
|
||||
|
|
@ -161,60 +176,57 @@ class Clusterize {
|
|||
await this.refresh(true);
|
||||
|
||||
// Apply sort to the updated data.
|
||||
await this.sortData(this.sort_mode_str, this.sort_dir_str);
|
||||
}
|
||||
|
||||
async filterData(filter_str) {
|
||||
if (this.filter_str === filter_str) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filter_str = isNullOrUndefined(filter_str) ? this.default_filter_str : filter_str;
|
||||
|
||||
// Filter is applied to entire dataset.
|
||||
const max_items = await this.options.callbacks.filterData(this.filter_str);
|
||||
// If the number of items changed after filter, we need to update the cluster.
|
||||
if (max_items !== this.#max_items) {
|
||||
this.#max_items = max_items;
|
||||
this.refresh(true);
|
||||
}
|
||||
// Apply sort to the new filtered data.
|
||||
await this.sortData(this.sort_mode_str, this.sort_dir_str);
|
||||
}
|
||||
|
||||
async sortData(sort_mode_str, sort_dir_str) {
|
||||
if (this.sort_mode_str === sort_mode_str && this.sort_dir_str === sort_dir_str) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sort_mode_str = isNullOrUndefined(sort_mode_str) ? this.default_sort_mode_str : sort_mode_str;
|
||||
this.sort_dir_str = isNullOrUndefined(sort_dir_str) ? this.default_sort_dir_str : sort_dir_str;
|
||||
|
||||
// Sort is applied to the filtered data.
|
||||
await this.options.callbacks.sortData(this.sort_mode_str, this.sort_dir_str === "descending");
|
||||
await this.#insertToDOM();
|
||||
await this.sortData();
|
||||
}
|
||||
|
||||
// ==== PRIVATE FUNCTIONS ====
|
||||
initDataDefault() {
|
||||
initDataDefaultCallback() {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
fetchDataDefault() {
|
||||
async initData() {
|
||||
return await this.options.callbacks.initData.call(this);
|
||||
}
|
||||
|
||||
fetchDataDefaultCallback() {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
sortDataDefault() {
|
||||
async fetchData(idx_start, idx_end) {
|
||||
return await this.options.callbacks.fetchData.call(this, idx_start, idx_end);
|
||||
}
|
||||
|
||||
sortDataDefaultCallback() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
filterDataDefault() {
|
||||
async sortData() {
|
||||
if (!this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort is applied to the filtered data.
|
||||
await this.options.callbacks.sortData.call(this);
|
||||
await this.#insertToDOM();
|
||||
}
|
||||
|
||||
filterDataDefaultCallback() {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
async filterData() {
|
||||
if (!this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter is applied to entire dataset.
|
||||
const max_items = await this.options.callbacks.filterData.call(this);
|
||||
await this.setMaxItems(max_items);
|
||||
}
|
||||
|
||||
#exploreEnvironment(rows, cache) {
|
||||
this.options.content_tag = this.content_elem.tagName.toLowerCase();
|
||||
if (!rows.length) {
|
||||
if (isNullOrUndefined(rows) || !rows.length) {
|
||||
return;
|
||||
}
|
||||
if (this.#ie && this.#ie <= 9 && !this.options.tag) {
|
||||
|
|
@ -241,7 +253,11 @@ class Clusterize {
|
|||
return;
|
||||
}
|
||||
|
||||
const nodes = this.content_elem.querySelectorAll(":not(.clusterize-row)");
|
||||
const rows = this.content_elem.children;
|
||||
if (!rows.length) {
|
||||
return;
|
||||
}
|
||||
const nodes = rows[0].children;
|
||||
if (!nodes.length) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -269,6 +285,7 @@ class Clusterize {
|
|||
// Update rows in block to match the number of elements that can fit in the scroll element view.
|
||||
this.options.rows_in_block = calcRowsPerCol(this.scroll_elem, node);
|
||||
this.options.cols_in_block = calcColsPerRow(this.content_elem, node);
|
||||
console.log("HERE:", this.scroll_elem, this.content_elem, node, this.options.rows_in_block, this.options.cols_in_block);
|
||||
|
||||
this.options.block_height = this.options.item_height * this.options.rows_in_block;
|
||||
this.options.block_width = this.options.item_width * this.options.cols_in_block;
|
||||
|
|
@ -323,18 +340,19 @@ class Clusterize {
|
|||
|
||||
const idx_start = Math.max(0, rows_start * this.options.cols_in_block);
|
||||
const idx_end = rows_end * this.options.cols_in_block;
|
||||
const this_cluster_rows = await this.options.callbacks.fetchData(idx_start, idx_end);
|
||||
const this_cluster_rows = await this.fetchData(idx_start, idx_end);
|
||||
return {
|
||||
top_offset: top_offset,
|
||||
bottom_offset: bottom_offset,
|
||||
rows_above: rows_above,
|
||||
rows: this_cluster_rows,
|
||||
rows: Array.isArray(this_cluster_rows) ? this_cluster_rows : [],
|
||||
};
|
||||
}
|
||||
|
||||
async #insertToDOM() {
|
||||
if (!this.options.cluster_height || !this.options.cluster_width) {
|
||||
const rows = await this.options.callbacks.fetchData(0, 1);
|
||||
console.log("HERE");
|
||||
const rows = await this.fetchData(0, 1);
|
||||
this.#exploreEnvironment(rows, this.#cache);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const initialUiOptionsLoaded = {state: false};
|
|||
|
||||
//
|
||||
|
||||
const popup = contents => {
|
||||
function popup(contents) {
|
||||
if (!globalPopup) {
|
||||
globalPopup = document.createElement('div');
|
||||
globalPopup.classList.add('global-popup');
|
||||
|
|
@ -44,45 +44,52 @@ const popup = contents => {
|
|||
globalPopupInner.appendChild(contents);
|
||||
|
||||
globalPopup.style.display = "flex";
|
||||
};
|
||||
}
|
||||
|
||||
const popupId = id => {
|
||||
function popupId(id) {
|
||||
if (!storedPopupIds[id]) {
|
||||
storedPopupIds[id] = gradioApp().getElementById(id);
|
||||
}
|
||||
|
||||
popup(storedPopupIds[id]);
|
||||
};
|
||||
}
|
||||
|
||||
const closePopup = () => {
|
||||
function closePopup() {
|
||||
if (!globalPopup) return;
|
||||
globalPopup.style.display = "none";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ==== GENERAL EXTRA NETWORKS FUNCTIONS ====
|
||||
|
||||
const extraNetworksClusterizersLoadTab = async (
|
||||
{
|
||||
tabname_full = "",
|
||||
selected = false,
|
||||
fetch_data = false,
|
||||
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;
|
||||
}
|
||||
|
||||
for (const v of Object.values(clusterizers[tabname_full])) {
|
||||
if (fetch_data) {
|
||||
await v.initDataDefault();
|
||||
} else {
|
||||
await v.refresh(true);
|
||||
}
|
||||
if (selected) {
|
||||
extraNetworksClusterizersEnable(tabname_full);
|
||||
}
|
||||
};
|
||||
|
||||
const extraNetworksRegisterPromptForTab = (tabname, id) => {
|
||||
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]) {
|
||||
|
|
@ -92,9 +99,9 @@ const extraNetworksRegisterPromptForTab = (tabname, id) => {
|
|||
textarea.addEventListener("focus", function() {
|
||||
activePromptTextarea[tabname] = textarea;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksMovePromptToTab = (tabname, id, showPrompt, showNegativePrompt) => {
|
||||
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`);
|
||||
|
|
@ -117,16 +124,16 @@ const extraNetworksMovePromptToTab = (tabname, id, showPrompt, showNegativePromp
|
|||
if (elem) {
|
||||
elem.classList.toggle('extra-page-prompts-active', showNegativePrompt || showPrompt);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksShowControlsForPage = (tabname, tabname_full) => {
|
||||
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);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksRemoveFromPrompt = (textarea, text, is_neg) => {
|
||||
function extraNetworksRemoveFromPrompt(textarea, text, is_neg) {
|
||||
let match = text.match(is_neg ? re_extranet_neg : re_extranet);
|
||||
let replaced = false;
|
||||
let res;
|
||||
|
|
@ -167,17 +174,17 @@ const extraNetworksRemoveFromPrompt = (textarea, text, is_neg) => {
|
|||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksUpdatePrompt = (textarea, text, is_neg) => {
|
||||
function extraNetworksUpdatePrompt(textarea, text, is_neg) {
|
||||
if (!extraNetworksRemoveFromPrompt(textarea, text, is_neg)) {
|
||||
textarea.value = textarea.value + opts.extra_networks_add_text_separator + text;
|
||||
}
|
||||
|
||||
updateInput(textarea);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksSaveCardPreview = (event, tabname, filename) => {
|
||||
function extraNetworksSaveCardPreview(event, tabname, filename) {
|
||||
const textarea = gradioApp().querySelector(`#${tabname}_preview_filename > label > textarea`);
|
||||
const button = gradioApp().getElementById(`${tabname}_save_preview`);
|
||||
|
||||
|
|
@ -188,9 +195,9 @@ const extraNetworksSaveCardPreview = (event, tabname, filename) => {
|
|||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksFlattenMetadata = obj => {
|
||||
function extraNetworksFlattenMetadata(obj) {
|
||||
const result = {};
|
||||
|
||||
// Convert any stringified JSON objects to actual objects
|
||||
|
|
@ -239,9 +246,9 @@ const extraNetworksFlattenMetadata = obj => {
|
|||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksShowMetadata = text => {
|
||||
function extraNetworksShowMetadata(text) {
|
||||
try {
|
||||
let parsed = JSON.parse(text);
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
|
|
@ -260,9 +267,9 @@ const extraNetworksShowMetadata = text => {
|
|||
|
||||
popup(elem);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksRefreshSingleCard = (tabname, extra_networks_tabname, name) => {
|
||||
function extraNetworksRefreshSingleCard(tabname, extra_networks_tabname, name) {
|
||||
requestGet(
|
||||
"./sd_extra_networks/get-single-card",
|
||||
{tabname: tabname, extra_networks_tabname: extra_networks_tabname, name: name},
|
||||
|
|
@ -279,9 +286,9 @@ const extraNetworksRefreshSingleCard = (tabname, extra_networks_tabname, name) =
|
|||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksRefreshTab = async tabname_full => {
|
||||
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`);
|
||||
|
|
@ -305,9 +312,9 @@ const extraNetworksRefreshTab = async tabname_full => {
|
|||
fetch_data: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksAutoSetTreeWidth = pane => {
|
||||
function extraNetworksAutoSetTreeWidth(pane) {
|
||||
if (!isElementLogError(pane)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -343,14 +350,14 @@ const extraNetworksAutoSetTreeWidth = pane => {
|
|||
|
||||
// Mimicks resizeHandle.js::setLeftColGridTemplate().
|
||||
row.style.gridTemplateColumns = `${max_width}px ${pad}px 1fr`;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksApplyFilter = tabname_full => {
|
||||
function extraNetworksApplyFilter(tabname_full) {
|
||||
if (!keyExistsLogError(clusterizers, tabname_full)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pane = gradioApp.getElementById(`${tabname_full}_pane`);
|
||||
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
|
||||
if (!isElementLogError(pane)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -361,7 +368,7 @@ const extraNetworksApplyFilter = tabname_full => {
|
|||
}
|
||||
|
||||
// We only want to filter/sort the cards list.
|
||||
clusterizers[tabname_full].cards_list.filterData(txt_search.value.toLowerCase());
|
||||
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.
|
||||
|
|
@ -375,70 +382,72 @@ const extraNetworksApplyFilter = tabname_full => {
|
|||
if (isElement(btn) && btn.textContent.trim() !== txt_search.value) {
|
||||
delete btn.dataset.selected;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ==== EVENT HANDLING ====
|
||||
|
||||
const extraNetworksInitCardsData = async () => {
|
||||
return await requestGetPromise(
|
||||
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);
|
||||
}
|
||||
|
||||
const extraNetworksInitTreeData = async () => {
|
||||
return await requestGetPromise(
|
||||
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);
|
||||
}
|
||||
|
||||
const extraNetworksOnInitData = async class_name => {
|
||||
async function extraNetworksOnInitData(tabname, extra_networks_tabname, class_name) {
|
||||
if (class_name === "ExtraNetworksClusterizeTreeList") {
|
||||
return await extraNetworksInitCardsData();
|
||||
return await extraNetworksInitTreeData(tabname, extra_networks_tabname);
|
||||
} else if (class_name === "ExtraNetworksClusterizeCardsList") {
|
||||
return await extraNetworksInitTreeData();
|
||||
return await extraNetworksInitCardsData(tabname, extra_networks_tabname);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksFetchCardsData = async (extra_networks_tabname, div_ids) => {
|
||||
return await requestGetPromise(
|
||||
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);
|
||||
}
|
||||
|
||||
const extraNetworksFetchTreeData = async (extra_networks_tabname, div_ids) => {
|
||||
return await requestGetPromise(
|
||||
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);
|
||||
}
|
||||
|
||||
const extraNetworksOnFetchData = async (class_name, extra_networks_tabname, div_ids) => {
|
||||
async function extraNetworksOnFetchData(class_name, extra_networks_tabname, div_ids) {
|
||||
if (class_name === "ExtraNetworksClusterizeTreeList") {
|
||||
return await extraNetworksFetchCardsData(extra_networks_tabname, div_ids);
|
||||
} else if (class_name === "ExtraNetworksClusterizeCardsList") {
|
||||
return await extraNetworksFetchTreeData(extra_networks_tabname, div_ids);
|
||||
} else if (class_name === "ExtraNetworksClusterizeCardsList") {
|
||||
return await extraNetworksFetchCardsData(extra_networks_tabname, div_ids);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksFetchMetadata = (extra_networks_tabname, card_name) => {
|
||||
const _showError = () => {
|
||||
extraNetworksShowMetadata("there was an error getting metadata");
|
||||
};
|
||||
function extraNetworksFetchMetadata(extra_networks_tabname, card_name) {
|
||||
const _showError = () => { extraNetworksShowMetadata("there was an error getting metadata"); };
|
||||
|
||||
requestGet(
|
||||
"./sd_extra_networks/metadata",
|
||||
|
|
@ -452,40 +461,51 @@ const extraNetworksFetchMetadata = (extra_networks_tabname, card_name) => {
|
|||
},
|
||||
_showError,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksUnrelatedTabSelected = tabname => {
|
||||
function extraNetworksUnrelatedTabSelected(tabname) {
|
||||
/** called from python when user selects an unrelated tab (generate) */
|
||||
extraNetworksMovePromptToTab(tabname, '', false, false);
|
||||
extraNetworksShowControlsForPage(tabname, null);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksTabSelected = async (tabname, id, showPrompt, showNegativePrompt, tabname_full) => {
|
||||
async 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);
|
||||
|
||||
await waitForKeyInObject({k: tabname_full, obj: clusterizers});
|
||||
await extraNetworksClusterizersLoadTab(tabname_full);
|
||||
};
|
||||
await extraNetworksClusterizersLoadTab({
|
||||
tabname_full: tabname_full,
|
||||
selected: true,
|
||||
fetch_data: false,
|
||||
});
|
||||
}
|
||||
|
||||
const extraNetworksBtnDirsViewItemOnClick = (event, tabname_full) => {
|
||||
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 _deselect_all_buttons = () => {
|
||||
gradioApp().querySelectorAll(".extra-network-dirs-view-button").forEach((elem) => {
|
||||
delete elem.dataset.selected;
|
||||
});
|
||||
};
|
||||
|
||||
const _select_button = elem => {
|
||||
const _select_button = (elem) => {
|
||||
_deselect_all_buttons();
|
||||
// Update search input with select button's path.
|
||||
elem.dataset.selected = "";
|
||||
txt_search.value = elem.textContent.trim();
|
||||
};
|
||||
|
||||
const _deselect_button = elem => {
|
||||
const _deselect_button = (elem) => {
|
||||
delete elem.dataset.selected;
|
||||
txt_search.value = "";
|
||||
};
|
||||
|
|
@ -498,9 +518,9 @@ const extraNetworksBtnDirsViewItemOnClick = (event, tabname_full) => {
|
|||
|
||||
updateInput(txt_search);
|
||||
extraNetworksApplyFilter(tabname_full);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksControlSearchClearOnClick = (event, tabname_full) => {
|
||||
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;
|
||||
|
|
@ -511,9 +531,9 @@ const extraNetworksControlSearchClearOnClick = (event, tabname_full) => {
|
|||
{bubbles: true, detail: {tabname_full: tabname_full}},
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksControlSortModeOnClick = (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 => {
|
||||
delete elem.dataset.selected;
|
||||
|
|
@ -526,11 +546,10 @@ const extraNetworksControlSortModeOnClick = (event, tabname_full) => {
|
|||
}
|
||||
|
||||
const sort_mode_str = event.currentTarget.dataset.sortMode.toLowerCase();
|
||||
clusterizers[tabname_full].cards_list.sort_mode_str = sort_mode_str;
|
||||
extraNetworksApplyFilter(tabname_full);
|
||||
};
|
||||
clusterizers[tabname_full].cards_list.setSortMode(sort_mode_str);
|
||||
}
|
||||
|
||||
const extraNetworksControlSortDirOnClick = (event, tabname_full) => {
|
||||
function extraNetworksControlSortDirOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for the Sort Direction button.
|
||||
*
|
||||
* Modifies the data attributes of the Sort Direction button to cycle between
|
||||
|
|
@ -550,11 +569,10 @@ const extraNetworksControlSortDirOnClick = (event, tabname_full) => {
|
|||
return;
|
||||
}
|
||||
|
||||
clusterizers[tabname_full].cards_list.sort_dir_str = sort_dir_str;
|
||||
extraNetworksApplyFilter(tabname_full);
|
||||
};
|
||||
clusterizers[tabname_full].cards_list.setSortDir(sort_dir_str);
|
||||
}
|
||||
|
||||
const extraNetworksControlTreeViewOnClick = (event, tabname_full) => {
|
||||
function extraNetworksControlTreeViewOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for the Tree View button.
|
||||
*
|
||||
* Toggles the tree view in the extra networks pane.
|
||||
|
|
@ -572,10 +590,10 @@ const extraNetworksControlTreeViewOnClick = (event, tabname_full) => {
|
|||
return;
|
||||
}
|
||||
clusterizers[tabname_full].tree_list.scroll_elem.parentElement.classList.toggle("hidden", !show);
|
||||
//clusterizers[tabname_full].tree_list.enable(show);
|
||||
};
|
||||
clusterizers[tabname_full].tree_list.enable(show);
|
||||
}
|
||||
|
||||
const extraNetworksControlDirsViewOnClick = (event, tabname_full) => {
|
||||
function extraNetworksControlDirsViewOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for the Dirs View button.
|
||||
*
|
||||
* Toggles the directory view in the extra networks pane.
|
||||
|
|
@ -589,9 +607,9 @@ const extraNetworksControlDirsViewOnClick = (event, tabname_full) => {
|
|||
|
||||
const pane = gradioApp().getElementById(`${tabname_full}_pane`);
|
||||
pane.querySelector(".extra-network-content--dirs-view").classList.toggle("hidden", !show);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksControlRefreshOnClick = (event, tabname_full) => {
|
||||
function extraNetworksControlRefreshOnClick(event, tabname_full) {
|
||||
/** Handles `onclick` events for the Refresh Page button.
|
||||
*
|
||||
* In order to actually call the python functions in `ui_extra_networks.py`
|
||||
|
|
@ -612,9 +630,9 @@ const extraNetworksControlRefreshOnClick = (event, tabname_full) => {
|
|||
|
||||
// Fire an event for this button click.
|
||||
gradioApp().getElementById(`${tabname_full}_extra_refresh_internal`).dispatchEvent(new Event("click"));
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksCardOnClick = (event, tabname) => {
|
||||
function extraNetworksCardOnClick(event, tabname) {
|
||||
const elem = event.currentTarget;
|
||||
const prompt_elem = gradioApp().querySelector(`#${tabname}_prompt > label > textarea`);
|
||||
const neg_prompt_elem = gradioApp().querySelector(`#${tabname}_neg_prompt > label > textarea`);
|
||||
|
|
@ -626,17 +644,17 @@ const extraNetworksCardOnClick = (event, tabname) => {
|
|||
} else {
|
||||
extraNetworksUpdatePrompt(prompt_elem, elem.dataset.prompt);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksTreeFileOnClick = (event, btn, tabname_full) => {
|
||||
function extraNetworksTreeFileOnClick(event, btn, tabname_full) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksTreeDirectoryOnClick = (event, btn, tabname_full) => {
|
||||
function extraNetworksTreeDirectoryOnClick(event, btn, tabname_full) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksTreeOnClick = (event, tabname_full) => {
|
||||
function extraNetworksTreeOnClick(event, tabname_full) {
|
||||
const btn = event.target.closest(".tree-list-item");
|
||||
if (!isElementLogError(btn)) {
|
||||
return;
|
||||
|
|
@ -649,14 +667,14 @@ const extraNetworksTreeOnClick = (event, tabname_full) => {
|
|||
}
|
||||
|
||||
event.stopPropagation();
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksBtnShowMetadataOnClick = (event, extra_networks_tabname, card_name) => {
|
||||
function extraNetworksBtnShowMetadataOnClick(event, extra_networks_tabname, card_name) {
|
||||
extraNetworksFetchMetadata(extra_networks_tabname, card_name);
|
||||
event.stopPropagation();
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksBtnEditMetadataOnClick = (event, tabname_full, card_name) => {
|
||||
function extraNetworksBtnEditMetadataOnClick(event, tabname_full, card_name) {
|
||||
const id = `${tabname_full}_edit_user_metadata`;
|
||||
let editor = extraPageUserMetadataEditors[id];
|
||||
if (isNullOrUndefined(editor)) {
|
||||
|
|
@ -673,16 +691,16 @@ const extraNetworksBtnEditMetadataOnClick = (event, tabname_full, card_name) =>
|
|||
editor.button.click();
|
||||
|
||||
popup(editor.page);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksBtnCopyPathOnClick = (event, path) => {
|
||||
function extraNetworksBtnCopyPathOnClick(event, path) {
|
||||
copyToClipboard(path);
|
||||
event.stopPropagation();
|
||||
};
|
||||
}
|
||||
|
||||
// ==== MAIN SETUP ====
|
||||
|
||||
const extraNetworksSetupEventDelegators = () => {
|
||||
function extraNetworksSetupEventDelegators() {
|
||||
/** Sets up event delegators for all extraNetworks tabs.
|
||||
*
|
||||
* These event handlers are not tied to any specific elements on the page.
|
||||
|
|
@ -724,20 +742,15 @@ const extraNetworksSetupEventDelegators = () => {
|
|||
closePopup();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksSetupTabContent = async (tabname, pane, controls_div) => {
|
||||
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`);
|
||||
const tree_scroll_elem = await waitForElement(`#${tabname_full}_tree_list_scroll_area`);
|
||||
const tree_content_elem = await waitForElement(`#${tabname_full}_tree_list_content_area`);
|
||||
const cards_scroll_elem = await waitForElement(`#${tabname_full}_cards_list_scroll_area`);
|
||||
const cards_content_elem = await waitForElement(`#${tabname_full}_cards_list_content_area`);
|
||||
await waitForElement(`#${tabname_full}_pane .extra-network-content--dirs-view`);
|
||||
|
||||
console.log("BEFORE:", tree_scroll_elem, cards_scroll_elem);
|
||||
controls.id = `${tabname_full}_controls`;
|
||||
controls_div.insertBefore(controls, null);
|
||||
|
||||
|
|
@ -745,8 +758,8 @@ const extraNetworksSetupTabContent = async (tabname, pane, controls_div) => {
|
|||
tree_list: new ExtraNetworksClusterizeTreeList({
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
scrollElem: tree_scroll_elem,
|
||||
contentElem: tree_content_elem,
|
||||
scrollId: `${tabname_full}_tree_list_scroll_area`,
|
||||
contentId: `${tabname_full}_tree_list_content_area`,
|
||||
tag: "div",
|
||||
callbacks: {
|
||||
initData: extraNetworksOnInitData,
|
||||
|
|
@ -756,8 +769,8 @@ const extraNetworksSetupTabContent = async (tabname, pane, controls_div) => {
|
|||
cards_list: new ExtraNetworksClusterizeCardsList({
|
||||
tabname: tabname,
|
||||
extra_networks_tabname: extra_networks_tabname,
|
||||
scrollElem: cards_scroll_elem,
|
||||
contentElem: cards_content_elem,
|
||||
scrollId: `${tabname_full}_cards_list_scroll_area`,
|
||||
contentId: `${tabname_full}_cards_list_content_area`,
|
||||
tag: "div",
|
||||
callbacks: {
|
||||
initData: extraNetworksOnInitData,
|
||||
|
|
@ -766,18 +779,15 @@ const extraNetworksSetupTabContent = async (tabname, pane, controls_div) => {
|
|||
}),
|
||||
};
|
||||
|
||||
await clusterizers[tabname_full].tree_list.setup();
|
||||
await clusterizers[tabname_full].cards_list.setup();
|
||||
|
||||
if (pane.style.display !== "none") {
|
||||
extraNetworksShowControlsForPage(tabname, tabname_full);
|
||||
}
|
||||
}
|
||||
|
||||
await extraNetworksClusterizersLoadTab({
|
||||
tabname_full: tabname_full,
|
||||
selected: false,
|
||||
fetch_data: true,
|
||||
});
|
||||
};
|
||||
|
||||
const extraNetworksSetupTab = async (tabname) => {
|
||||
async function extraNetworksSetupTab(tabname) {
|
||||
let controls_div;
|
||||
|
||||
const this_tab = await waitForElement(`#${tabname}_extra_tabs`);
|
||||
|
|
@ -793,15 +803,15 @@ const extraNetworksSetupTab = async (tabname) => {
|
|||
}
|
||||
extraNetworksRegisterPromptForTab(tabname, `${tabname}_prompt`);
|
||||
extraNetworksRegisterPromptForTab(tabname, `${tabname}_neg_prompt`);
|
||||
};
|
||||
}
|
||||
|
||||
const extraNetworksSetup = async () => {
|
||||
async function extraNetworksSetup() {
|
||||
await waitForBool(initialUiOptionsLoaded);
|
||||
|
||||
extraNetworksSetupTab('txt2img');
|
||||
extraNetworksSetupTab('img2img');
|
||||
extraNetworksSetupEventDelegators();
|
||||
};
|
||||
}
|
||||
|
||||
onUiLoaded(extraNetworksSetup);
|
||||
onOptionsChanged(() => initialUiOptionsLoaded.state = true);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class ExtraNetworksClusterize extends Clusterize {
|
|||
sort_fn = this.default_sort_fn;
|
||||
tabname = "";
|
||||
extra_networks_tabname = "";
|
||||
enabled = false;
|
||||
|
||||
// Override base class defaults
|
||||
default_sort_mode_str = "divId";
|
||||
|
|
@ -27,17 +28,54 @@ class ExtraNetworksClusterize extends Clusterize {
|
|||
sort_dir_str = this.default_sort_dir_str;
|
||||
filter_str = this.default_filter_str;
|
||||
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
// finish initialization
|
||||
this.tabname = getValueThrowError(...args, "tabname");
|
||||
this.extra_networks_tabname = getValueThrowError(...args, "extra_networks_tabname");
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.tabname = getValueThrowError(args, "tabname");
|
||||
this.extra_networks_tabname = getValueThrowError(args, "extra_networks_tabname");
|
||||
}
|
||||
|
||||
sortByDivId() {
|
||||
sortByDivId(data) {
|
||||
/** Sort data_obj keys (div_id) as numbers. */
|
||||
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort(INT_COLLATOR.compare);
|
||||
return Object.keys(data).sort(INT_COLLATOR.compare);
|
||||
}
|
||||
|
||||
async reinitData() {
|
||||
await this.initData();
|
||||
// can't use super class' sort since it relies on setup being run first.
|
||||
// but we do need to make sure to sort the new data before continuing.
|
||||
await this.options.callbacks.sortData.call(this);
|
||||
await this.setMaxItems(Object.keys(this.data_obj).length);
|
||||
}
|
||||
|
||||
async setup() {
|
||||
if (this.setup_has_run) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.reinitData();
|
||||
|
||||
if (this.enabled) {
|
||||
await super.setup();
|
||||
}
|
||||
}
|
||||
|
||||
async load(force_init_data) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.setup_has_run) {
|
||||
await this.setup();
|
||||
} else if (force_init_data) {
|
||||
await this.reinitData();
|
||||
} else {
|
||||
await this.refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
enable(state) {
|
||||
// if no state is passed, we enable by default.
|
||||
this.enabled = state !== false;
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
|
@ -46,31 +84,54 @@ class ExtraNetworksClusterize extends Clusterize {
|
|||
super.clear();
|
||||
}
|
||||
|
||||
async initDataDefault() {
|
||||
/**Fetches the initial data.
|
||||
*
|
||||
* This data should be minimal and only contain div IDs and other necessary
|
||||
* information such as sort keys and terms for filtering.
|
||||
*/
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
setSortMode(sort_mode_str) {
|
||||
if (this.sort_mode_str === sort_mode_str) {
|
||||
return;
|
||||
}
|
||||
|
||||
async fetchDataDefault(idx_start, idx_end) {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
async sortDataDefault(sort_mode_str, sort_dir_str) {
|
||||
this.sort_mode_str = sort_mode_str;
|
||||
this.sort_dir_str = sort_dir_str;
|
||||
this.sort_reverse = sort_dir_str === "descending";
|
||||
this.sortData();
|
||||
}
|
||||
|
||||
setSortDir(sort_dir_str) {
|
||||
const reverse = (sort_dir_str === "descending");
|
||||
if (this.sort_reverse === reverse) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sort_dir_str = sort_dir_str;
|
||||
this.sort_reverse = reverse;
|
||||
this.sortData();
|
||||
}
|
||||
|
||||
setFilterStr(filter_str) {
|
||||
if (isString(filter_str) && this.filter_str !== filter_str.toLowerCase()) {
|
||||
this.filter_str = filter_str.toLowerCase();
|
||||
} else if (isNullOrUndefined(this.filter_str)) {
|
||||
this.filter_str = this.default_filter_str;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filterData();
|
||||
}
|
||||
|
||||
async initDataDefaultCallback() {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
async fetchDataDefaultCallback() {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
async sortDataDefaultCallback() {
|
||||
this.data_obj_keys_sorted = this.sort_fn(this.data_obj);
|
||||
if (this.sort_reverse) {
|
||||
this.data_obj_keys_sorted = this.data_obj_keys_sorted.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
async filterDataDefault(filter_str) {
|
||||
async filterDataDefaultCallback() {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
}
|
||||
|
|
@ -79,8 +140,10 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
selected_div_id = null;
|
||||
|
||||
constructor(args) {
|
||||
args.no_data_text = "Directory is empty.";
|
||||
super(args);
|
||||
super({
|
||||
...args,
|
||||
no_data_text: "Directory is empty.",
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -147,6 +210,42 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
this.selected_div_id = "selected" in elem.dataset ? div_id : null;
|
||||
}
|
||||
|
||||
getMaxRowWidth() {
|
||||
/** Calculates the width of the widest row in the list. */
|
||||
if (!this.enabled) {
|
||||
// Inactive list is not displayed on screen. Can't calculate size.
|
||||
return false;
|
||||
}
|
||||
if (this.content_elem.children.length === 0) {
|
||||
// If there is no data then just skip.
|
||||
return false;
|
||||
}
|
||||
|
||||
let max_width = 0;
|
||||
for (let i = 0; i < this.content_elem.children.length; i += this.n_cols) {
|
||||
let row_width = 0;
|
||||
for (let j = 0; j < this.n_cols; j++) {
|
||||
const child = this.content_elem.children[i + j];
|
||||
const child_style = window.getComputedStyle(child, null);
|
||||
const prev_style = child.style.cssText;
|
||||
const n_cols = child_style.getPropertyValue("grid-template-columns").split(" ").length;
|
||||
child.style.gridTemplateColumns = `repeat(${n_cols}, max-content)`;
|
||||
row_width += child.scrollWidth;
|
||||
// Restore previous style.
|
||||
child.style.cssText = prev_style;
|
||||
}
|
||||
max_width = Math.max(max_width, row_width);
|
||||
}
|
||||
if (max_width <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adds the scroll element's border and the scrollbar's width to the result.
|
||||
// If scrollbar isn't visible, then only the element border is added.
|
||||
max_width += this.scroll_elem.offsetWidth - this.scroll_elem.clientWidth;
|
||||
return max_width;
|
||||
}
|
||||
|
||||
async onRowExpandClick(div_id, elem) {
|
||||
/** Expands or collapses a row to show/hide children. */
|
||||
if (!keyExistsLogError(this.data_obj, div_id)){
|
||||
|
|
@ -165,7 +264,7 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
await this.setMaxItems(Object.values(this.data_obj).filter(v => v.visible).length);
|
||||
}
|
||||
|
||||
async initDataDefault() {
|
||||
async initData() {
|
||||
/*Expects an object like the following:
|
||||
{
|
||||
parent: null or div_id,
|
||||
|
|
@ -174,11 +273,18 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
expanded: bool,
|
||||
}
|
||||
*/
|
||||
console.log("BLAH:", this.options.callbacks.initData);
|
||||
this.data_obj = await this.options.callbacks.initData(this.constructor.name);
|
||||
this.data_obj = await this.options.callbacks.initData.call(
|
||||
this,
|
||||
this.tabname,
|
||||
this.extra_networks_tabname,
|
||||
this.constructor.name,
|
||||
);
|
||||
}
|
||||
|
||||
async fetchDataDefault(idx_start, idx_end) {
|
||||
async fetchData(idx_start, idx_end) {
|
||||
if (!this.enabled) {
|
||||
return [];
|
||||
}
|
||||
const n_items = idx_end - idx_start;
|
||||
const div_ids = [];
|
||||
for (const div_id of this.data_obj_keys_sorted.slice(idx_start)) {
|
||||
|
|
@ -190,7 +296,8 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
}
|
||||
}
|
||||
|
||||
const data = await this.options.callbacks.fetchData(
|
||||
const data = await this.options.callbacks.fetchData.call(
|
||||
this,
|
||||
this.constructor.name,
|
||||
this.extra_networks_tabname,
|
||||
div_ids,
|
||||
|
|
@ -202,8 +309,8 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
const text_size = style.getPropertyValue("--button-large-text-size");
|
||||
|
||||
const res = [];
|
||||
for (const [div_id, item] of Object.entries(data)) {
|
||||
const parsed_html = htmlStringToElement(item);
|
||||
for (const [div_id, html_str] of Object.entries(data)) {
|
||||
const parsed_html = htmlStringToElement(html_str);
|
||||
const depth = Number(parsed_html.dataset.depth);
|
||||
parsed_html.style.paddingLeft = `calc(${depth} * ${text_size})`;
|
||||
parsed_html.style.boxShadow = this.getBoxShadow(depth);
|
||||
|
|
@ -216,14 +323,10 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
res.push(parsed_html.outerHTML);
|
||||
}
|
||||
|
||||
return rows;
|
||||
return res;
|
||||
}
|
||||
|
||||
async sortDataDefault(sort_mode, sort_dir) {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
async filterDataDefault(filter_str) {
|
||||
async filterDataDefaultCallback() {
|
||||
// just return the number of visible objects in our data.
|
||||
return Object.values(this.data_obj).filter(v => v.visible).length;
|
||||
}
|
||||
|
|
@ -231,8 +334,10 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
|
|||
|
||||
class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
|
||||
constructor(args) {
|
||||
args.no_data_text = "No files matching filter.";
|
||||
super(args);
|
||||
super({
|
||||
...args,
|
||||
no_data_text: "No files matching filter.",
|
||||
});
|
||||
}
|
||||
|
||||
sortByName(data) {
|
||||
|
|
@ -259,18 +364,25 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
|
|||
});
|
||||
}
|
||||
|
||||
async initDataDefault() {
|
||||
async initData() {
|
||||
/*Expects an object like the following:
|
||||
{
|
||||
search_keys: array of strings,
|
||||
sort_<mode>: string, (for various sort modes)
|
||||
}
|
||||
*/
|
||||
console.log("HERE:", this.options.callbacks);
|
||||
this.data_obj = await this.options.callbacks.initData(this.constructor.name);
|
||||
this.data_obj = await this.options.callbacks.initData.call(
|
||||
this,
|
||||
this.tabname,
|
||||
this.extra_networks_tabname,
|
||||
this.constructor.name,
|
||||
);
|
||||
}
|
||||
|
||||
async fetchDataDefault(idx_start, idx_end) {
|
||||
async fetchData(idx_start, idx_end) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
const n_items = idx_end - idx_start;
|
||||
const div_ids = [];
|
||||
for (const div_id of this.data_obj_keys_sorted.slice(idx_start)) {
|
||||
|
|
@ -282,7 +394,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
|
|||
}
|
||||
}
|
||||
|
||||
const data = await this.options.callbacks.fetchData(
|
||||
const data = await this.options.callbacks.fetchData.call(
|
||||
this,
|
||||
this.constructor.name,
|
||||
this.extra_networks_tabname,
|
||||
div_ids,
|
||||
|
|
@ -291,35 +404,29 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
|
|||
return Object.values(data);
|
||||
}
|
||||
|
||||
async sortDataDefault(sort_mode_str, sort_dir_str) {
|
||||
switch (sort_mode_str) {
|
||||
async sortData() {
|
||||
switch (this.sort_mode_str) {
|
||||
case "name":
|
||||
this.sort_fn = this.sortByName;
|
||||
break;
|
||||
case "path":
|
||||
this.sort_fn = this.sortByPath;
|
||||
break;
|
||||
case "created":
|
||||
case "date_created":
|
||||
this.sort_fn = this.sortByDateCreated;
|
||||
break;
|
||||
case "modified":
|
||||
case "date_modified":
|
||||
this.sort_fn = this.sortByDateModified;
|
||||
break;
|
||||
default:
|
||||
this.sort_fn = this.default_sort_fn;
|
||||
break;
|
||||
}
|
||||
await super.sortDataDefault(sort_mode_str, sort_dir_str)
|
||||
await super.sortData()
|
||||
}
|
||||
|
||||
async filterDataDefault(filter_str) {
|
||||
async filterDataDefaultCallback() {
|
||||
/** Filters data by a string and returns number of items after filter. */
|
||||
if (isString(filter_str)) {
|
||||
this.filter_str = filter_str.toLowerCase();
|
||||
} else if (isNullOrUndefined(this.filter_str)) {
|
||||
this.filter_str = this.default_filter_str;
|
||||
}
|
||||
|
||||
let n_visible = 0;
|
||||
for (const [div_id, v] of Object.entries(this.data_obj)) {
|
||||
let visible = v.search_terms.indexOf(this.filter_str) != -1;
|
||||
|
|
|
|||
|
|
@ -1,156 +1,161 @@
|
|||
/** Helper functions for checking types and simplifying logging/error handling. */
|
||||
/** Collators used for sorting. */
|
||||
const INT_COLLATOR = new Intl.Collator([], {numeric: true});
|
||||
const STR_COLLATOR = new Intl.Collator("en", {numeric: true, sensitivity: "base"});
|
||||
|
||||
const isNumber = x => typeof x === "number" && isFinite(x);
|
||||
const isNumberLogError = x => {
|
||||
/** Helper functions for checking types and simplifying logging/error handling. */
|
||||
function isNumber(x) { return typeof x === "number" && isFinite(x); }
|
||||
function isNumberLogError(x) {
|
||||
if (isNumber(x)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`expected number, got: ${typeof x}`);
|
||||
return false;
|
||||
};
|
||||
const isNumberThrowError = x => {
|
||||
}
|
||||
function isNumberThrowError(x) {
|
||||
if (isNumber(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`expected number, got: ${typeof x}`);
|
||||
};
|
||||
}
|
||||
|
||||
const isString = x => typeof x === "string" || x instanceof String;
|
||||
const isStringLogError = x => {
|
||||
function isString(x) { return typeof x === "string" || x instanceof String; }
|
||||
function isStringLogError(x) {
|
||||
if (isString(x)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`expected string, got: ${typeof x}`);
|
||||
return false;
|
||||
};
|
||||
const isStringThrowError = x => {
|
||||
}
|
||||
function isStringThrowError(x) {
|
||||
if (isString(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`expected string, got: ${typeof x}`);
|
||||
};
|
||||
}
|
||||
|
||||
const isNull = x => x === null;
|
||||
const isUndefined = x => typeof x === "undefined" || x === undefined;
|
||||
function isNull(x) { return x === null; }
|
||||
function isUndefined(x) { return typeof x === "undefined" || x === undefined; }
|
||||
// checks both null and undefined for simplicity sake.
|
||||
const isNullOrUndefined = x => isNull(x) || isUndefined(x);
|
||||
const isNullOrUndefinedLogError = x => {
|
||||
function isNullOrUndefined(x) { return isNull(x) || isUndefined(x); }
|
||||
function isNullOrUndefinedLogError(x) {
|
||||
if (isNullOrUndefined(x)) {
|
||||
console.error("Variable is null/undefined.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const isNullOrUndefinedThrowError = x => {
|
||||
}
|
||||
function isNullOrUndefinedThrowError(x) {
|
||||
if (!isNullOrUndefined(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error("Variable is null/undefined.");
|
||||
};
|
||||
}
|
||||
|
||||
const isElement = x => x instanceof Element;
|
||||
const isElementLogError = x => {
|
||||
function isElement(x) { return x instanceof Element; }
|
||||
function isElementLogError(x) {
|
||||
if (isElement(x)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`expected element type, got: ${typeof x}`);
|
||||
return false;
|
||||
};
|
||||
const isElementThrowError = x => {
|
||||
}
|
||||
function isElementThrowError(x) {
|
||||
if (isElement(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`expected element type, got: ${typeof x}`);
|
||||
};
|
||||
}
|
||||
|
||||
const isFunction = x => typeof x === "function";
|
||||
const isFunctionLogError = x => {
|
||||
function isFunction(x) { return typeof x === "function"; }
|
||||
function isFunctionLogError(x) {
|
||||
if (isFunction(x)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`expected function type, got: ${typeof x}`);
|
||||
return false;
|
||||
};
|
||||
const isFunctionThrowError = x => {
|
||||
}
|
||||
function isFunctionThrowError(x) {
|
||||
if (isFunction(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`expected function type, got: ${typeof x}`);
|
||||
};
|
||||
}
|
||||
|
||||
const isObject = x => typeof x === "object" && !Array.isArray(x);
|
||||
const isObjectLogError = x => {
|
||||
function isObject(x) { return typeof x === "object" && !Array.isArray(x); }
|
||||
function isObjectLogError(x) {
|
||||
if (isObject(x)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`expected object type, got: ${typeof x}`);
|
||||
return false;
|
||||
};
|
||||
const isObjectThrowError = x => {
|
||||
}
|
||||
function isObjectThrowError(x) {
|
||||
if (isObject(x)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`expected object type, got: ${typeof x}`);
|
||||
};
|
||||
}
|
||||
|
||||
const keyExists = (obj, k) => isObject(obj) && isString(k) && k in obj;
|
||||
const keyExistsLogError = (obj, k) => {
|
||||
function keyExists(obj, k) {
|
||||
return isObject(obj) && isString(k) && k in obj;
|
||||
}
|
||||
function keyExistsLogError(obj, k) {
|
||||
if (keyExists(obj, k)) {
|
||||
return true;
|
||||
}
|
||||
console.error(`key does not exist in object: ${k}`);
|
||||
return false;
|
||||
};
|
||||
const keyExistsThrowError = (obj, k) => {
|
||||
}
|
||||
function keyExistsThrowError(obj, k) {
|
||||
if (keyExists(obj, k)) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`key does not exist in object: ${k}`)
|
||||
};
|
||||
}
|
||||
|
||||
const getValue = (obj, k) => {
|
||||
function getValue(obj, k) {
|
||||
/** Returns value of object for given key if it exists, otherwise returns null. */
|
||||
if (keyExists(obj, k)) {
|
||||
return obj[k];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const getValueLogError = (obj, k) => {
|
||||
}
|
||||
function getValueLogError(obj, k) {
|
||||
if (keyExistsLogError(obj, k)) {
|
||||
return obj[k];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const getValueThrowError = (obj, k) => {
|
||||
}
|
||||
function getValueThrowError(obj, k) {
|
||||
keyExistsThrowError(obj, k);
|
||||
return obj[k];
|
||||
};
|
||||
}
|
||||
|
||||
const getElementByIdLogError = selector => {
|
||||
function getElementByIdLogError(selector) {
|
||||
const elem = gradioApp().getElementById(selector);
|
||||
isElementLogError(elem);
|
||||
return elem;
|
||||
};
|
||||
const getElementByIdThrowError = selector => {
|
||||
}
|
||||
function getElementByIdThrowError(selector) {
|
||||
const elem = gradioApp().getElementById(selector);
|
||||
isElementThrowError(elem);
|
||||
return elem;
|
||||
};
|
||||
}
|
||||
|
||||
const querySelectorLogError = selector => {
|
||||
function querySelectorLogError(selector) {
|
||||
const elem = gradioApp().querySelector(selector);
|
||||
isElementLogError(elem);
|
||||
return elem;
|
||||
};
|
||||
const querySelectorThrowError = selector => {
|
||||
}
|
||||
function querySelectorThrowError(selector) {
|
||||
const elem = gradioApp().querySelector(selector);
|
||||
isElementThrowError(elem);
|
||||
return elem;
|
||||
};
|
||||
}
|
||||
|
||||
/** Functions for getting dimensions of elements. */
|
||||
|
||||
const getComputedPropertyDims = (elem, prop) => {
|
||||
function getComputedPropertyDims(elem, prop) {
|
||||
/** Returns the top/left/bottom/right float dimensions of an element for the specified property. */
|
||||
const style = window.getComputedStyle(elem, null);
|
||||
return {
|
||||
|
|
@ -159,27 +164,27 @@ const getComputedPropertyDims = (elem, prop) => {
|
|||
bottom: parseFloat(style.getPropertyValue(`${prop}-bottom`)),
|
||||
right: parseFloat(style.getPropertyValue(`${prop}-right`)),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const getComputedMarginDims = elem => {
|
||||
function getComputedMarginDims(elem) {
|
||||
/** Returns the width/height of the computed margin of an element. */
|
||||
const dims = getComputedPropertyDims(elem, "margin");
|
||||
return {
|
||||
width: dims.left + dims.right,
|
||||
height: dims.top + dims.bottom,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const getComputedPaddingDims = elem => {
|
||||
function getComputedPaddingDims(elem) {
|
||||
/** Returns the width/height of the computed padding of an element. */
|
||||
const dims = getComputedPropertyDims(elem, "padding");
|
||||
return {
|
||||
width: dims.left + dims.right,
|
||||
height: dims.top + dims.bottom,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const getComputedBorderDims = elem => {
|
||||
function getComputedBorderDims(elem) {
|
||||
/** Returns the width/height of the computed border of an element. */
|
||||
// computed border will always start with the pixel width so thankfully
|
||||
// the parseFloat() conversion will just give us the width and ignore the rest.
|
||||
|
|
@ -189,9 +194,9 @@ const getComputedBorderDims = elem => {
|
|||
width: dims.left + dims.right,
|
||||
height: dims.top + dims.bottom,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const getComputedDims = elem => {
|
||||
function getComputedDims(elem) {
|
||||
/** Returns the full width and height of an element including its margin, padding, and border. */
|
||||
const width = elem.scrollWidth;
|
||||
const height = elem.scrollHeight;
|
||||
|
|
@ -202,24 +207,24 @@ const getComputedDims = elem => {
|
|||
width: width + margin.width + padding.width + border.width,
|
||||
height: height + margin.height + padding.height + border.height,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const calcColsPerRow = function (parent, child) {
|
||||
function calcColsPerRow(parent, child) {
|
||||
/** Calculates the number of columns of children that can fit in a parent's visible width. */
|
||||
const parent_inner_width = parent.offsetWidth - getComputedPaddingDims(parent).width;
|
||||
return parseInt(parent_inner_width / getComputedDims(child).width, 10);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const calcRowsPerCol = function (parent, child) {
|
||||
function calcRowsPerCol(parent, child) {
|
||||
/** Calculates the number of rows of children that can fit in a parent's visible height. */
|
||||
const parent_inner_height = parent.offsetHeight - getComputedPaddingDims(parent).height;
|
||||
return parseInt(parent_inner_height / getComputedDims(child).height, 10);
|
||||
};
|
||||
}
|
||||
|
||||
/** Functions for asynchronous operations. */
|
||||
|
||||
const debounce = (handler, timeout_ms) => {
|
||||
function debounce(handler, timeout_ms) {
|
||||
/** Debounces a function call.
|
||||
*
|
||||
* NOTE: This will NOT work if called from within a class.
|
||||
|
|
@ -244,9 +249,9 @@ const debounce = (handler, timeout_ms) => {
|
|||
clearTimeout(timer);
|
||||
timer = setTimeout(() => handler(...args), timeout_ms);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const waitForElement = selector => {
|
||||
function waitForElement(selector) {
|
||||
/** Promise that waits for an element to exist in DOM. */
|
||||
return new Promise(resolve => {
|
||||
if (document.querySelector(selector)) {
|
||||
|
|
@ -265,9 +270,9 @@ const waitForElement = selector => {
|
|||
subtree: true
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const waitForBool = o => {
|
||||
function waitForBool(o) {
|
||||
/** Promise that waits for a boolean to be true.
|
||||
*
|
||||
* `o` must be an Object of the form:
|
||||
|
|
@ -283,9 +288,9 @@ const waitForBool = o => {
|
|||
setTimeout(_waitForBool, 100);
|
||||
})();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const waitForKeyInObject = o => {
|
||||
function waitForKeyInObject(o) {
|
||||
/** Promise that waits for a key to exist in an object.
|
||||
*
|
||||
* `o` must be an Object of the form:
|
||||
|
|
@ -304,9 +309,9 @@ const waitForKeyInObject = o => {
|
|||
setTimeout(_waitForKeyInObject, 100);
|
||||
})();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const waitForValueInObject = o => {
|
||||
function waitForValueInObject(o) {
|
||||
/** Promise that waits for a key value pair in an Object.
|
||||
*
|
||||
* `o` must be an Object of the form:
|
||||
|
|
@ -329,11 +334,11 @@ const waitForValueInObject = o => {
|
|||
})();
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/** Requests */
|
||||
|
||||
const requestGet = (url, data, handler, errorHandler) => {
|
||||
function requestGet(url, data, handler, errorHandler) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var args = Object.keys(data).map(function (k) {
|
||||
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]);
|
||||
|
|
@ -357,9 +362,9 @@ const requestGet = (url, data, handler, errorHandler) => {
|
|||
};
|
||||
var js = JSON.stringify(data);
|
||||
xhr.send(js);
|
||||
};
|
||||
}
|
||||
|
||||
const requestGetPromise = (url, data) => {
|
||||
function requestGetPromise(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
let args = Object.keys(data).map(k => {
|
||||
|
|
@ -367,39 +372,40 @@ const requestGetPromise = (url, data) => {
|
|||
}).join("&");
|
||||
xhr.open("GET", url + "?" + args, true);
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
resolve(xhr.responseText);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject({ status: this.status, statusText: xhr.statusText });
|
||||
}
|
||||
xhr.onload = () => {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
resolve(xhr.responseText);
|
||||
} else {
|
||||
reject({status: xhr.status, response: xhr.responseText});
|
||||
}
|
||||
};
|
||||
xhr.send(JSON.stringify(data));
|
||||
|
||||
xhr.onerror = () => {
|
||||
reject({status: xhr.status, response: xhr.responseText});
|
||||
};
|
||||
const payload = JSON.stringify(data);
|
||||
xhr.send(payload);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/** Misc helper functions. */
|
||||
|
||||
const clamp = (x, min, max) => Math.max(min, Math.min(x, max));
|
||||
function clamp(x, min, max) {
|
||||
return Math.max(min, Math.min(x, max));
|
||||
}
|
||||
|
||||
const getStyle = (prop, elem) => {
|
||||
function getStyle(prop, elem) {
|
||||
return window.getComputedStyle ? window.getComputedStyle(elem)[prop] : elem.currentStyle[prop];
|
||||
};
|
||||
}
|
||||
|
||||
const htmlStringToElement = function (str) {
|
||||
function htmlStringToElement(s) {
|
||||
/** Converts an HTML string into an Element type. */
|
||||
let parser = new DOMParser();
|
||||
let tmp = parser.parseFromString(str, "text/html");
|
||||
let tmp = parser.parseFromString(s, "text/html");
|
||||
return tmp.body.firstElementChild;
|
||||
};
|
||||
}
|
||||
|
||||
const toggleCss = (key, css, enable) => {
|
||||
function toggleCss(key, css, enable) {
|
||||
var style = document.getElementById(key);
|
||||
if (enable && !style) {
|
||||
style = document.createElement('style');
|
||||
|
|
@ -414,10 +420,10 @@ const toggleCss = (key, css, enable) => {
|
|||
style.innerHTML == '';
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const copyToClipboard = s => {
|
||||
function copyToClipboard(s) {
|
||||
/** Copies the passed string to the clipboard. */
|
||||
isStringThrowError(s);
|
||||
navigator.clipboard.writeText(s);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue