From 34ddcab07f8f8f11c5c8c5f1df98e7da7e2495a0 Mon Sep 17 00:00:00 2001 From: Jorge Pinna Puissant Date: Mon, 8 Aug 2022 09:08:09 +0000 Subject: [PATCH] [IMP] web: Tooltip UX on touch-enable devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, in a touch device the behaviour was a "tap-hold-to-show” which let the user see the Tooltip by pressing the element, and letting it disappear when the pressure ends. This commit allows choosing between the previous "tap-hold-to-show" behaviour and a new "tap-to-show" which let the user see the Tooltip by pressing the element, and keep it open until it press something else. This behaviour is more adapted when the tooltip is on a specific icon, as is the case for the labels, since : f981c5f8f09ff884f0e134ae8d4ee0ad5f56e3f4 closes odoo/odoo#97680 Signed-off-by: Lucas Perais (lpe) --- .../src/core/tooltip/tooltip_service.js | 20 ++++++++-- .../web/static/src/views/form/form_label.js | 2 +- .../core/tooltip/tooltip_service_tests.js | 39 ++++++++++++++++++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/core/tooltip/tooltip_service.js b/addons/web/static/src/core/tooltip/tooltip_service.js index 684421f8e68..a398562510f 100644 --- a/addons/web/static/src/core/tooltip/tooltip_service.js +++ b/addons/web/static/src/core/tooltip/tooltip_service.js @@ -23,6 +23,10 @@ const { whenReady } = owl; * The opening delay can be modified with the "data-tooltip-delay" attribute (default: 400): * * + * The default behaviour on touch devices to open the tooltip can be modified from "hold-to-show" + * to "tap-to-show" "with the data-tooltip-touch-tap-to-show" attribute: + * + * * For advanced tooltips containing dynamic and/or html content, the * "data-tooltip-template" and "data-tooltip-info" attributes can be used. * For example, let's suppose the following qweb template: @@ -188,12 +192,20 @@ export const tooltipService = { if (hasTouch()) { document.body.addEventListener("touchstart", onTouchStart); - document.body.addEventListener("touchend", () => { - touchPressed = false; + document.body.addEventListener("touchend", (ev) => { + if (ev.target.matches("[data-tooltip], [data-tooltip-template]")) { + if (!ev.target.dataset.tooltipTouchTapToShow) { + touchPressed = false; + } + } }); - document.body.addEventListener("touchcancel", () => { - touchPressed = false; + document.body.addEventListener("touchcancel", (ev) => { + if (ev.target.matches("[data-tooltip], [data-tooltip-template]")) { + if (!ev.target.dataset.tooltipTouchTapToShow) { + touchPressed = false; + } + } }); return; diff --git a/addons/web/static/src/views/form/form_label.js b/addons/web/static/src/views/form/form_label.js index ea79db9e04d..d9e826d333e 100644 --- a/addons/web/static/src/views/form/form_label.js +++ b/addons/web/static/src/views/form/form_label.js @@ -55,6 +55,6 @@ export class FormLabel extends Component { } FormLabel.template = xml` `; diff --git a/addons/web/static/tests/core/tooltip/tooltip_service_tests.js b/addons/web/static/tests/core/tooltip/tooltip_service_tests.js index 5c1c5a9f4b2..b2b1f7a0788 100644 --- a/addons/web/static/tests/core/tooltip/tooltip_service_tests.js +++ b/addons/web/static/tests/core/tooltip/tooltip_service_tests.js @@ -381,7 +381,7 @@ QUnit.module("Tooltip service", (hooks) => { await nextTick(); }); - QUnit.test("touch rendering", async (assert) => { + QUnit.test("touch rendering - hold-to-show", async (assert) => { class MyComponent extends Component {} MyComponent.template = xml``; let simulateTimeout; @@ -414,4 +414,41 @@ QUnit.module("Tooltip service", (hooks) => { await nextTick(); assert.containsNone(target, ".o_popover_container .o_popover"); }); + + QUnit.test("touch rendering - tap-to-show", async (assert) => { + class MyComponent extends Component {} + MyComponent.template = xml``; + let simulateTimeout; + const mockSetTimeout = (fn) => { + simulateTimeout = fn; + }; + let simulateInterval; + const mockSetInterval = (fn) => { + simulateInterval = fn; + }; + const mockOnTouchStart = () => {}; + await makeParent(MyComponent, { mockSetTimeout, mockSetInterval, mockOnTouchStart }); + + assert.containsNone(target, ".o_popover_container .o_popover"); + await triggerEvent(target, "button[data-tooltip]", "touchstart"); + await nextTick(); + assert.containsNone(target, ".o_popover_container .o_popover"); + + simulateTimeout(); + await nextTick(); + assert.containsOnce(target, ".o_popover_container .o_popover"); + assert.strictEqual( + target.querySelector(".o_popover_container .o_popover").innerText, + "hello" + ); + + await triggerEvent(target, "button[data-tooltip]", "touchend"); + assert.containsOnce(target, ".o_popover_container .o_popover"); + simulateInterval(); + await nextTick(); + assert.containsOnce(target, ".o_popover_container .o_popover"); + + await triggerEvent(target, "button[data-tooltip]", "touchstart"); + assert.containsNone(target, ".o_popover_container .o_popover"); + }); });