mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:20:47 +00:00
fix(client): block Safari page-level pinch-zoom (#3901)
iOS Safari has ignored the `user-scalable=no` viewport hint since iOS 10, so two-finger pinch still zooms the whole page and can softlock the in-game HUD. Intercept WebKit's non-standard `gesturestart`, `gesturechange` and `gestureend` events at `document` and call `preventDefault()` so the page stays put. The game's own pinch-to-zoom on the map canvas is driven by pointer events (InputHandler) and is unaffected; browsers that do not fire GestureEvent treat the listeners as a no-op. Resolves #2330 If this PR fixes an issue, link it below. If not, delete these two lines. Resolves #(issue number) ## Description: Describe the PR. ## Please complete the following: - [ ] I have added screenshots for all UI updates - [ ] I process any text displayed to the user through translateText() and I've added it to the en.json file - [ ] I have added relevant tests to the test directory - [ ] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: DISCORD_USERNAME
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { installSafariPinchZoomBlocker } from "../../src/client/utilities/DisableSafariPinchZoom";
|
||||
|
||||
const GESTURE_EVENTS = ["gesturestart", "gesturechange", "gestureend"] as const;
|
||||
|
||||
function dispatchCancelableGestureEvent(
|
||||
target: EventTarget,
|
||||
type: string,
|
||||
): Event {
|
||||
// Safari's GestureEvent is not available in jsdom. Dispatch a plain
|
||||
// cancelable Event of the same name so preventDefault() is observable via
|
||||
// defaultPrevented.
|
||||
const event = new Event(type, { bubbles: true, cancelable: true });
|
||||
target.dispatchEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
describe("installSafariPinchZoomBlocker", () => {
|
||||
it("prevents the default action of each Safari gesture event on document", () => {
|
||||
const uninstall = installSafariPinchZoomBlocker();
|
||||
|
||||
try {
|
||||
for (const type of GESTURE_EVENTS) {
|
||||
const event = dispatchCancelableGestureEvent(document, type);
|
||||
expect(event.defaultPrevented).toBe(true);
|
||||
}
|
||||
} finally {
|
||||
uninstall();
|
||||
}
|
||||
});
|
||||
|
||||
it("attaches listeners to the provided target", () => {
|
||||
const target = document.createElement("div");
|
||||
const uninstall = installSafariPinchZoomBlocker(target);
|
||||
|
||||
try {
|
||||
for (const type of GESTURE_EVENTS) {
|
||||
const event = dispatchCancelableGestureEvent(target, type);
|
||||
expect(event.defaultPrevented).toBe(true);
|
||||
}
|
||||
} finally {
|
||||
uninstall();
|
||||
}
|
||||
});
|
||||
|
||||
it("removes the listeners when the returned disposer is called", () => {
|
||||
const target = document.createElement("div");
|
||||
const uninstall = installSafariPinchZoomBlocker(target);
|
||||
uninstall();
|
||||
|
||||
for (const type of GESTURE_EVENTS) {
|
||||
const event = dispatchCancelableGestureEvent(target, type);
|
||||
expect(event.defaultPrevented).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("does not affect events on unrelated targets", () => {
|
||||
const scope = document.createElement("div");
|
||||
const other = document.createElement("div");
|
||||
const uninstall = installSafariPinchZoomBlocker(scope);
|
||||
|
||||
try {
|
||||
const event = dispatchCancelableGestureEvent(other, "gesturestart");
|
||||
expect(event.defaultPrevented).toBe(false);
|
||||
} finally {
|
||||
uninstall();
|
||||
}
|
||||
});
|
||||
|
||||
it("leaves unrelated event types alone", () => {
|
||||
const uninstall = installSafariPinchZoomBlocker();
|
||||
|
||||
try {
|
||||
const event = new Event("touchstart", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
expect(event.defaultPrevented).toBe(false);
|
||||
} finally {
|
||||
uninstall();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user