Fix action directive double tab iOS issues (#4639)

This commit is contained in:
Bram Kragten 2020-01-29 19:03:43 +01:00 committed by GitHub
parent 7ab9257f5e
commit dd8c568a2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,5 +1,7 @@
import { directive, PropertyPart } from "lit-html"; import { directive, PropertyPart } from "lit-html";
import "@material/mwc-ripple"; import "@material/mwc-ripple";
// tslint:disable-next-line
import { Ripple } from "@material/mwc-ripple";
import { import {
ActionHandlerOptions, ActionHandlerOptions,
ActionHandlerDetail, ActionHandlerDetail,
@ -26,22 +28,16 @@ declare global {
} }
class ActionHandler extends HTMLElement implements ActionHandler { class ActionHandler extends HTMLElement implements ActionHandler {
public holdTime: number; public holdTime = 500;
public ripple: any; public ripple: Ripple;
protected timer: number | undefined; protected timer?: number;
protected held: boolean; protected held = false;
protected cooldownStart: boolean; protected touch?: boolean;
protected cooldownEnd: boolean; private dblClickTimeout?: number;
private dblClickTimeout: number | undefined;
constructor() { constructor() {
super(); super();
this.holdTime = 500;
this.ripple = document.createElement("mwc-ripple"); this.ripple = document.createElement("mwc-ripple");
this.timer = undefined;
this.held = false;
this.cooldownStart = false;
this.cooldownEnd = false;
} }
public connectedCallback() { public connectedCallback() {
@ -96,10 +92,23 @@ class ActionHandler extends HTMLElement implements ActionHandler {
return false; return false;
}); });
const clickStart = (ev: Event) => { const touchStart = (ev: TouchEvent) => {
if (this.cooldownStart) { if (this.touch === false) {
return; return;
} }
this.touch = true;
start(ev);
};
const clickStart = (ev: MouseEvent) => {
if (this.touch === true) {
return;
}
this.touch = false;
start(ev);
};
const start = (ev: Event) => {
this.held = false; this.held = false;
let x; let x;
let y; let y;
@ -115,16 +124,34 @@ class ActionHandler extends HTMLElement implements ActionHandler {
this.startAnimation(x, y); this.startAnimation(x, y);
this.held = true; this.held = true;
}, this.holdTime); }, this.holdTime);
this.cooldownStart = true;
window.setTimeout(() => (this.cooldownStart = false), 100);
}; };
const clickEnd = (ev: Event) => { const touchEnd = (ev: TouchEvent) => {
if (this.touch === false) {
return;
}
end(ev);
};
const clickEnd = (ev: MouseEvent) => {
if (this.touch === true) {
return;
}
end(ev);
};
const handleEnter = (ev: KeyboardEvent) => {
if (this.touch === true || ev.keyCode !== 13) {
return;
}
this.touch = false;
end(ev);
};
const end = (ev: Event) => {
if ( if (
this.cooldownEnd || ["touchend", "touchcancel"].includes(ev.type) &&
(["touchend", "touchcancel"].includes(ev.type) && this.timer === undefined
this.timer === undefined)
) { ) {
return; return;
} }
@ -134,41 +161,33 @@ class ActionHandler extends HTMLElement implements ActionHandler {
if (this.held) { if (this.held) {
fireEvent(element, "action", { action: "hold" }); fireEvent(element, "action", { action: "hold" });
} else if (options.hasDoubleClick) { } else if (options.hasDoubleClick) {
if ((ev as MouseEvent).detail === 1 || ev.type === "keyup") { if (
(ev.type === "click" && (ev as MouseEvent).detail < 2) ||
!this.dblClickTimeout
) {
this.dblClickTimeout = window.setTimeout(() => { this.dblClickTimeout = window.setTimeout(() => {
this.dblClickTimeout = undefined;
fireEvent(element, "action", { action: "tap" }); fireEvent(element, "action", { action: "tap" });
}, 250); }, 250);
} else { } else {
clearTimeout(this.dblClickTimeout); clearTimeout(this.dblClickTimeout);
this.dblClickTimeout = undefined;
fireEvent(element, "action", { action: "double_tap" }); fireEvent(element, "action", { action: "double_tap" });
} }
} else { } else {
fireEvent(element, "action", { action: "tap" }); fireEvent(element, "action", { action: "tap" });
} }
this.cooldownEnd = true; window.setTimeout(() => (this.touch = undefined), 100);
window.setTimeout(() => (this.cooldownEnd = false), 100);
}; };
const handleEnter = (ev: Event) => { element.addEventListener("touchstart", touchStart, { passive: true });
if ((ev as KeyboardEvent).keyCode === 13) { element.addEventListener("touchend", touchEnd);
return clickEnd(ev); element.addEventListener("touchcancel", touchEnd);
}
}; element.addEventListener("mousedown", clickStart, { passive: true });
element.addEventListener("click", clickEnd);
element.addEventListener("touchstart", clickStart, { passive: true });
element.addEventListener("touchend", clickEnd);
element.addEventListener("touchcancel", clickEnd);
element.addEventListener("keyup", handleEnter); element.addEventListener("keyup", handleEnter);
// iOS 13 sends a complete normal touchstart-touchend series of events followed by a mousedown-click series.
// That might be a bug, but until it's fixed, this should make action-handler work.
// If it's not a bug that is fixed, this might need updating with the next iOS version.
// Note that all events (both touch and mouse) must be listened for in order to work on computers with both mouse and touchscreen.
const isIOS13 = /iPhone OS 13_/.test(window.navigator.userAgent);
if (!isIOS13) {
element.addEventListener("mousedown", clickStart, { passive: true });
element.addEventListener("click", clickEnd);
}
} }
private startAnimation(x: number, y: number) { private startAnimation(x: number, y: number) {