implement proper match highlighting in vm search feature
This commit is contained in:
parent
07bf4b0967
commit
746136724f
103
scripts/index.js
103
scripts/index.js
@ -62,7 +62,7 @@ class InstanceCard extends HTMLElement {
|
|||||||
this.vmid = data.vmid;
|
this.vmid = data.vmid;
|
||||||
this.name = data.name;
|
this.name = data.name;
|
||||||
this.node = data.node;
|
this.node = data.node;
|
||||||
this.searchQuery = data.searchQuery;
|
this.searchQueryResult = data.searchQueryResult;
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,18 +71,36 @@ class InstanceCard extends HTMLElement {
|
|||||||
vmidParagraph.innerText = this.vmid;
|
vmidParagraph.innerText = this.vmid;
|
||||||
|
|
||||||
const nameParagraph = this.shadowRoot.querySelector("#instance-name");
|
const nameParagraph = this.shadowRoot.querySelector("#instance-name");
|
||||||
if (this.searchQuery) {
|
if (this.searchQueryResult.alignment) {
|
||||||
const regExpEscape = v => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
let i = 0; // name index
|
||||||
const escapedQuery = regExpEscape(this.searchQuery);
|
let c = 0; // alignment index
|
||||||
const searchRegExp = new RegExp(`(${escapedQuery})`, "gi");
|
const alignment = this.searchQueryResult.alignment;
|
||||||
const nameParts = this.name.split(searchRegExp);
|
while (i < this.name.length && c < alignment.length) {
|
||||||
for (let i = 0; i < nameParts.length; i++) {
|
if (alignment[c] === "M") {
|
||||||
const part = document.createElement("span");
|
const part = document.createElement("span");
|
||||||
part.innerText = nameParts[i];
|
part.innerText = this.name[i];
|
||||||
if (nameParts[i].toLowerCase() === this.searchQuery.toLowerCase()) {
|
|
||||||
part.style = "color: var(--lightbg-text-color); background-color: var(--highlight-color);";
|
part.style = "color: var(--lightbg-text-color); background-color: var(--highlight-color);";
|
||||||
|
nameParagraph.append(part);
|
||||||
|
i++;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
else if (alignment[c] === "I") {
|
||||||
|
const part = document.createElement("span");
|
||||||
|
part.innerText = this.name[i];
|
||||||
|
nameParagraph.append(part);
|
||||||
|
i++;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
else if (alignment[c] === "D") {
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
else if (alignment[c] === "X") {
|
||||||
|
const part = document.createElement("span");
|
||||||
|
part.innerText = this.name[i];
|
||||||
|
nameParagraph.append(part);
|
||||||
|
i++;
|
||||||
|
c++;
|
||||||
}
|
}
|
||||||
nameParagraph.append(part);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -282,25 +300,23 @@ async function populateInstances () {
|
|||||||
const searchQuery = document.querySelector("#search").value || null;
|
const searchQuery = document.querySelector("#search").value || null;
|
||||||
let criteria;
|
let criteria;
|
||||||
if (!searchQuery) {
|
if (!searchQuery) {
|
||||||
criteria = (a, b) => {
|
criteria = (item, query = null) => {
|
||||||
return (a.vmid > b.vmid) ? 1 : -1;
|
return { score: item.vmid, alignment: null };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (searchCriteria === "exact") {
|
else if (searchCriteria === "exact") {
|
||||||
criteria = (a, b) => {
|
criteria = (item, query) => {
|
||||||
const aInc = a.name.toLowerCase().includes(searchQuery.toLowerCase());
|
const substrInc = item.includes(query);
|
||||||
const bInc = b.name.toLowerCase().includes(searchQuery.toLowerCase());
|
if (substrInc) {
|
||||||
if (aInc && bInc) {
|
const substrStartIndex = item.indexOf(query);
|
||||||
return a.vmid > b.vmid ? 1 : -1;
|
const queryLength = query.length;
|
||||||
}
|
const remaining = item.length - substrInc - queryLength;
|
||||||
else if (aInc && !bInc) {
|
const alignment = `${"X".repeat(substrStartIndex)}${"M".repeat(queryLength)}${"X".repeat(remaining)}`;
|
||||||
return -1;
|
return { score: 1, alignment };
|
||||||
}
|
|
||||||
else if (!aInc && bInc) {
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return a.vmid > b.vmid ? 1 : -1;
|
const alignment = `${"X".repeat(item.length)}`;
|
||||||
|
return { score: 0, alignment };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -308,34 +324,43 @@ async function populateInstances () {
|
|||||||
const penalties = {
|
const penalties = {
|
||||||
m: 0,
|
m: 0,
|
||||||
x: 1,
|
x: 1,
|
||||||
o: 1,
|
o: 0,
|
||||||
e: 1
|
e: 1
|
||||||
};
|
};
|
||||||
criteria = (a, b) => {
|
criteria = (item, query) => {
|
||||||
// lower is better
|
// lower is better
|
||||||
const aAlign = wfAlign(a.name.toLowerCase(), searchQuery.toLowerCase(), penalties);
|
const { score, CIGAR } = wfAlign(query, item, penalties, true);
|
||||||
const aScore = aAlign.score / a.name.length;
|
return { score: score / item.length, alignment: CIGAR };
|
||||||
const bAlign = wfAlign(b.name.toLowerCase(), searchQuery.toLowerCase(), penalties);
|
|
||||||
const bScore = bAlign.score / b.name.length;
|
|
||||||
if (aScore === bScore) {
|
|
||||||
return a.vmid > b.vmid ? 1 : -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return aScore - bScore;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
instances.sort(criteria);
|
sortInstances(criteria, searchQuery);
|
||||||
const instanceContainer = document.querySelector("#instance-container");
|
const instanceContainer = document.querySelector("#instance-container");
|
||||||
instanceContainer.innerHTML = "";
|
instanceContainer.innerHTML = "";
|
||||||
for (let i = 0; i < instances.length; i++) {
|
for (let i = 0; i < instances.length; i++) {
|
||||||
const newInstance = document.createElement("instance-card");
|
const newInstance = document.createElement("instance-card");
|
||||||
instances[i].searchQuery = searchQuery;
|
|
||||||
newInstance.data = instances[i];
|
newInstance.data = instances[i];
|
||||||
instanceContainer.append(newInstance);
|
instanceContainer.append(newInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortInstances (criteria, searchQuery) {
|
||||||
|
for (let i = 0; i < instances.length; i++) {
|
||||||
|
const { score, alignment } = criteria(instances[i].name.toLowerCase(), searchQuery ? searchQuery.toLowerCase() : "");
|
||||||
|
instances[i].searchQueryResult = { score, alignment };
|
||||||
|
}
|
||||||
|
const sortCriteria = (a, b) => {
|
||||||
|
const aScore = a.searchQueryResult.score;
|
||||||
|
const bScore = b.searchQueryResult.score;
|
||||||
|
if (aScore === bScore) {
|
||||||
|
return a.vmid > b.vmid ? 1 : -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return aScore - bScore;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
instances.sort(sortCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
async function handleInstanceAdd () {
|
async function handleInstanceAdd () {
|
||||||
const header = "Create New Instance";
|
const header = "Create New Instance";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user