add expand/collapse buttons to directories in tree view

This commit is contained in:
Sj-Si 2024-04-21 12:07:53 -04:00
parent 580711cdac
commit 7d953cc6c5
5 changed files with 106 additions and 16 deletions

View File

@ -188,22 +188,26 @@ class Clusterize {
}
async setMaxItems(max_items) {
/** Sets the new max number of items.
*
* This is used to control the scroll bar's length.
*
* Returns whether the number of max items changed.
*/
if (!this.setup_has_run || !this.enabled) {
this.#max_items = max_items;
return;
return this.#max_items !== max_items;
}
if (max_items === this.#max_items) {
if (this.#max_items === max_items) {
// No change. do nothing.
return;
return false;
}
// If the number of items changed, we need to update the cluster.
this.#max_items = max_items;
await this.refresh();
// Apply sort to the updated data.
await this.sortData();
return true;
}
// ==== PRIVATE FUNCTIONS ====

View File

@ -938,15 +938,14 @@ function extraNetworksTreeDirectoryOnClick(event, btn, tabname_full) {
const tab = extra_networks_tabs[tabname_full];
if (true_targ.matches(".tree-list-item-action--leading, .tree-list-item-action-chevron")) {
const prev_selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
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 if (true_targ.matches(".tree-list-item-action--trailing .tree-list-item-action-expand")) {
tab.tree_list.onExpandAllClick(div_id);
} else if (true_targ.matches(".tree-list-item-action--trailing .tree-list-item-action-collapse")) {
tab.tree_list.onCollapseAllClick(div_id);
} else {
// user clicked anywhere else on the row
tab.tree_list.onRowSelected(div_id, btn);
@ -963,6 +962,11 @@ function extraNetworksTreeDirectoryOnClick(event, btn, tabname_full) {
}
tab.updateSearch("selected" in btn.dataset ? btn.dataset.path : "");
}
const selected_elem = gradioApp().querySelector(".tree-list-item[data-selected='']");
if (isElement(prev_selected_elem) && !isElement(selected_elem)) {
// if a selected element was removed, clear filter.
tab.updateSearch("");
}
}
function extraNetworksTreeOnClick(event, tabname_full) {

View File

@ -338,6 +338,58 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
return max_width;
}
async onExpandAllClick(div_id) {
if (!keyExistsLogError(this.data_obj, div_id)) {
return;
}
const _expand = (parent_id) => {
const this_obj = this.data_obj[parent_id];
this_obj.visible = true;
this_obj.expanded = true;
for (const child_id of this_obj.children) {
_expand(child_id);
}
};
this.data_obj[div_id].expanded = true;
for (const child_id of this.data_obj[div_id].children) {
_expand(child_id);
}
const new_len = Object.values(this.data_obj).filter(v => v.visible).length;
const max_items_changed = await this.setMaxItems(new_len);
if (!max_items_changed) {
await this.refresh(true);
}
}
async onCollapseAllClick(div_id) {
if (!keyExistsLogError(this.data_obj, div_id)) {
return;
}
const _collapse = (parent_id) => {
const this_obj = this.data_obj[parent_id];
this_obj.visible = false;
this_obj.expanded = false;
for (const child_id of this_obj.children) {
_collapse(child_id);
}
};
this.data_obj[div_id].expanded = false;
for (const child_id of this.data_obj[div_id].children) {
_collapse(child_id);
}
const new_len = Object.values(this.data_obj).filter(v => v.visible).length;
const max_items_changed = await this.setMaxItems(new_len);
if (!max_items_changed) {
await this.refresh(true);
}
}
async onRowExpandClick(div_id, elem) {
/** Expands or collapses a row to show/hide children. */
if (!keyExistsLogError(this.data_obj, div_id)) {
@ -353,7 +405,10 @@ class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
}
const new_len = Object.values(this.data_obj).filter(v => v.visible).length;
await this.setMaxItems(new_len);
const max_items_changed = await this.setMaxItems(new_len);
if (!max_items_changed) {
await this.refresh(true);
}
}
async initData() {

View File

@ -317,6 +317,13 @@ class ExtraNetworksPage:
# Action buttons
if item is not None:
action_list_item_action_trailing += self.get_button_row(tabname, item)
else:
action_list_item_action_trailing += (
"<div class='button-row'>"
"<div class='tree-list-item-action-expand card-button' title='Expand All'></div>"
"<div class='tree-list-item-action-collapse card-button' title='Collapse All'></div>"
"</div>"
)
data_attributes_str = ""
for k, v in data_attributes.items():

View File

@ -1272,6 +1272,8 @@ body.resizing .resize-handle {
}
.extra-network-content.resize-handle-col {
display: flex;
flex-direction: column;
overflow: auto;
}
@ -1526,13 +1528,31 @@ body.resizing .resize-handle {
color: var(--button-secondary-text-color);
}
/* ==== TREE VIEW EXPAND/COLLAPSE BUTTONS ==== */
.tree-list-item-action-expand::before {
content: "≫";
}
.tree-list-item-action-expand {
transform: rotate(90deg);
}
.tree-list-item-action-collapse::before {
content: "≫";
}
.tree-list-item-action-collapse {
transform: rotate(-90deg);
}
/* ==== CHEVRON ICON ACTIONS ==== */
/* Define the animation for the arrow when it is clicked. */
.tree-list-item-action-chevron {
display: inline-flex;
height: var(--button-large-text-size);
width: var(--button-large-text-size);
mask-image: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M7 7H17V17" stroke="%23000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>');
mask-image: url('data:image/svg+xml,<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M 4 4 H 12 V 12"/></svg>');
mask-repeat: no-repeat;
mask-position: center center;
mask-size: 100%;
@ -1594,7 +1614,6 @@ body.resizing .resize-handle {
.tree-list-item-action--trailing {
grid-area: trailing-action;
display: inline-flex;
}
.tree-list-item .button-row {
@ -1606,6 +1625,7 @@ body.resizing .resize-handle {
gap: var(--spacing-sm);
box-sizing: border-box;
margin: 0;
margin-right: var(--spacing-sm);
}
.tree-list-item:hover .button-row {