FIX: allows modals to disable swipe to close (#26460)

Prior to this fix the `swipe` modifier could not be disabled and we were not using the `this.dimissable` property to apply/not apply it.

This commit adds a new `enabled` param to the `swipe` modifier, which is used in modals with the value of `this.dismissable`.

Note this commit also adds tests for this modifier.
This commit is contained in:
Joffrey JAFFEUX 2024-04-02 11:11:32 +02:00 committed by GitHub
parent 9182501366
commit defd63d20b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 104 additions and 10 deletions

View File

@ -302,9 +302,9 @@ export default class DModal extends Component {
<div <div
class={{concatClass "d-modal__header" @headerClass}} class={{concatClass "d-modal__header" @headerClass}}
{{swipe {{swipe
didStartSwipe=this.handleSwipeStarted
didSwipe=this.handleSwipe didSwipe=this.handleSwipe
didEndSwipe=this.handleSwipeEnded didEndSwipe=this.handleSwipeEnded
enabled=this.dismissable
}} }}
> >
{{yield to="headerAboveTitle"}} {{yield to="headerAboveTitle"}}
@ -396,9 +396,9 @@ export default class DModal extends Component {
<div <div
class="d-modal__backdrop" class="d-modal__backdrop"
{{swipe {{swipe
didStartSwipe=this.handleSwipeStarted
didSwipe=this.handleSwipe didSwipe=this.handleSwipe
didEndSwipe=this.handleSwipeEnded didEndSwipe=this.handleSwipeEnded
enabled=this.dismissable
}} }}
{{on "click" this.handleWrapperClick}} {{on "click" this.handleWrapperClick}}
></div> ></div>

View File

@ -26,10 +26,11 @@ export default class SwipeModifier extends Modifier {
* @type {Element} * @type {Element}
*/ */
element; element;
enabled = true;
constructor(owner, args) { constructor(owner, args) {
super(owner, args); super(owner, args);
registerDestructor(this, (instance) => instance.cleanup(instance.element)); registerDestructor(this, (instance) => instance.cleanup());
} }
/** /**
@ -41,8 +42,14 @@ export default class SwipeModifier extends Modifier {
* @param {Function} options.didStartSwipe Callback to be executed when a swipe starts. * @param {Function} options.didStartSwipe Callback to be executed when a swipe starts.
* @param {Function} options.didSwipe Callback to be executed when a swipe moves. * @param {Function} options.didSwipe Callback to be executed when a swipe moves.
* @param {Function} options.didEndSwipe Callback to be executed when a swipe ends. * @param {Function} options.didEndSwipe Callback to be executed when a swipe ends.
* @param {Boolean} options.enabled Enable or disable the swipe modifier.
*/ */
modify(element, _, { didStartSwipe, didSwipe, didEndSwipe }) { modify(element, _, { didStartSwipe, didSwipe, didEndSwipe, enabled }) {
if (enabled === false) {
this.enabled = enabled;
return;
}
this.element = element; this.element = element;
this.didSwipeCallback = didSwipe; this.didSwipeCallback = didSwipe;
this.didStartSwipeCallback = didStartSwipe; this.didStartSwipeCallback = didStartSwipe;
@ -121,12 +128,14 @@ export default class SwipeModifier extends Modifier {
/** /**
* Cleans up the modifier by removing event listeners from the element. * Cleans up the modifier by removing event listeners from the element.
*
* @param {Element} element The DOM element from which to remove event listeners.
*/ */
cleanup(element) { cleanup() {
element.removeEventListener("touchstart", this.handleTouchStart); if (!this.enabled) {
element.removeEventListener("touchmove", this.handleTouchMove); return;
element.removeEventListener("touchend", this.handleTouchEnd); }
this.element?.removeEventListener("touchstart", this.handleTouchStart);
this.element?.removeEventListener("touchmove", this.handleTouchMove);
this.element?.removeEventListener("touchend", this.handleTouchEnd);
} }
} }

View File

@ -0,0 +1,85 @@
import { render, triggerEvent } from "@ember/test-helpers";
import { setupRenderingTest } from "ember-qunit";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
module("Integration | Modifier | swipe", function (hooks) {
setupRenderingTest(hooks);
test("it calls didStartSwipe on touchstart", async function (assert) {
this.didStartSwipe = (state) => {
assert.ok(state, "didStartSwipe called with state");
};
await render(hbs`<div {{swipe didStartSwipe=this.didStartSwipe}}></div>`);
await triggerEvent("div", "touchstart", {
touches: [{ clientX: 0, clientY: 0 }],
});
});
test("it calls didSwipe on touchmove", async function (assert) {
this.didSwipe = (state) => {
assert.ok(state, "didSwipe called with state");
};
await render(hbs`<div {{swipe didSwipe=this.didSwipe}}></div>`);
await triggerEvent("div", "touchstart", {
touches: [{ clientX: 0, clientY: 0 }],
changedTouches: [{ clientX: 0, clientY: 0 }],
});
await triggerEvent("div", "touchmove", {
touches: [{ clientX: 5, clientY: 5 }],
});
});
test("it calls didEndSwipe on touchend", async function (assert) {
this.didEndSwipe = (state) => {
assert.ok(state, "didEndSwipe called with state");
};
await render(hbs`<div {{swipe didEndSwipe=this.didEndSwipe}}></div>`);
await triggerEvent("div", "touchstart", {
touches: [{ clientX: 0, clientY: 0 }],
changedTouches: [{ clientX: 0, clientY: 0 }],
});
await triggerEvent("div", "touchmove", {
touches: [{ clientX: 10, clientY: 0 }],
changedTouches: [{ clientX: 10, clientY: 0 }],
});
await triggerEvent("div", "touchend", {
changedTouches: [{ clientX: 10, clientY: 0 }],
});
});
test("it does not trigger when disabled", async function (assert) {
let calls = 0;
this.didStartSwipe = () => {
calls++;
};
this.set("isEnabled", false);
await render(
hbs`<div {{swipe didStartSwipe=this.didStartSwipe enabled=this.isEnabled}}></div>`
);
await triggerEvent("div", "touchstart", {
touches: [{ clientX: 0, clientY: 0 }],
});
this.set("isEnabled", true);
await triggerEvent("div", "touchstart", {
touches: [{ clientX: 0, clientY: 0 }],
});
assert.deepEqual(calls, 1, "didStartSwipe should be called once");
});
});