Dropdown mouse hover & click

This commit is contained in:
Christian Bastian
2024-01-25 21:10:41 -05:00
parent 4d0db38847
commit 9712d2a3bb

View File

@@ -49,13 +49,28 @@ const modelNodeType = {
"vae_approx": undefined, "vae_approx": undefined,
}; };
const dropdownSelectClass = "search-dropdown-selected";
/** /**
* @param {HTMLDivElement} dropdown * @param {HTMLDivElement} dropdown
* @param {Array.<{name: string, childCount: ?int, childIndex: ?int}>} directories * @param {Array.<{name: string, childCount: ?int, childIndex: ?int}>} directories
* @param {string} modelType * @param {string} modelType
* @param {string} filter * @param {string} filter
* @param {string} sep
* @param {HTMLInputElement} inputElement
* @param {Function} updateModelDropdown
* @param {Function} updateModelGrid
*/ */
function updateDirectorySuggestionDropdown(dropdown, directories, modelType, filter, sep) { function updateDirectorySuggestionDropdown(
dropdown,
directories,
modelType,
filter,
sep,
inputElement,
updateModelDropdown,
updateModelGrid
) {
let options = []; let options = [];
if (filter[0] === sep) { if (filter[0] === sep) {
let cwd = null; let cwd = null;
@@ -131,10 +146,63 @@ function updateDirectorySuggestionDropdown(dropdown, directories, modelType, fil
} }
} }
} }
const setActiveMouseOver = (e) => {
const children = dropdown.children;
let iChild;
for (iChild = 0; iChild < children.length; iChild++) {
const child = children[iChild];
if (child.classList.contains(dropdownSelectClass)) {
child.classList.remove(dropdownSelectClass);
}
}
e.target.classList.add(dropdownSelectClass);
};
const onMouseEnter = (e) => {
e.stopPropagation();
setActiveMouseOver(e);
};
const onMouseMove = (e) => {
if (!e.target.classList.contains(dropdownSelectClass)) {
// assumes only one will ever selected at a time
e.stopPropagation();
setActiveMouseOver(e);
}
};
const onMouseLeave = (e) => {
e.stopPropagation();
e.target.classList.remove(dropdownSelectClass);
};
const onMouseDown = (e) => {
e.stopPropagation();
//e.target.classList.remove(dropdownSelectClass);
appendDropdownSelectionToInput(
inputElement,
e.target,
sep,
updateModelDropdown,
updateModelGrid
);
};
const innerHtml = options.map((text) => { const innerHtml = options.map((text) => {
const p = $el("p", [text]); /** @type {HTMLParagraphElement} */
//p.onclick = (e) => { console.log(e.target); }; // TODO: Click on dropdown elements when input gets blurred? const p = $el(
"p",
{
onmouseenter: (e) => onMouseEnter(e),
onmousemove: (e) => onMouseMove(e),
onmouseleave: (e) => onMouseLeave(e),
onmousedown: (e) => onMouseDown(e),
},
[
text
]
);
return p; return p;
}); });
dropdown.innerHTML = ""; dropdown.innerHTML = "";
@@ -146,6 +214,75 @@ function updateDirectorySuggestionDropdown(dropdown, directories, modelType, fil
} }
} }
/**
* @param {HTMLInputElement} inputElement
* @param {HTMLParagraphElement} child
* @param {string} sep
* @param {Function} updateModelDropdown
* @param {Function} updateModelGrid
*/
function appendDropdownSelectionToInput(inputElement, child, sep, updateModelDropdown, updateModelGrid) {
if (child !== undefined && child !== null) {
child.classList.remove(dropdownSelectClass);
const selectedText = child.innerText;
const oldFilterText = inputElement.value;
const iSep = oldFilterText.lastIndexOf(sep);
const previousPath = oldFilterText.substring(0, iSep + 1);
const newFilterText = previousPath + selectedText;
inputElement.value = newFilterText;
updateModelDropdown(); // TODO: should this be here?
}
updateModelGrid(); // TODO: GENERALIZATION -> this shouldn't be here
inputElement.blur();
}
/**
* @param {HTMLDivElement} modelGrid
* @param {Object} models
* @param {HTMLSelectElement} modelSelect
* @param {Object.<{value: string}>} previousModelType
* @param {Object} settings
* @param {Array} previousModelFilters
* @param {HTMLInputElement} modelFilter
*/
function updateModelGrid(modelGrid, models, modelSelect, previousModelType, settings, previousModelFilters, modelFilter) {
let modelType = modelSelect.value;
if (models[modelType] === undefined) {
modelType = "checkpoints"; // TODO: magic value
}
if (modelType !== previousModelType.value) {
if (settings["model-persistent-search"].checked) {
previousModelFilters.splice(0, previousModelFilters.length); // TODO: make sure this actually worked!
}
else {
// cache previous filter text
previousModelFilters[previousModelType.value] = modelFilter.value;
// read cached filter text
modelFilter.value = previousModelFilters[modelType] ?? "";
}
previousModelType.value = modelType;
}
let modelTypeOptions = [];
for (const [key, value] of Object.entries(models)) {
const el = $el("option", [key]);
modelTypeOptions.push(el);
}
modelSelect.innerHTML = "";
modelTypeOptions.forEach(option => modelSelect.add(option));
modelSelect.value = modelType;
const searchAppend = settings["model-search-always-append"].value;
const searchText = modelFilter.value + " " + searchAppend;
const modelList = ModelGrid.filter(models[modelType], searchText);
modelGrid.innerHTML = "";
const modelGridModels = ModelGrid.generateInnerHtml(modelList, modelType, settings);
modelGrid.append.apply(modelGrid, modelGridModels);
}
/** /**
* @param {string} nodeType * @param {string} nodeType
* @returns {int} * @returns {int}
@@ -433,7 +570,7 @@ class ModelGrid {
.split(/(-?".*?"|[^\s"]+)+/g) .split(/(-?".*?"|[^\s"]+)+/g)
.map((item) => item .map((item) => item
.trim() .trim()
.replace(/(?:'|")+/g, "") .replace(/(?:")+/g, "")
.toLowerCase()) .toLowerCase())
.filter(Boolean); .filter(Boolean);
@@ -743,8 +880,8 @@ class ModelManager extends ComfyDialog {
/** @type {Array} */ sources: [], /** @type {Array} */ sources: [],
/** @type {Object} */ models: {}, /** @type {Object} */ models: {},
/** @type {{name: string, childCount: ?int, childIndex: ?int}[]} */ modelDirectories: null, /** @type {{name: string, childCount: ?int, childIndex: ?int}[]} */ modelDirectories: null,
/** @type {Array} */ prevousModelFilters: [], /** @type {Array} */ previousModelFilters: [],
/** @type {string} */ prevousModelType: undefined, /** @type {Object.<{value: string}>} */ previousModelType: { value: undefined },
}; };
/** @type {string} */ /** @type {string} */
@@ -953,7 +1090,6 @@ class ModelManager extends ComfyDialog {
$: (el) => (this.#el.modelDirectorySearchOptions = el), $: (el) => (this.#el.modelDirectorySearchOptions = el),
style: { display: "none" }, style: { display: "none" },
}); });
const dropdownSelectClass = "search-dropdown-selected";
return [ return [
$el("div.row.tab-header", [ $el("div.row.tab-header", [
@@ -995,18 +1131,13 @@ class ModelManager extends ComfyDialog {
} }
else if (e.key === "Enter") { else if (e.key === "Enter") {
e.stopPropagation(); e.stopPropagation();
if (iChild < children.length) { appendDropdownSelectionToInput(
const child = children[iChild]; e.target,
child.classList.remove(dropdownSelectClass); children[iChild],
const selectedText = child.innerText; this.sep,
const filterText = e.target.value; this.#modelUpdateFilterDropdown,
const iSep = filterText.lastIndexOf(this.sep); this.#modelGridUpdate
const previousPath = filterText.substring(0, iSep + 1); );
e.target.value = previousPath + selectedText;
this.#modelUpdateFilterDropdown();
}
this.#modelGridUpdate();
e.target.blur();
} }
else if (e.key === "ArrowDown" || e.key === "ArrowUp") { else if (e.key === "ArrowDown" || e.key === "ArrowUp") {
e.stopPropagation(); e.stopPropagation();
@@ -1065,49 +1196,15 @@ class ModelManager extends ComfyDialog {
]; ];
} }
#modelGridUpdate() { #modelGridUpdate = () => updateModelGrid(
const models = this.#data.models; this.#el.modelGrid,
const modelSelect = this.#el.modelTypeSelect; this.#data.models,
this.#el.modelTypeSelect,
let modelType = modelSelect.value; this.#data.previousModelType,
if (models[modelType] === undefined) { this.#el.settings,
modelType = "checkpoints"; // TODO: magic value this.#data.previousModelFilters,
} this.#el.modelContentFilter
);
const prevousModelType = this.#el.prevousModelType;
if (modelType !== prevousModelType) {
if (this.#el.settings["model-persistent-search"].checked) {
this.#data.prevousModelFilters = [];
}
else {
const modelFilter = this.#el.modelContentFilter;
const prevousModelFilters = this.#data.prevousModelFilters;
// cache previous filter text
prevousModelFilters[prevousModelType] = modelFilter.value;
// read cached filter text
modelFilter.value = prevousModelFilters[modelType] ?? "";
}
this.#el.prevousModelType = modelType;
}
let modelTypeOptions = [];
for (const [key, value] of Object.entries(models)) {
const el = $el("option", [key]);
modelTypeOptions.push(el);
}
modelSelect.innerHTML = "";
modelTypeOptions.forEach(option => modelSelect.add(option));
modelSelect.value = modelType;
const searchAppend = this.#el.settings["model-search-always-append"].value;
const searchText = this.#el.modelContentFilter.value + " " + searchAppend;
const modelList = ModelGrid.filter(models[modelType], searchText);
const modelGrid = this.#el.modelGrid;
modelGrid.innerHTML = "";
const modelGridModels = ModelGrid.generateInnerHtml(modelList, modelType, this.#el.settings);
modelGrid.append.apply(modelGrid, modelGridModels);
}
async #modelGridRefresh() { async #modelGridRefresh() {
this.#data.models = await request("/model-manager/models"); this.#data.models = await request("/model-manager/models");
@@ -1115,17 +1212,20 @@ class ModelManager extends ComfyDialog {
this.#modelGridUpdate(); this.#modelGridUpdate();
} }
async #modelUpdateFilterDropdown() { #modelUpdateFilterDropdown = () => {
const filter = this.#el.modelContentFilter.value;
const modelType = this.#el.modelTypeSelect.value; const modelType = this.#el.modelTypeSelect.value;
const filter = this.#el.modelContentFilter.value;
updateDirectorySuggestionDropdown( updateDirectorySuggestionDropdown(
this.#el.modelDirectorySearchOptions, this.#el.modelDirectorySearchOptions,
this.#data.modelDirectories, this.#data.modelDirectories,
modelType, modelType,
filter, filter,
this.sep this.sep,
this.#el.modelContentFilter,
this.#modelUpdateFilterDropdown,
this.#modelGridUpdate,
); );
this.#data.prevousModelFilters[modelType] = filter; this.#data.previousModelFilters[modelType] = filter;
} }
/** /**