mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2025-04-27 00:00:19 +08:00
Address caret positioning issues. Fixes https://github.com/hodgef/simple-keyboard/issues/695 - Fixes https://github.com/hodgef/react-simple-keyboard/issues/788
This commit is contained in:
parent
548cc8d753
commit
8e2339567d
@ -380,19 +380,16 @@ class SimpleKeyboard {
|
||||
* Handles button mouseup
|
||||
*/
|
||||
handleButtonMouseUp(button) {
|
||||
this.dispatch(instance => {
|
||||
/**
|
||||
* Remove active class
|
||||
*/
|
||||
instance.recurseButtons(buttonElement => {
|
||||
buttonElement.classList.remove(this.activeButtonClass);
|
||||
});
|
||||
|
||||
instance.isMouseHold = false;
|
||||
if (instance.holdInteractionTimeout)
|
||||
clearTimeout(instance.holdInteractionTimeout);
|
||||
/**
|
||||
* Remove active class
|
||||
*/
|
||||
this.recurseButtons(buttonElement => {
|
||||
buttonElement.classList.remove(this.activeButtonClass);
|
||||
});
|
||||
|
||||
this.isMouseHold = false;
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
|
||||
/**
|
||||
* Calling onKeyReleased
|
||||
*/
|
||||
@ -543,7 +540,6 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* inputName changed. This requires a caretPosition reset
|
||||
*/
|
||||
// TODO: Review side-effects
|
||||
if (this.options.debug) {
|
||||
console.log("inputName changed. caretPosition reset.");
|
||||
}
|
||||
@ -741,8 +737,6 @@ class SimpleKeyboard {
|
||||
* Handles simple-keyboard event listeners
|
||||
*/
|
||||
setEventListeners() {
|
||||
const { useTouchEvents, useMouseEvents } = this.options;
|
||||
|
||||
/**
|
||||
* Only first instance should set the event listeners
|
||||
*/
|
||||
@ -754,42 +748,10 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Event Listeners
|
||||
*/
|
||||
document.onkeyup = this.handleKeyUp;
|
||||
document.onkeydown = this.handleKeyDown;
|
||||
|
||||
/**
|
||||
* Pointer events
|
||||
*/
|
||||
if (
|
||||
this.utilities.pointerEventsSupported() &&
|
||||
!useTouchEvents &&
|
||||
!useMouseEvents
|
||||
) {
|
||||
document.onpointerdown = this.handlePointerDown;
|
||||
document.onpointerup = this.handlePointerUp;
|
||||
document.onpointercancel = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.onpointerdown = this.handleKeyboardContainerMouseDown;
|
||||
|
||||
/**
|
||||
* Touch events
|
||||
*/
|
||||
} else if (useTouchEvents) {
|
||||
document.ontouchstart = this.handlePointerDown;
|
||||
document.ontouchend = this.handlePointerUp;
|
||||
document.ontouchcancel = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.ontouchstart = this.handleKeyboardContainerMouseDown;
|
||||
|
||||
/**
|
||||
* Mouse events
|
||||
*/
|
||||
} else if (!useTouchEvents) {
|
||||
document.onmousedown = this.handlePointerDown;
|
||||
document.onmouseup = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.onmousedown = this.handleKeyboardContainerMouseDown;
|
||||
}
|
||||
document.addEventListener("keyup", this.handleKeyUp);
|
||||
document.addEventListener("keydown", this.handleKeyDown);
|
||||
document.addEventListener("mouseup", this.handleMouseUp);
|
||||
document.addEventListener("touchend", this.handleTouchEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -814,51 +776,42 @@ class SimpleKeyboard {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Handler: PointerDown
|
||||
* Event Handler: MouseUp
|
||||
*/
|
||||
handlePointerDown(event) {
|
||||
handleMouseUp(event) {
|
||||
this.caretEventHandler(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Handler: PointerUp
|
||||
* Event Handler: TouchEnd
|
||||
*/
|
||||
handlePointerUp(event) {
|
||||
this.handleButtonMouseUp();
|
||||
// TODO: Will need further investigation
|
||||
// https://github.com/hodgef/simple-keyboard/issues/54
|
||||
/* istanbul ignore next */
|
||||
setTimeout(() => {
|
||||
this.caretEventHandler(event);
|
||||
}, 0);
|
||||
/* istanbul ignore next */
|
||||
handleTouchEnd(event) {
|
||||
this.caretEventHandler(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered
|
||||
*/
|
||||
caretEventHandler(event) {
|
||||
if (this.options.disableCaretPositioning) {
|
||||
this.setCaretPosition(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let targetTagName;
|
||||
|
||||
if (event.target.tagName) {
|
||||
targetTagName = event.target.tagName.toLowerCase();
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
this.dispatch(instance => {
|
||||
const isKeyboard =
|
||||
event.target === instance.keyboardDOM ||
|
||||
(event.target && instance.keyboardDOM.contains(event.target));
|
||||
|
||||
// if (!this.isMouseHold) {
|
||||
// instance.isMouseHold = false;
|
||||
// }
|
||||
if (instance.isMouseHold) {
|
||||
instance.isMouseHold = false;
|
||||
}
|
||||
|
||||
if (targetTagName === "textarea" || targetTagName === "input") {
|
||||
if (
|
||||
(targetTagName === "textarea" || targetTagName === "input") &&
|
||||
!instance.options.disableCaretPositioning
|
||||
) {
|
||||
/**
|
||||
* Tracks current cursor position
|
||||
* As keys are pressed, text will be added/removed at that position within the input.
|
||||
@ -877,9 +830,10 @@ class SimpleKeyboard {
|
||||
`(${instance.keyboardDOMClass})`
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Review side-effects
|
||||
} else if (!isKeyboard) {
|
||||
} else if (instance.options.disableCaretPositioning || !isKeyboard) {
|
||||
/**
|
||||
* If we toggled off disableCaretPositioning, we must ensure caretPosition doesn't persist once reactivated.
|
||||
*/
|
||||
instance.setCaretPosition(null);
|
||||
}
|
||||
});
|
||||
@ -905,6 +859,18 @@ class SimpleKeyboard {
|
||||
`Destroying simple-keyboard instance: ${this.currentInstanceName}`
|
||||
);
|
||||
|
||||
/**
|
||||
* Remove document listeners
|
||||
*/
|
||||
document.removeEventListener("keyup", this.handleKeyUp);
|
||||
document.removeEventListener("keydown", this.handleKeyDown);
|
||||
document.removeEventListener("mouseup", this.handleMouseUp);
|
||||
document.removeEventListener("touchend", this.handleTouchEnd);
|
||||
document.onpointerup = null;
|
||||
document.ontouchend = null;
|
||||
document.ontouchcancel = null;
|
||||
document.onmouseup = null;
|
||||
|
||||
/**
|
||||
* Remove buttons
|
||||
*/
|
||||
@ -924,6 +890,8 @@ class SimpleKeyboard {
|
||||
};
|
||||
|
||||
this.recurseButtons(deleteButton);
|
||||
|
||||
this.recurseButtons = null;
|
||||
deleteButton = null;
|
||||
|
||||
/**
|
||||
@ -938,55 +906,12 @@ class SimpleKeyboard {
|
||||
*/
|
||||
this.clear();
|
||||
|
||||
/**
|
||||
* Remove timouts
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
/* istanbul ignore next */
|
||||
if (this.holdTimeout) clearTimeout(this.holdTimeout);
|
||||
|
||||
/**
|
||||
* Remove instance
|
||||
*/
|
||||
window["SimpleKeyboardInstances"][this.currentInstanceName] = null;
|
||||
delete window["SimpleKeyboardInstances"][this.currentInstanceName];
|
||||
|
||||
/**
|
||||
* Removing document listeners if there are no more instances
|
||||
*/
|
||||
if (!Object.keys(window["SimpleKeyboardInstances"]).length) {
|
||||
/**
|
||||
* Remove document listeners
|
||||
*/
|
||||
document.onkeydown = null;
|
||||
document.onkeyup = null;
|
||||
|
||||
document.onpointerdown = null;
|
||||
document.onpointerup = null;
|
||||
|
||||
document.onmousedown = null;
|
||||
document.onmouseup = null;
|
||||
|
||||
document.ontouchstart = null;
|
||||
document.ontouchend = null;
|
||||
document.ontouchcancel = null;
|
||||
|
||||
if (this.options.debug) {
|
||||
console.log(
|
||||
"Destroy: No instances remaining. Document listeners removed",
|
||||
window["SimpleKeyboardInstances"]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (this.options.debug) {
|
||||
console.log(
|
||||
"Destroy: Instances remaining! Document listeners not removed",
|
||||
window["SimpleKeyboardInstances"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset initialized flag
|
||||
*/
|
||||
@ -1500,6 +1425,7 @@ class SimpleKeyboard {
|
||||
* Handle mouse events
|
||||
*/
|
||||
buttonDOM.onclick = () => {
|
||||
this.isMouseHold = false;
|
||||
this.handleButtonClicked(button);
|
||||
};
|
||||
buttonDOM.onmousedown = e => {
|
||||
@ -1570,6 +1496,36 @@ class SimpleKeyboard {
|
||||
*/
|
||||
this.initialized = true;
|
||||
|
||||
/**
|
||||
* Handling parent events
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
this.utilities.pointerEventsSupported() &&
|
||||
!useTouchEvents &&
|
||||
!useMouseEvents
|
||||
) {
|
||||
document.onpointerup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onpointerdown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (useTouchEvents) {
|
||||
/**
|
||||
* Handling ontouchend, ontouchcancel
|
||||
*/
|
||||
document.ontouchend = () => this.handleButtonMouseUp();
|
||||
document.ontouchcancel = () => this.handleButtonMouseUp();
|
||||
|
||||
this.keyboardDOM.ontouchstart = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (!useTouchEvents) {
|
||||
/**
|
||||
* Handling mouseup
|
||||
*/
|
||||
document.onmouseup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onmousedown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling onInit
|
||||
*/
|
||||
|
@ -590,13 +590,15 @@ it('Keyboard will receive physical keyboard events', () => {
|
||||
physicalKeyboardHighlight: true
|
||||
});
|
||||
|
||||
document.onkeyup({
|
||||
document.dispatchEvent(new KeyboardEvent('keyup', {
|
||||
charCode: 0,
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: document.createElement('input')
|
||||
});
|
||||
target: {
|
||||
tagName: "input"
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler will detect input, textarea focus', () => {
|
||||
@ -1224,15 +1226,15 @@ it('Keyboard destroy will work', () => {
|
||||
expect(document.onkeydown).toBe(null);
|
||||
expect(document.onkeyup).toBe(null);
|
||||
|
||||
expect(document.onpointerdown).toBe(null);
|
||||
expect(document.onpointerup).toBe(null);
|
||||
// expect(document.onpointerdown).toBe(null);
|
||||
// expect(document.onpointerup).toBe(null);
|
||||
|
||||
expect(document.onmousedown).toBe(null);
|
||||
expect(document.onmouseup).toBe(null);
|
||||
// expect(document.onmousedown).toBe(null);
|
||||
// expect(document.onmouseup).toBe(null);
|
||||
|
||||
expect(document.ontouchstart).toBe(null);
|
||||
expect(document.ontouchend).toBe(null);
|
||||
expect(document.ontouchcancel).toBe(null);
|
||||
// expect(document.ontouchstart).toBe(null);
|
||||
// expect(document.ontouchend).toBe(null);
|
||||
// expect(document.ontouchcancel).toBe(null);
|
||||
|
||||
expect(keyboard.initialized).toBe(false);
|
||||
});
|
||||
@ -1262,10 +1264,8 @@ it('Keyboard caretEventHandler will be triggered on mouseup and ontouchend', ()
|
||||
disableCaretPositioning: true
|
||||
});
|
||||
|
||||
// TODO: Will need further investigation
|
||||
// https://github.com/hodgef/simple-keyboard/issues/54
|
||||
// keyboard.setCaretPosition(6);
|
||||
// expect(keyboard.getCaretPosition()).toBe(6);
|
||||
keyboard.setCaretPosition(6);
|
||||
expect(keyboard.getCaretPosition()).toBe(6);
|
||||
|
||||
const event = {
|
||||
target: document.body
|
||||
@ -1381,17 +1381,32 @@ it('Keyboard handleKeyboardContainerMouseDown will respect preventMouseDownDefau
|
||||
expect(works).toBe(true);
|
||||
});
|
||||
|
||||
it('Keyboard handlePointerDown will work', () => {
|
||||
it('Keyboard caret positioning will work', () => {
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
const keyboard = new Keyboard({
|
||||
onKeyPress: (button) => {
|
||||
if (button === "{shift}" || button === "{lock}") handleShift();
|
||||
else if (keyboard.options.layoutName === "shift") handleShift();
|
||||
}
|
||||
});
|
||||
|
||||
keyboard.setCaretPosition(3);
|
||||
expect(keyboard.getCaretPosition()).toBe(3);
|
||||
function handleShift() {
|
||||
const currentLayout = keyboard.options.layoutName;
|
||||
const shiftToggle = currentLayout === "default" ? "shift" : "default";
|
||||
|
||||
keyboard.setOptions({
|
||||
layoutName: shiftToggle
|
||||
});
|
||||
}
|
||||
|
||||
triggerDocumentPointerDown({
|
||||
target: document.body
|
||||
})
|
||||
keyboard.getButtonElement("h").onpointerdown();
|
||||
keyboard.getButtonElement("o").onpointerdown();
|
||||
keyboard.setCaretPosition(1);
|
||||
keyboard.getButtonElement("{shift}")[0].onpointerdown();
|
||||
keyboard.getButtonElement("E").onpointerdown();
|
||||
keyboard.getButtonElement("l").onpointerdown();
|
||||
keyboard.getButtonElement("l").onpointerdown();
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(null);
|
||||
expect(keyboard.getInput()).toBe("hEllo");
|
||||
});
|
@ -26,13 +26,17 @@
|
||||
/**
|
||||
* Trigger pointerup
|
||||
*/
|
||||
export const triggerDocumentPointerUp = (e = {}) => (document.onpointerup || document.onmouseup || document.ontouchstart)(e);
|
||||
export const triggerDocumentPointerUp = (e = {}) => {
|
||||
document.dispatchEvent(new MouseEvent('mouseup', e));
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger pointerdown
|
||||
*/
|
||||
export const triggerDocumentPointerDown = (e = {}) => (document.onpointerdown || document.onmousedown || document.ontouchend)(e);
|
||||
|
||||
export const triggerDocumentPointerDown = (e = {}) => {
|
||||
document.dispatchEvent(new MouseEvent('mousedown', e));
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if standard buttons respect maxLength and do input a value
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user