Dropdown mouse hover & click
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user