mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2025-04-24 05:20:22 +08:00
Merge pull request #2277 from XcrossD/patch-1
Expose a method to change keyboard instance internal state before input value change
This commit is contained in:
commit
20b4fd5ca3
@ -118,6 +118,7 @@ class SimpleKeyboard {
|
|||||||
* @property {function(input: string):string} onChange Executes the callback function on input change. Returns the current input’s string.
|
* @property {function(input: string):string} onChange Executes the callback function on input change. Returns the current input’s string.
|
||||||
* @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
|
* @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
|
||||||
* @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
|
* @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
|
||||||
|
* @property {function(keyboard: Keyboard):void} beforeInputUpdate Perform an action before any input change
|
||||||
* @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs.
|
* @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs.
|
||||||
* @property {boolean} useButtonTag Render buttons as a button element instead of a div element.
|
* @property {boolean} useButtonTag Render buttons as a button element instead of a div element.
|
||||||
* @property {boolean} disableCaretPositioning A prop to ensure characters are always be added/removed at the end of the string.
|
* @property {boolean} disableCaretPositioning A prop to ensure characters are always be added/removed at the end of the string.
|
||||||
@ -393,6 +394,13 @@ class SimpleKeyboard {
|
|||||||
candidateStr = selectedCandidate.normalize("NFD");
|
candidateStr = selectedCandidate.normalize("NFD");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an action before any input change
|
||||||
|
*/
|
||||||
|
if (typeof this.options.beforeInputUpdate === "function") {
|
||||||
|
this.options.beforeInputUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
const currentInput = this.getInput(this.options.inputName, true);
|
const currentInput = this.getInput(this.options.inputName, true);
|
||||||
const initialCaretPosition = this.getCaretPositionEnd() || 0;
|
const initialCaretPosition = this.getCaretPositionEnd() || 0;
|
||||||
const inputSubstr =
|
const inputSubstr =
|
||||||
@ -458,6 +466,13 @@ class SimpleKeyboard {
|
|||||||
*/
|
*/
|
||||||
if (!this.input[inputName]) this.input[inputName] = "";
|
if (!this.input[inputName]) this.input[inputName] = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an action before any input change
|
||||||
|
*/
|
||||||
|
if (typeof this.options.beforeInputUpdate === "function") {
|
||||||
|
this.options.beforeInputUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculating new input
|
* Calculating new input
|
||||||
*/
|
*/
|
||||||
|
@ -332,98 +332,133 @@ it('CandidateBox show not be called if keyboard.candidateBox is undefined upon s
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('CandidateBox selection should trigger onChange', () => {
|
it('CandidateBox selection should trigger onChange', () => {
|
||||||
const keyboard = new Keyboard({
|
const keyboard = new Keyboard({
|
||||||
layout: {
|
layout: {
|
||||||
default: [
|
default: [
|
||||||
"a b {bksp}"
|
"a b {bksp}"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
layoutCandidates: {
|
layoutCandidates: {
|
||||||
a: "1 2 3 4 5 6"
|
a: "1 2 3 4 5 6"
|
||||||
},
|
},
|
||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
onChangeAll: jest.fn()
|
onChangeAll: jest.fn()
|
||||||
});
|
|
||||||
|
|
||||||
let candidateBoxOnItemSelected;
|
|
||||||
|
|
||||||
const onSelect = jest.fn().mockImplementation((selectedCandidate) => {
|
|
||||||
candidateBoxOnItemSelected(selectedCandidate);
|
|
||||||
keyboard.candidateBox.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
|
||||||
|
|
||||||
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
|
||||||
candidateBoxOnItemSelected = params.onItemSelected;
|
|
||||||
params.onItemSelected = onSelect;
|
|
||||||
candidateBoxRenderFn(params);
|
|
||||||
});
|
|
||||||
|
|
||||||
keyboard.getButtonElement("a").click();
|
|
||||||
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
|
||||||
|
|
||||||
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.mock.calls[1][0]).toBe("1");
|
|
||||||
expect(keyboard.options.onChangeAll.mock.calls[1][0]).toMatchObject({"default": "1"});
|
|
||||||
keyboard.destroy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('CandidateBox normalization will work', () => {
|
let candidateBoxOnItemSelected;
|
||||||
const keyboard = new Keyboard({
|
|
||||||
layout: {
|
|
||||||
default: [
|
|
||||||
"a b {bksp}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
layoutCandidates: {
|
|
||||||
a: "신"
|
|
||||||
},
|
|
||||||
onChange: jest.fn(),
|
|
||||||
onChangeAll: jest.fn()
|
|
||||||
});
|
|
||||||
|
|
||||||
let candidateBoxOnItemSelected;
|
const onSelect = jest.fn().mockImplementation((selectedCandidate) => {
|
||||||
|
candidateBoxOnItemSelected(selectedCandidate);
|
||||||
const onSelect = jest.fn().mockImplementation((selectedCandidate) => {
|
keyboard.candidateBox.destroy();
|
||||||
candidateBoxOnItemSelected(selectedCandidate);
|
});
|
||||||
keyboard.candidateBox.destroy();
|
|
||||||
});
|
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
||||||
|
|
||||||
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
||||||
|
candidateBoxOnItemSelected = params.onItemSelected;
|
||||||
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
params.onItemSelected = onSelect;
|
||||||
candidateBoxOnItemSelected = params.onItemSelected;
|
candidateBoxRenderFn(params);
|
||||||
params.onItemSelected = onSelect;
|
});
|
||||||
candidateBoxRenderFn(params);
|
|
||||||
});
|
keyboard.getButtonElement("a").click();
|
||||||
|
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||||
|
|
||||||
|
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.mock.calls[1][0]).toBe("1");
|
||||||
|
expect(keyboard.options.onChangeAll.mock.calls[1][0]).toMatchObject({"default": "1"});
|
||||||
|
keyboard.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('CandidateBox selection should trigger beforeInputChange', () => {
|
||||||
|
const keyboard = new Keyboard({
|
||||||
|
layout: {
|
||||||
|
default: [
|
||||||
|
"a b {bksp}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
layoutCandidates: {
|
||||||
|
a: "1 2 3 4 5 6"
|
||||||
|
},
|
||||||
|
beforeInputUpdate: jest.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let candidateBoxOnItemSelected;
|
||||||
|
|
||||||
keyboard.getButtonElement("a").click();
|
const onSelect = jest.fn().mockImplementation((selectedCandidate) => {
|
||||||
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
candidateBoxOnItemSelected(selectedCandidate);
|
||||||
|
keyboard.candidateBox.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
||||||
|
|
||||||
expect(keyboard.options.onChange.mock.calls[0][0]).toBe("a");
|
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
||||||
expect(keyboard.options.onChangeAll.mock.calls[0][0]).toMatchObject({"default": "a"});
|
candidateBoxOnItemSelected = params.onItemSelected;
|
||||||
|
params.onItemSelected = onSelect;
|
||||||
|
candidateBoxRenderFn(params);
|
||||||
|
});
|
||||||
|
|
||||||
// Selected candidate will be normalized
|
keyboard.getButtonElement("a").click();
|
||||||
expect(keyboard.options.onChange.mock.calls[1][0]).toBe("신");
|
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||||
expect(keyboard.options.onChange.mock.calls[1][0].length).toBe(3);
|
|
||||||
expect(keyboard.options.onChangeAll.mock.calls[1][0]).toMatchObject({"default": "신"});
|
|
||||||
|
|
||||||
// Selected candidate will not be normalized
|
expect(keyboard.options.beforeInputUpdate.mock.calls[0][0]).toMatchObject(keyboard);
|
||||||
keyboard.clearInput();
|
keyboard.destroy();
|
||||||
keyboard.setOptions({ disableCandidateNormalization: true });
|
});
|
||||||
|
|
||||||
keyboard.getButtonElement("a").click();
|
it('CandidateBox normalization will work', () => {
|
||||||
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
const keyboard = new Keyboard({
|
||||||
|
layout: {
|
||||||
|
default: [
|
||||||
|
"a b {bksp}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
layoutCandidates: {
|
||||||
|
a: "신"
|
||||||
|
},
|
||||||
|
onChange: jest.fn(),
|
||||||
|
onChangeAll: jest.fn()
|
||||||
|
});
|
||||||
|
|
||||||
|
let candidateBoxOnItemSelected;
|
||||||
|
|
||||||
expect(keyboard.options.onChange.mock.calls[2][0]).toBe("a");
|
const onSelect = jest.fn().mockImplementation((selectedCandidate) => {
|
||||||
expect(keyboard.options.onChangeAll.mock.calls[2][0]).toMatchObject({"default": "a"});
|
candidateBoxOnItemSelected(selectedCandidate);
|
||||||
|
keyboard.candidateBox.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
expect(keyboard.options.onChange.mock.calls[3][0]).toBe("신");
|
const candidateBoxRenderFn = keyboard.candidateBox.renderPage;
|
||||||
expect(keyboard.options.onChange.mock.calls[3][0].length).toBe(1);
|
|
||||||
expect(keyboard.options.onChangeAll.mock.calls[3][0]).toMatchObject({"default": "신"});
|
jest.spyOn(keyboard.candidateBox, "renderPage").mockImplementation((params) => {
|
||||||
|
candidateBoxOnItemSelected = params.onItemSelected;
|
||||||
|
params.onItemSelected = onSelect;
|
||||||
|
candidateBoxRenderFn(params);
|
||||||
|
});
|
||||||
|
|
||||||
keyboard.destroy();
|
keyboard.getButtonElement("a").click();
|
||||||
});
|
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||||
|
|
||||||
|
expect(keyboard.options.onChange.mock.calls[0][0]).toBe("a");
|
||||||
|
expect(keyboard.options.onChangeAll.mock.calls[0][0]).toMatchObject({"default": "a"});
|
||||||
|
|
||||||
|
// Selected candidate will be normalized
|
||||||
|
expect(keyboard.options.onChange.mock.calls[1][0]).toBe("신");
|
||||||
|
expect(keyboard.options.onChange.mock.calls[1][0].length).toBe(3);
|
||||||
|
expect(keyboard.options.onChangeAll.mock.calls[1][0]).toMatchObject({"default": "신"});
|
||||||
|
|
||||||
|
// Selected candidate will not be normalized
|
||||||
|
keyboard.clearInput();
|
||||||
|
keyboard.setOptions({ disableCandidateNormalization: true });
|
||||||
|
|
||||||
|
keyboard.getButtonElement("a").click();
|
||||||
|
keyboard.candidateBox.candidateBoxElement.querySelector("li").click();
|
||||||
|
|
||||||
|
expect(keyboard.options.onChange.mock.calls[2][0]).toBe("a");
|
||||||
|
expect(keyboard.options.onChangeAll.mock.calls[2][0]).toMatchObject({"default": "a"});
|
||||||
|
|
||||||
|
expect(keyboard.options.onChange.mock.calls[3][0]).toBe("신");
|
||||||
|
expect(keyboard.options.onChange.mock.calls[3][0].length).toBe(1);
|
||||||
|
expect(keyboard.options.onChangeAll.mock.calls[3][0]).toMatchObject({"default": "신"});
|
||||||
|
|
||||||
|
keyboard.destroy();
|
||||||
|
});
|
@ -218,6 +218,19 @@ it('Keyboard onChange will work', () => {
|
|||||||
expect(output).toBe("q");
|
expect(output).toBe("q");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Keyboard beforeInputChange will work', () => {
|
||||||
|
const mockBeforeInputUpdate = jest.fn();
|
||||||
|
|
||||||
|
const keyboard = new Keyboard({
|
||||||
|
beforeInputUpdate: mockBeforeInputUpdate,
|
||||||
|
useMouseEvents: true
|
||||||
|
});
|
||||||
|
|
||||||
|
keyboard.getButtonElement("q").onclick();
|
||||||
|
|
||||||
|
expect(mockBeforeInputUpdate).toHaveBeenCalledWith(keyboard);
|
||||||
|
});
|
||||||
|
|
||||||
it('Keyboard onChangeAll will work', () => {
|
it('Keyboard onChangeAll will work', () => {
|
||||||
let output;
|
let output;
|
||||||
|
|
||||||
|
@ -291,6 +291,11 @@ export interface KeyboardOptions {
|
|||||||
*/
|
*/
|
||||||
onKeyReleased?: (button: string, e?: MouseEvent) => any;
|
onKeyReleased?: (button: string, e?: MouseEvent) => any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the callback function before an input is about to be updated
|
||||||
|
*/
|
||||||
|
beforeInputUpdate?: (instance: SimpleKeyboard) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module options can have any format
|
* Module options can have any format
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user