stable-diffusion-webui/javascript/extraNetworksClusterize.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

337 lines
11 KiB
JavaScript
Raw Normal View History

2024-04-09 11:19:07 +00:00
class NotImplementedError extends Error {
constructor(...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, NotImplementedError);
}
this.name = "NotImplementedError";
}
}
class ExtraNetworksClusterize extends Clusterize {
data_obj = {};
data_obj_keys_sorted = [];
sort_reverse = false;
default_sort_fn = this.sortByDivId;
sort_fn = this.default_sort_fn;
tabname = "";
extra_networks_tabname = "";
// Override base class defaults
default_sort_mode_str = "divId";
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;
constructor(...args) {
super(...args);
// finish initialization
this.tabname = getValueThrowError(...args, "tabname");
this.extra_networks_tabname = getValueThrowError(...args, "extra_networks_tabname");
}
sortByDivId() {
/** Sort data_obj keys (div_id) as numbers. */
this.data_obj_keys_sorted = Object.keys(this.data_obj).sort(INT_COLLATOR.compare);
}
clear() {
this.data_obj = {};
this.data_obj_keys_sorted = [];
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();
}
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.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) {
throw new NotImplementedError();
}
}
class ExtraNetworksClusterizeTreeList extends ExtraNetworksClusterize {
selected_div_id = null;
constructor(args) {
args.no_data_text = "Directory is empty.";
super(args);
}
clear() {
this.selected_div_id = null;
super.clear();
}
getBoxShadow(depth) {
/** Generates style for a multi-level box shadow for vertical indentation lines.
* This is used to indicate the depth of a directory/file within a directory tree.
*/
let res = "";
var style = getComputedStyle(document.body);
let bg = style.getPropertyValue("--body-background-fill");
let fg = style.getPropertyValue("--border-color-primary");
let text_size = style.getPropertyValue("--button-large-text-size");
for (let i = 1; i <= depth; i++) {
res += `calc((${i} * ${text_size}) - (${text_size} * 0.6)) 0 0 ${bg} inset,`;
res += `calc((${i} * ${text_size}) - (${text_size} * 0.4)) 0 0 ${fg} inset`;
res += (i + 1 > depth) ? "" : ", ";
}
return res;
}
#setVisibility(div_id, visible) {
/** Recursively sets the visibility of a div_id and its children. */
for (const child_id of this.data_obj[div_id].children) {
this.data_obj[child_id].visible = visible;
if (visible) {
if (this.data_obj[div_id].expanded) {
this.#setVisibility(child_id, visible);
}
} else {
if (this.selected_div_id === child_id) {
this.selected_div_id = null;
}
this.#setVisibility(child_id, visible);
}
}
}
onRowSelected(div_id, elem, override) {
/** Selects a row and deselects all others. */
if (!isElementLogError(elem)) {
return;
}
if (!keyExistsLogError(this.data_obj, div_id)) {
return;
}
override = override === true;
if (!isNullOrUndefined(this.selected_div_id) && div_id !== this.selected_div_id) {
// deselect current selection if exists on page
const prev_elem = this.content_elem.querySelector(`div[data-div-id="${this.selected_div_id}"]`);
if (isElement(prev_elem)) {
delete prev_elem.dataset.selected;
}
}
elem.toggleAttribute("data-selected");
this.selected_div_id = "selected" in elem.dataset ? div_id : null;
}
async onRowExpandClick(div_id, elem) {
/** Expands or collapses a row to show/hide children. */
if (!keyExistsLogError(this.data_obj, div_id)){
return;
}
// Toggle state
this.data_obj[div_id].expanded = !this.data_obj[div_id].expanded;
const visible = this.data_obj[div_id].expanded;
for (const child_id of this.data_obj[div_id].children) {
this.#setVisibility(child_id, visible)
}
this.#setVisibility()
await this.setMaxItems(Object.values(this.data_obj).filter(v => v.visible).length);
}
async initDataDefault() {
/*Expects an object like the following:
{
parent: null or div_id,
children: array of div_id's,
visible: bool,
expanded: bool,
}
*/
console.log("BLAH:", this.options.callbacks.initData);
this.data_obj = await this.options.callbacks.initData(this.constructor.name);
}
async fetchDataDefault(idx_start, idx_end) {
const n_items = idx_end - idx_start;
const div_ids = [];
for (const div_id of this.data_obj_keys_sorted.slice(idx_start)) {
if (this.data_obj[div_id].visible) {
div_ids.push(div_id);
}
if (div_ids.length >= n_items) {
break;
}
}
const data = await this.options.callbacks.fetchData(
this.constructor.name,
this.extra_networks_tabname,
div_ids,
);
// we have to calculate the box shadows here since the element is on the page
// at this point and we can get its computed styles.
const style = getComputedStyle(document.body);
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);
const depth = Number(parsed_html.dataset.depth);
parsed_html.style.paddingLeft = `calc(${depth} * ${text_size})`;
parsed_html.style.boxShadow = this.getBoxShadow(depth);
if (this.data_obj[div_id].expanded) {
parsed_html.dataset.expanded = "";
}
if (div_id === this.selected_div_id) {
parsed_html.dataset.selected = "";
}
res.push(parsed_html.outerHTML);
}
return rows;
}
async sortDataDefault(sort_mode, sort_dir) {
throw new NotImplementedError();
}
async filterDataDefault(filter_str) {
// just return the number of visible objects in our data.
return Object.values(this.data_obj).filter(v => v.visible).length;
}
}
class ExtraNetworksClusterizeCardsList extends ExtraNetworksClusterize {
constructor(args) {
args.no_data_text = "No files matching filter.";
super(args);
}
sortByName(data) {
return Object.keys(data).sort((a, b) => {
return STR_COLLATOR.compare(data[a].sort_name, data[b].sort_name);
});
}
sortByPath(data) {
return Object.keys(data).sort((a, b) => {
return STR_COLLATOR.compare(data[a].sort_path, data[b].sort_path);
});
}
sortByDateCreated(data) {
return Object.keys(data).sort((a, b) => {
return INT_COLLATOR.compare(data[a].sort_date_created, data[b].sort_date_created);
});
}
sortByDateModified(data) {
return Object.keys(data).sort((a, b) => {
return INT_COLLATOR.compare(data[a].sort_date_modified, data[b].sort_date_modified);
});
}
async initDataDefault() {
/*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);
}
async fetchDataDefault(idx_start, idx_end) {
const n_items = idx_end - idx_start;
const div_ids = [];
for (const div_id of this.data_obj_keys_sorted.slice(idx_start)) {
if (this.data_obj[div_id].visible) {
div_ids.push(div_id);
}
if (div_ids.length >= n_items) {
break;
}
}
const data = await this.options.callbacks.fetchData(
this.constructor.name,
this.extra_networks_tabname,
div_ids,
);
return Object.values(data);
}
async sortDataDefault(sort_mode_str, sort_dir_str) {
switch (sort_mode_str) {
case "name":
this.sort_fn = this.sortByName;
break;
case "path":
this.sort_fn = this.sortByPath;
break;
case "created":
this.sort_fn = this.sortByDateCreated;
break;
case "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)
}
async filterDataDefault(filter_str) {
/** 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;
if (v.search_only && this.filter_str.length < 4) {
visible = false;
}
this.data_obj[div_id].visible = visible;
if (visible) {
n_visible++;
}
}
return n_visible;
}
}