Cleaned up chip list code further and simplified a few things.

This commit is contained in:
2025-09-26 08:35:09 -07:00
parent eac3a3cc22
commit 47c1953b23

View File

@@ -52,11 +52,10 @@ class ChipList extends IgniteElement {
input: null, input: null,
search: true, search: true,
searching: false, searching: false,
showSearchResults: true,
searchLoading: false, searchLoading: false,
searchResults: null, searchResults: null,
searchResultConverter: (result) => new text(result), searchResultConverter: (result) => new text(result),
searchDelay: 200, searchDelay: 300,
searchCallback: null, searchCallback: null,
searchFunction: null, searchFunction: null,
documentListener: null, documentListener: null,
@@ -101,46 +100,6 @@ class ChipList extends IgniteElement {
.class("input") .class("input")
.attribute("contenteditable", "true") .attribute("contenteditable", "true")
.ref(this.input) .ref(this.input)
.onEnter((e) => {
e.preventDefault();
//If we are read only don't do anything.
if (this.readOnly) {
return;
}
//If this chip allows free form input then add a new item.
if (this.freeForm && this.input.textContent.trim().length >= 1) {
if (this.items == null) {
this.items = [];
}
//Add a new item to the chip list.
this.items.push({ content: this.input.textContent.trim() });
this.input.innerHTML = "";
this.input.focus(); //Refocus to ensure we still have it.
this.searching = false; //Reset searching since we just added a item.
this.changed = true; //Make sure changed flag was set.
}
})
.onBackspace((e) => {
//If we are read only don't do anything.
if (this.readOnly) {
return;
}
//If the backspace key is pressed and there is no content, try to remove the last item from the list.
if (this.input.textContent.length == 0 || (this.input.textContent.length == 1 && this.input.textContent[0] == " ")) {
e.preventDefault();
if (this.items) {
this.items.pop();
this.changed = true; //Make sure changed flag was set.
}
this.searching = false;
}
})
.on("keydown", (e) => { .on("keydown", (e) => {
//If we are read only don't do anything. //If we are read only don't do anything.
if (this.readOnly) { if (this.readOnly) {
@@ -149,16 +108,39 @@ class ChipList extends IgniteElement {
//If the escape key is pressed stop searching until something else happens. //If the escape key is pressed stop searching until something else happens.
if (e.key == "Escape") { if (e.key == "Escape") {
this.searching = false; this.stopSearching();
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
return; return;
} }
//If the enter key is pressed add a new item if free form allows.
else if (e.key == "Enter") {
e.preventDefault();
e.stopPropagation();
if (this.freeForm && this.input.textContent.trim().length >= 1) {
this.stopSearching();
//Add a new item to the chip list.
if (this.items) {
this.items.push(this.input.textContent.trim());
} else {
this.items = [this.input.textContent.trim()];
}
this.input.innerHTML = "";
this.input.focus(); //Refocus to ensure we still have it.
this.changed = true; //Make sure changed flag was set.
return;
} else if (!this.searching) {
this.searching = true;
this.searchLoading = false;
}
}
//Reset the searching and input if we get a tab, since the browser //Reset the searching and input if we get a tab, since the browser
//will focus the next avaiable element. //will focus the next avaiable element.
if (e.key == "Tab") { else if (e.key == "Tab") {
this.searching = false;
this.editing = false; this.editing = false;
//Fire a change event if there was a change. //Fire a change event if there was a change.
@@ -167,32 +149,44 @@ class ChipList extends IgniteElement {
this.dispatchEvent(new Event("change")); this.dispatchEvent(new Event("change"));
} }
this.stopSearching();
this.input.innerHTML = ""; this.input.innerHTML = "";
return; return;
} }
//If we are not searching and a key was pressed, open the search box. //If we are not searching and a key was pressed, open the search box.
if (!this.searching && this.search && (e.key !== "Backspace" || (e.key == "Backspace" && e.target.textContent.length > 1)) && (this.items == null || this.items.length < this.itemsMax)) { else if (!this.searching && this.search && (e.key !== "Backspace" || (e.key == "Backspace" && e.target.textContent.length > 1)) && (this.items == null || this.items.length < this.itemsMax)) {
this.searching = true; this.searching = true;
this.showSearchResults = true; this.searchLoading = false;
} else if (this.items != null && this.items.length >= this.itemsMax && e.key !== "Backspace") { }
//Don't allow input if we reached the max number of items. //Don't allow input if we reached the max number of items.
else if (this.items != null && this.items.length >= this.itemsMax && e.key !== "Backspace") {
e.preventDefault(); e.preventDefault();
} }
//Remove the last item and stop searching if the backspace was pressed and there is no search text
else if (e.key == "Backspace" && (this.input.textContent.length == 0 || (this.input.textContent.length == 1 && this.input.textContent[0] == " "))) {
e.preventDefault();
//If we are searching and we have a on search function invoke it. if (this.items) {
this.items.pop();
this.changed = true; //Make sure changed flag was set.
}
this.stopSearching();
}
//If we are searching and we have a search function invoke it.
if (this.searching && this.searchFunction) { if (this.searching && this.searchFunction) {
//Clear a pending search //Clear a pending search if there is one
if (this.searchCallback) { if (this.searchCallback) {
clearTimeout(this.searchCallback); clearTimeout(this.searchCallback);
this.searchCallback = null;
} }
//Schedule a new search //Schedule a new search
this.searchCallback = setTimeout(async () => { this.searchCallback = setTimeout(async () => {
this.searchLoading = true; this.searchLoading = true;
this.searchResults = await this.searchFunction(this.input.textContent.trim()); this.searchResults = await this.searchFunction(this.input.textContent.trim());
this.searchLoading = false; this.searchLoading = false;
}, this.searchDelay); }, this.searchDelay);
} }
@@ -203,16 +197,18 @@ class ChipList extends IgniteElement {
//Clear button //Clear button
new button() new button()
.class("btn btn-link text-muted fs-4") .class("btn btn-link text-muted fs-4")
.attribute("tabindex", "-1")
.title("Clear") .title("Clear")
.show([this.showClearButton, this.items], (show, items) => show && items && items.length > 0) .show([this.showClearButton, this.items], (show, items) => show && items && items.length > 0)
.child(new i().class('fa fa-times')) .child(new i().class('fa fa-times'))
.onClick(() => { .onClick(() => {
this.items = null; this.items = null;
this.editing = false; this.editing = false;
this.searching = false; this.stopSearching();
this.changed = true;
this.input.blur(); this.input.blur();
this.input.innerHTML = ""; this.input.innerHTML = "";
this.changed = false;
this.dispatchEvent(new Event("change"));
}), }),
//Search results popper //Search results popper
@@ -232,7 +228,7 @@ class ChipList extends IgniteElement {
new span().class("text-muted").hide(this.searchLoading).innerText(this.searchResults, results => results && results.length > 0 ? `Showing ${results.length} ${results.length == 1 ? "result" : "results"}` : "No results"), new span().class("text-muted").hide(this.searchLoading).innerText(this.searchResults, results => results && results.length > 0 ? `Showing ${results.length} ${results.length == 1 ? "result" : "results"}` : "No results"),
//Results //Results
new div().class("d-flex flex-column gap-2").hide([this.showSearchResults, this.searchLoading], (showSearchResults, searchLoading) => !showSearchResults || searchLoading).child( new div().class("d-flex flex-column gap-2").hide(this.searchLoading).child(
new list( new list(
this.searchResults, this.searchResults,
result => new div() result => new div()
@@ -299,6 +295,17 @@ class ChipList extends IgniteElement {
this.input.innerHTML = ""; this.input.innerHTML = "";
this.input.focus(); this.input.focus();
} }
stopSearching() {
this.searching = false;
this.searchLoading = false;
if (this.searchCallback) {
clearTimeout(this.searchCallback);
this.searchCallback = null;
}
}
} }
class ChipListTemplate extends IgniteTemplate { class ChipListTemplate extends IgniteTemplate {