clean up and fix bugs

This commit is contained in:
Sj-Si 2024-03-25 10:26:29 -04:00
parent 4885d59ac1
commit 62a5b2bc74
3 changed files with 145 additions and 102 deletions

View file

@ -1,3 +1,5 @@
const SEARCH_INPUT_DEBOUNCE_TIME_MS = 250;
const re_extranet = /<([^:^>]+:[^:]+):[\d.]+>(.*)/;
const re_extranet_g = /<([^:^>]+:[^:]+):[\d.]+>/g;
const re_extranet_neg = /\(([^:^>]+:[\d.]+)\)/;
@ -7,7 +9,6 @@ const clusterizers = {};
var globalPopup = null;
var globalPopupInner = null;
const storedPopupIds = {};
const tab_setup_complete = {};
const extraPageUserMetadataEditors = {};
// A flag used by the `waitForBool` promise to determine when we first load Ui Options.
const initialUiOptionsLoaded = { state: false };
@ -197,14 +198,14 @@ function extraNetworksSetupTabContent(tabname, pane, controls_div) {
// Debounce search text input. This way we only search after user is done typing.
let search_input_debounce = debounce(() => {
if (txt_search.value) {
extraNetworksApplyFilter(tabname_full);
}
}, 250);
extraNetworksApplyFilter(tabname_full);
}, SEARCH_INPUT_DEBOUNCE_TIME_MS);
txt_search.addEventListener("keyup", search_input_debounce);
// Update search filter whenever the search input's clear button is pressed.
txt_search.addEventListener("extra-network-control--search-clear", () => extraNetworksApplyFilter(tabname_full));
txt_search.addEventListener("extra-network-control--search-clear", () => {
extraNetworksApplyFilter(tabname_full);
});
// Insert the controls into the page.
var controls = gradioApp().querySelector(`#${tabname_full}_controls`);
@ -212,8 +213,6 @@ function extraNetworksSetupTabContent(tabname, pane, controls_div) {
if (pane.style.display != "none") {
extraNetworksShowControlsForPage(tabname, tabname_full);
}
}).then(() => {
tab_setup_complete[tabname_full] = true;
});
}
@ -313,6 +312,7 @@ function extraNetworksApplyFilter(tabname_full) {
}
function extraNetworksClusterizersEnable(tabname_full) {
/** Enables the selected tab's clusterizer and disables all others. */
// iterate over tabnames
for (const [_tabname_full, tab_clusterizers] of Object.entries(clusterizers)) {
// iterate over clusterizers in tab
@ -323,14 +323,15 @@ function extraNetworksClusterizersEnable(tabname_full) {
}
}
function extraNetworkClusterizersOnTabLoad(tabname_full) {
function extraNetworkClusterizersOnTabLoad(tabname_full) { /** promise */
return new Promise(resolve => {
/** Enables a tab's clusterizer, updates its data, and rebuilds it. */
// Enables a tab's clusterizer, updates its data, and rebuilds it.
if (!(tabname_full in clusterizers)) {
return resolve();
}
(async () => {
// Enable then load the selected tab's clusterize lists.
extraNetworksClusterizersEnable(tabname_full);
for (const v of Object.values(clusterizers[tabname_full])) {
await v.load();
@ -346,7 +347,7 @@ function extraNetworksSetupEventHandlers() {
// This will automatically fit the left pane to the size of its largest loaded row.
window.addEventListener("resizeHandleDblClick", (e) => {
e.stopPropagation();
const tabname_full = e.target.closest(".extra-network-pane").id.replace("_pane", "");
const tabname_full = e.target.closest(".extra-network-pane").dataset.tabnameFull;
// This event is only applied to the currently selected tab if has clusterize list.
if (!(tabname_full in clusterizers)) {
return;
@ -489,34 +490,6 @@ function extraNetworksTreeProcessDirectoryClick(event, btn, tabname_full) {
var true_targ = event.target;
const div_id = btn.dataset.divId;
function _expandOrCollapse(_btn) {
// Expands/Collapses all children of the button.
if ("expanded" in _btn.dataset) {
delete _btn.dataset.expanded;
clusterizers[tabname_full].tree_list.removeChildRows(div_id);
} else {
_btn.dataset.expanded = "";
clusterizers[tabname_full].tree_list.addChildRows(div_id);
}
// update html after changing attr.
clusterizers[tabname_full].tree_list.updateDivContent(div_id, _btn.outerHTML);
clusterizers[tabname_full].tree_list.updateRows();
}
function _removeSelectedFromAll() {
// Removes the `selected` attribute from all buttons.
var sels = document.querySelectorAll(".tree-list-item");
[...sels].forEach(el => {
delete el.dataset.selected;
});
}
function _selectButton(_btn) {
// Removes `data-selected` attribute from all buttons then adds to passed button.
_removeSelectedFromAll();
_btn.dataset.selected = "";
}
function _updateSearch(_search_text) {
// Update search input with select button's path.
var search_input_elem = gradioApp().querySelector(`#${tabname_full}_extra_search`);
@ -525,21 +498,19 @@ function extraNetworksTreeProcessDirectoryClick(event, btn, tabname_full) {
extraNetworksApplyFilter(tabname_full);
}
// If user clicks on the chevron, then we do not select the folder.
if (true_targ.matches(".tree-list-item-action--leading, .tree-list-item-action-chevron")) {
_expandOrCollapse(btn);
} else {
// User clicked anywhere else on the button.
if ("selected" in btn.dataset) {
// If folder is selected, deselect button.
delete btn.dataset.selected;
// If user clicks on the chevron, then we do not select the folder.
let prev_selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
clusterizers[tabname_full].tree_list.onRowExpandClick(div_id, btn);
let selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
if (prev_selected_elem instanceof Element && !(selected_elem instanceof Element)) {
// if a selected element was removed, clear filter.
_updateSearch("");
} else {
// If folder is not selected, select it.
_selectButton(btn);
_updateSearch(btn.dataset.path);
}
} else {
// user clicked anywhere else on row.
clusterizers[tabname_full].tree_list.onRowSelected(div_id, btn);
_updateSearch("selected" in btn.dataset ? btn.dataset.path : "");
}
}
@ -599,19 +570,18 @@ function extraNetworkDirsOnClick(event, tabname_full) {
function extraNetworksControlSearchClearOnClick(event, tabname_full) {
/** Clears the search <input> text. */
let clear_btn = event.target.closest(".extra-network-control--search-clear");
// Deselect all buttons from both dirs view and tree view
gradioApp().querySelectorAll(".extra-network-dirs-view-button").forEach((elem) => {
delete elem.dataset.selected;
});
gradioApp().querySelectorAll(".tree-list-item").forEach((elem) => {
delete elem.dataset.selected;
});
let txt_search = clear_btn.previousElementSibling;
txt_search.value = "";
txt_search.dispatchEvent(new CustomEvent("extra-network-control--search-clear", {}));
txt_search.dispatchEvent(
new CustomEvent(
"extra-network-control--search-clear",
{
detail: {
tabname_full: tabname_full
}
}
)
);
}
function extraNetworksControlSortModeOnClick(event, tabname_full) {
@ -650,7 +620,7 @@ function extraNetworksControlSortDirOnClick(event, tabname_full) {
}
if (tabname_full in clusterizers) {
clusterizers[tabname_full].cards_list.setSortDir(event.currentTarget);
clusterizers[tabname_full].cards_list.setSortDir(event.currentTarget.dataset.sortDir.toLowerCase());
extraNetworksApplyFilter(tabname_full);
}
}
@ -705,7 +675,6 @@ function extraNetworksControlRefreshOnClick(event, tabname_full) {
*/
// reset states
initialUiOptionsLoaded.state = false;
tab_setup_complete = {};
// Fire an event for this button click.
gradioApp().getElementById(`${tabname_full}_extra_refresh_internal`).dispatchEvent(new Event("click"));
}

View file

@ -1,4 +1,4 @@
const JSON_UPDATE_DEBOUNCE_TIME_MS = 1000;
const JSON_UPDATE_DEBOUNCE_TIME_MS = 250;
const RESIZE_DEBOUNCE_TIME_MS = 250;
// Collators used for sorting.
const INT_COLLATOR = new Intl.Collator([], { numeric: true });
@ -132,9 +132,9 @@ function decompress(base64string) {
const parseHtml = function (str) {
/** Converts an HTML string into an Element type. */
const tmp = document.implementation.createHTMLDocument('');
tmp.body.innerHTML = str;
return [...tmp.body.childNodes];
let parser = new DOMParser();
let tmp = parser.parseFromString(str, "text/html");
return tmp.body.firstElementChild;
}
const getComputedValue = function (container, css_property) {
@ -260,13 +260,12 @@ class ExtraNetworksClusterize {
return resolve();
}
Promise.resolve(encoded_str)
.then(v => { if (!isNullOrUndefined(this.clusterize)) {this.clear();} return v; })
.then(v => decompress(v))
.then(v => JSON.parse(v))
.then(v => this.updateJson(v))
.then(() => this.encoded_str = encoded_str)
.then(() => this.rebuild())
//.then(() => this.init())
//.then(() => this.repair())
.then(() => this.applyFilter())
.then(() => { return resolve(); });
});
@ -308,7 +307,7 @@ class ExtraNetworksClusterize {
var results = [];
for (const div_id of this.data_obj_keys_sorted) {
if (obj[div_id].active) {
results.push(obj[div_id].element.outerHTML);
results.push(obj[div_id].html);
}
}
return results;
@ -324,11 +323,11 @@ class ExtraNetworksClusterize {
*/
if (!(div_id in this.data_obj)) {
console.error("div_id not in data_obj:", div_id);
} else if (typeof content === "object") {
this.data_obj[div_id].element = parseHtml(content.outerHTML)[0];
} else if (isElement(content)) {
this.data_obj[div_id].html = content.outerHTML;
return true;
} else if (typeof content === "string") {
this.data_obj[div_id].element = parseHtml(content)[0];
} else if (isString(content)) {
this.data_obj[div_id].html = content;
return true;
} else {
console.error("Invalid content:", div_id, content);
@ -379,7 +378,7 @@ class ExtraNetworksClusterize {
// We remove this row before returning.
if (this.rowCount() === 0){// || this.content_elem.innerHTML === "") {
this.clear();
this.update([this.data_obj[this.data_obj_keys_sorted[0]].element.outerHTML]);
this.update([this.data_obj[this.data_obj_keys_sorted[0]].html]);
clear_before_return = true;
}
@ -636,6 +635,8 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
/** Subclass used to display a directories/files in the Tree View. */
constructor(...args) {
super(...args);
this.selected_div_id = null;
}
getBoxShadow(depth) {
@ -659,26 +660,30 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
/** Processes JSON object and adds each entry to our data object. */
return new Promise(resolve => {
var style = getComputedStyle(document.body);
//let spacing_sm = style.getPropertyValue("--spacing-sm");
let text_size = style.getPropertyValue("--button-large-text-size");
for (const [k, v] of Object.entries(json)) {
let div_id = k;
let parsed_html = parseHtml(v)[0];
let parsed_html = parseHtml(v);
// parent_id = -1 if item is at root level
let parent_id = "parentId" in parsed_html.dataset ? parsed_html.dataset.parentId : -1;
let expanded = "expanded" in parsed_html.dataset;
let selected = "selected" in parsed_html.dataset;
let depth = Number(parsed_html.dataset.depth);
parsed_html.style.paddingLeft = `calc(${depth} * ${text_size})`;
parsed_html.style.boxShadow = this.getBoxShadow(depth);
// Add the updated html to the data object.
this.data_obj[div_id] = {
element: parsed_html,
html: parsed_html.outerHTML,
active: parent_id === -1, // always show root
expanded: expanded || (parent_id === -1), // always expand root
selected: selected,
parent: parent_id,
children: [], // populated later
};
// maybe not necessary.
parsed_html = null;
}
// Build list of children for each element in dataset.
@ -715,15 +720,20 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
*/
for (const child_id of this.data_obj[div_id].children) {
this.data_obj[child_id].active = false;
this.data_obj[child_id].expanded = false;
delete this.data_obj[child_id].element.dataset.expanded;
if (this.data_obj[child_id].selected) {
// deselect the child only if it is selected.
let elem = parseHtml(this.data_obj[child_id].html);
delete elem.dataset.selected;
this.data_obj[child_id].selected = false;
this.updateDivContent(child_id, elem);
}
this.removeChildRows(child_id);
}
}
addChildRows(div_id) {
/** Adds rows to the list that are children of the passed div.
* The rows aren't removed from the data object, just set to active=true
/** Adds rows to the list that are children of the passed div.
* The rows aren't added to the data object, just set to active=true
* so they are displayed.
*/
for (const child_id of this.data_obj[div_id].children) {
@ -734,6 +744,56 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
}
}
onRowExpandClick(div_id, elem) {
/** Toggles expand/collapse of a row's children. */
if ("expanded" in elem.dataset) {
this.data_obj[div_id].expanded = false;
delete elem.dataset.expanded;
this.removeChildRows(div_id)
} else {
this.data_obj[div_id].expanded = true;
elem.dataset.expanded = "";
this.addChildRows(div_id)
}
this.updateDivContent(div_id, elem);
this.updateRows();
}
onRowSelected(div_id, elem) {
/** Selects a row and deselects all others. */
if (!isElementLogError(elem)) {
return;
}
if (!(div_id in this.data_obj)) {
console.error("div_id not in dataset:", div_id);
return;
}
if (!isNullOrUndefined(this.selected_div_id) && div_id !== this.selected_div_id) {
let prev_elem = parseHtml(this.data_obj[this.selected_div_id].html);
delete prev_elem.dataset.selected;
this.updateDivContent(this.selected_div_id, prev_elem);
this.data_obj[this.selected_div_id].selected = false;
this.selected_div_id = div_id;
elem.dataset.selected = "";
this.data_obj[div_id].selected = true;
this.updateDivContent(this.selected_div_id, elem);
} else {
if ("selected" in elem.dataset) {
delete elem.dataset.selected;
this.data_obj[div_id].selected = false;
this.selected_div_id = null;
} else {
elem.dataset.selected = "";
this.data_obj[div_id].selected = true;
this.selected_div_id = div_id;
}
this.updateDivContent(div_id, elem);
}
this.updateRows();
}
getMaxRowWidth() {
/** Calculates the width of the widest row in the list. */
if (!this.enabled) {
@ -785,14 +845,33 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
updateJson(json) {
/** Processes JSON object and adds each entry to our data object. */
return new Promise(resolve => {
for (const [k, v] of Object.entries(json)) {
for (const [i, [k, v]] of Object.entries(Object.entries(json))) {
let div_id = k;
let parsed_html = parseHtml(v)[0];
let parsed_html = parseHtml(v);
let search_only = isElement(parsed_html.querySelector(".search_only"));
let search_terms_elem = parsed_html.querySelector(".search_terms");
let search_terms = "";
if (isElement(search_terms_elem)) {
search_terms = Array.prototype.map.call(
parsed_html.querySelectorAll(".search_terms"),
(elem) => { return elem.textContent.toLowerCase(); }
).join(" ");
}
// Add the updated html to the data object.
this.data_obj[div_id] = {
element: parsed_html,
active: true,
html: v,
sort_name: parsed_html.dataset.sortName,
sort_path: parsed_html.dataset.sortPath,
sort_created: parsed_html.dataset.sortCreated,
sort_modified: parsed_html.dataset.sortModified,
search_only: search_only,
search_terms: search_terms,
};
// maybe not necessary
parsed_html = null;
}
return resolve();
});
@ -815,8 +894,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
sortByName() {
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort((a, b) => {
return STR_COLLATOR.compare(
this.data_obj[a].element.dataset.sortName,
this.data_obj[b].element.dataset.sortName,
this.data_obj[a].sort_name,
this.data_obj[b].sort_name,
);
});
}
@ -824,8 +903,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
sortByPath() {
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort((a, b) => {
return STR_COLLATOR.compare(
this.data_obj[a].element.dataset.sortPath,
this.data_obj[b].element.dataset.sortPath,
this.data_obj[a].sort_path,
this.data_obj[b].sort_path,
);
});
}
@ -833,8 +912,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
sortByCreated() {
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort((a, b) => {
return INT_COLLATOR.compare(
this.data_obj[a].element.dataset.sortCreated,
this.data_obj[b].element.dataset.sortCreated,
this.data_obj[a].sort_created,
this.data_obj[b].sort_created,
);
});
}
@ -842,8 +921,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
sortByModified() {
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort((a, b) => {
return INT_COLLATOR.compare(
this.data_obj[a].element.dataset.sortModified,
this.data_obj[b].element.dataset.sortModified,
this.data_obj[a].sort_modified,
this.data_obj[b].sort_modified,
);
});
}
@ -888,13 +967,8 @@ class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
}
for (const [k, v] of Object.entries(this.data_obj)) {
let search_only = v.element.querySelector(".search_only");
let text = Array.prototype.map.call(v.element.querySelectorAll(".search_terms"), function (t) {
return t.textContent.toLowerCase();
}).join(" ");
let visible = text.indexOf(this.filter_str) != -1;
if (search_only && this.filter_str.length < 4) {
let visible = v.search_terms.indexOf(this.filter_str) != -1;
if (v.search_only && this.filter_str.length < 4) {
visible = false;
}
this.data_obj[k].active = visible;