mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2026-04-30 00:00:04 +08:00
Allow CandidateBox caret positioning, passing event though onChange. Per https://github.com/hodgef/react-simple-keyboard/issues/1298
This commit is contained in:
@@ -45,8 +45,8 @@ class CandidateBox {
|
||||
targetElement,
|
||||
pageIndex: this.pageIndex,
|
||||
nbPages: candidateListPages.length,
|
||||
onItemSelected: (selectedCandidate: string) => {
|
||||
onSelect(selectedCandidate);
|
||||
onItemSelected: (selectedCandidate: string, e: MouseEvent) => {
|
||||
onSelect(selectedCandidate, e);
|
||||
this.destroy();
|
||||
},
|
||||
});
|
||||
@@ -73,9 +73,18 @@ class CandidateBox {
|
||||
// Create Candidate box list items
|
||||
candidateListPages[pageIndex].forEach((candidateListItem) => {
|
||||
const candidateListLIElement = document.createElement("li");
|
||||
const getMouseEvent = () => {
|
||||
const mouseEvent = new MouseEvent("click");
|
||||
Object.defineProperty(mouseEvent, "target", {
|
||||
value: candidateListLIElement,
|
||||
});
|
||||
return mouseEvent;
|
||||
};
|
||||
|
||||
candidateListLIElement.className = "hg-candidate-box-list-item";
|
||||
candidateListLIElement.textContent = candidateListItem;
|
||||
candidateListLIElement.onclick = () => onItemSelected(candidateListItem);
|
||||
candidateListLIElement.onclick = (e = getMouseEvent()) =>
|
||||
onItemSelected(candidateListItem, e);
|
||||
|
||||
// Append list item to ul
|
||||
candidateListULElement.appendChild(candidateListLIElement);
|
||||
|
||||
@@ -320,8 +320,10 @@ class SimpleKeyboard {
|
||||
|
||||
const layoutCandidates = Object.keys(layoutCandidatesObj).filter(
|
||||
(layoutCandidate: string) => {
|
||||
const inputSubstr =
|
||||
input.substring(0, this.getCaretPositionEnd() || 0) || input;
|
||||
const regexp = new RegExp(`${layoutCandidate}$`, "g");
|
||||
const matches = [...input.matchAll(regexp)];
|
||||
const matches = [...inputSubstr.matchAll(regexp)];
|
||||
return !!matches.length;
|
||||
}
|
||||
);
|
||||
@@ -359,21 +361,37 @@ class SimpleKeyboard {
|
||||
this.candidateBox.show({
|
||||
candidateValue,
|
||||
targetElement,
|
||||
onSelect: (selectedCandidate: string) => {
|
||||
onSelect: (selectedCandidate: string, e: MouseEvent) => {
|
||||
const currentInput = this.getInput(this.options.inputName, true);
|
||||
const initialCaretPosition = this.getCaretPositionEnd() || 0;
|
||||
const inputSubstr =
|
||||
currentInput.substring(0, initialCaretPosition || 0) ||
|
||||
currentInput;
|
||||
|
||||
const regexp = new RegExp(`${candidateKey}$`, "g");
|
||||
const newInput = currentInput.replace(regexp, selectedCandidate);
|
||||
const newInputSubstr = inputSubstr.replace(regexp, selectedCandidate);
|
||||
const newInput = currentInput.replace(inputSubstr, newInputSubstr);
|
||||
|
||||
const caretPositionDiff = newInputSubstr.length - inputSubstr.length;
|
||||
let newCaretPosition =
|
||||
(initialCaretPosition || currentInput.length) + caretPositionDiff;
|
||||
|
||||
if (newCaretPosition < 0) newCaretPosition = 0;
|
||||
|
||||
this.setInput(newInput, this.options.inputName, true);
|
||||
this.setCaretPosition(newCaretPosition);
|
||||
|
||||
if (typeof this.options.onChange === "function")
|
||||
this.options.onChange(this.getInput(this.options.inputName, true));
|
||||
this.options.onChange(
|
||||
this.getInput(this.options.inputName, true),
|
||||
e
|
||||
);
|
||||
|
||||
/**
|
||||
* Calling onChangeAll
|
||||
*/
|
||||
if (typeof this.options.onChangeAll === "function")
|
||||
this.options.onChangeAll(this.getAllInputs());
|
||||
this.options.onChangeAll(this.getAllInputs(), e);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -429,7 +447,7 @@ class SimpleKeyboard {
|
||||
* Calling onKeyPress
|
||||
*/
|
||||
if (typeof this.options.onKeyPress === "function")
|
||||
this.options.onKeyPress(button);
|
||||
this.options.onKeyPress(button, e);
|
||||
|
||||
if (
|
||||
// If input will change as a result of this button press
|
||||
@@ -483,13 +501,13 @@ class SimpleKeyboard {
|
||||
* Calling onChange
|
||||
*/
|
||||
if (typeof this.options.onChange === "function")
|
||||
this.options.onChange(this.getInput(this.options.inputName, true));
|
||||
this.options.onChange(this.getInput(this.options.inputName, true), e);
|
||||
|
||||
/**
|
||||
* Calling onChangeAll
|
||||
*/
|
||||
if (typeof this.options.onChangeAll === "function")
|
||||
this.options.onChangeAll(this.getAllInputs());
|
||||
this.options.onChangeAll(this.getAllInputs(), e);
|
||||
|
||||
/**
|
||||
* Check if this new input has candidates (suggested words)
|
||||
|
||||
@@ -216,7 +216,7 @@ it('CandidateBox select candidate will work', () => {
|
||||
keyboard.getButtonElement("a").click();
|
||||
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||
|
||||
expect(onSelect).toBeCalledWith("1");
|
||||
expect(onSelect).toBeCalledWith("1", expect.anything());
|
||||
keyboard.destroy();
|
||||
});
|
||||
|
||||
@@ -353,6 +353,7 @@ it('CandidateBox selection should trigger onChange', () => {
|
||||
});
|
||||
|
||||
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
||||
|
||||
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
||||
candidateBoxOnItemSelected = params.onItemSelected;
|
||||
params.onItemSelected = onSelect;
|
||||
@@ -362,10 +363,10 @@ it('CandidateBox selection should trigger onChange', () => {
|
||||
keyboard.getButtonElement("a").click();
|
||||
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||
|
||||
expect(keyboard.options.onChange).toBeCalledWith("a");
|
||||
expect(keyboard.options.onChangeAll).toBeCalledWith({"default": "a"});
|
||||
expect(keyboard.options.onChange.mock.calls[0][0]).toBe("a");
|
||||
expect(keyboard.options.onChangeAll.mock.calls[0][0]).toMatchObject({"default": "a"});
|
||||
|
||||
expect(keyboard.options.onChange).toBeCalledWith("1");
|
||||
expect(keyboard.options.onChangeAll).toBeCalledWith({"default": "1"});
|
||||
expect(keyboard.options.onChange.mock.calls[1][0]).toBe("1");
|
||||
expect(keyboard.options.onChangeAll.mock.calls[1][0]).toMatchObject({"default": "1"});
|
||||
keyboard.destroy();
|
||||
});
|
||||
+12
-2
@@ -31,7 +31,7 @@ export type CandidateBoxShowParams = {
|
||||
candidateValue: string,
|
||||
targetElement: KeyboardElement,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
onSelect: (selectedCandidate: string) => void
|
||||
onSelect: (selectedCandidate: string, e: MouseEvent) => void
|
||||
}
|
||||
|
||||
export type CandidateBoxRenderParams = {
|
||||
@@ -40,7 +40,7 @@ export type CandidateBoxRenderParams = {
|
||||
pageIndex: number;
|
||||
nbPages: number;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
onItemSelected: (selectedCandidate: string) => void
|
||||
onItemSelected: (selectedCandidate: string, e: MouseEvent) => void
|
||||
}
|
||||
|
||||
export type KeyboardElement = HTMLDivElement | HTMLButtonElement;
|
||||
@@ -240,6 +240,16 @@ export interface KeyboardOptions {
|
||||
*/
|
||||
onInit?: (instance?: SimpleKeyboard) => void;
|
||||
|
||||
/**
|
||||
* Retrieves the current input
|
||||
*/
|
||||
onChange?: (input: string, e?: MouseEvent) => any;
|
||||
|
||||
/**
|
||||
* Retrieves all inputs
|
||||
*/
|
||||
onChangeAll?: (inputObj: KeyboardInput, e?: MouseEvent) => any;
|
||||
|
||||
/**
|
||||
* Module options can have any format
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user