simple-keyboard/src/lib/components/CandidateBox.ts
2023-04-24 04:04:46 -04:00

163 lines
4.6 KiB
TypeScript

import "./css/CandidateBox.css";
import Utilities from "../services/Utilities";
import {
CandidateBoxParams,
CandidateBoxRenderParams,
CandidateBoxShowParams,
KeyboardOptions,
} from "./../interfaces";
class CandidateBox {
utilities: Utilities;
options: KeyboardOptions;
candidateBoxElement!: HTMLDivElement;
pageIndex = 0;
pageSize: number;
constructor({ utilities, options }: CandidateBoxParams) {
this.utilities = utilities;
this.options = options;
Utilities.bindMethods(CandidateBox, this);
this.pageSize = this.utilities.getOptions().layoutCandidatesPageSize || 5;
}
destroy() {
if (this.candidateBoxElement) {
this.candidateBoxElement.remove();
this.pageIndex = 0;
}
}
show({
candidateValue,
targetElement,
onSelect,
}: CandidateBoxShowParams): void {
if (!candidateValue || !candidateValue.length) {
return;
}
const candidateListPages = this.utilities.chunkArray(
candidateValue.split(" "),
this.pageSize
);
this.renderPage({
candidateListPages,
targetElement,
pageIndex: this.pageIndex,
nbPages: candidateListPages.length,
onItemSelected: (selectedCandidate: string, e: MouseEvent) => {
onSelect(selectedCandidate, e);
this.destroy();
},
});
}
renderPage({
candidateListPages,
targetElement,
pageIndex,
nbPages,
onItemSelected,
}: CandidateBoxRenderParams) {
// Remove current candidate box, if any
this.candidateBoxElement?.remove();
// Create candidate box element
this.candidateBoxElement = document.createElement("div");
this.candidateBoxElement.className = "hg-candidate-box";
// Candidate box list
const candidateListULElement = document.createElement("ul");
candidateListULElement.className = "hg-candidate-box-list";
// Create Candidate box list items
candidateListPages[pageIndex].forEach((candidateListItem) => {
const candidateListLIElement = document.createElement("li");
const getMouseEvent = () => {
const mouseEvent = new (this.options.useTouchEvents ? TouchEvent : MouseEvent)("click");
Object.defineProperty(mouseEvent, "target", {
value: candidateListLIElement,
});
return mouseEvent;
};
candidateListLIElement.className = "hg-candidate-box-list-item";
candidateListLIElement.innerHTML = this.options.display?.[candidateListItem] || candidateListItem;
if(this.options.useTouchEvents) {
candidateListLIElement.ontouchstart = (e: any) =>
onItemSelected(candidateListItem, e || getMouseEvent());
} else {
candidateListLIElement.onclick = (e = getMouseEvent() as MouseEvent) =>
onItemSelected(candidateListItem, e);
}
// Append list item to ul
candidateListULElement.appendChild(candidateListLIElement);
});
// Add previous button
const isPrevBtnElementActive = pageIndex > 0;
const prevBtnElement = document.createElement("div");
prevBtnElement.classList.add("hg-candidate-box-prev");
isPrevBtnElementActive &&
prevBtnElement.classList.add("hg-candidate-box-btn-active");
const prevBtnElementClickAction = () => {
if (!isPrevBtnElementActive) return;
this.renderPage({
candidateListPages,
targetElement,
pageIndex: pageIndex - 1,
nbPages,
onItemSelected,
});
};
if(this.options.useTouchEvents) {
prevBtnElement.ontouchstart = prevBtnElementClickAction;
} else {
prevBtnElement.onclick = prevBtnElementClickAction;
}
this.candidateBoxElement.appendChild(prevBtnElement);
// Add elements to container
this.candidateBoxElement.appendChild(candidateListULElement);
// Add next button
const isNextBtnElementActive = pageIndex < nbPages - 1;
const nextBtnElement = document.createElement("div");
nextBtnElement.classList.add("hg-candidate-box-next");
isNextBtnElementActive &&
nextBtnElement.classList.add("hg-candidate-box-btn-active");
const nextBtnElementClickAction = () => {
if (!isNextBtnElementActive) return;
this.renderPage({
candidateListPages,
targetElement,
pageIndex: pageIndex + 1,
nbPages,
onItemSelected,
});
};
if(this.options.useTouchEvents) {
nextBtnElement.ontouchstart = nextBtnElementClickAction;
} else {
nextBtnElement.onclick = nextBtnElementClickAction;
}
this.candidateBoxElement.appendChild(nextBtnElement);
// Append candidate box to target element
targetElement.prepend(this.candidateBoxElement);
}
}
export default CandidateBox;