From 9d98d1e870066d5124befe97e02829df408eb43f Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Thu, 23 Sep 2021 09:26:32 +0000 Subject: [PATCH] [REF] web: useTooltip: use template instead of component Allowing to specify components inside tooltips to obtain dynamic and/or html content was a bit overkill and unnecessary: a template can do the trick and it is easier to define. This commit thus renames attribute "data-tooltip-component" into "data-tooltip-template" (the name of the qweb template) and introduces the "data-tooltip-info" attribute (its value is then available in the template under the "info" variable). X-original-commit: 8683a8d762339451e3d9f8706aac86da80510b37 Part-of: odoo/odoo#77113 --- addons/web/static/src/core/tooltip/tooltip.js | 6 +-- .../web/static/src/core/tooltip/tooltip.xml | 4 +- .../static/src/core/tooltip/tooltip_hook.js | 32 ++++++++---- .../tests/core/tooltip/tooltip_hook_tests.js | 49 +++++++++++++++++++ 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/addons/web/static/src/core/tooltip/tooltip.js b/addons/web/static/src/core/tooltip/tooltip.js index f35de09b408..a2409b7a951 100644 --- a/addons/web/static/src/core/tooltip/tooltip.js +++ b/addons/web/static/src/core/tooltip/tooltip.js @@ -5,7 +5,7 @@ const { Component } = owl; export class Tooltip extends Component {} Tooltip.template = "web.Tooltip"; Tooltip.props = { - tooltip: String, - Component: { optional: true }, - props: { optional: true }, + tooltip: { type: String, optional: true }, + template: { type: String, optional: true }, + info: { optional: true }, }; diff --git a/addons/web/static/src/core/tooltip/tooltip.xml b/addons/web/static/src/core/tooltip/tooltip.xml index d9c74413ede..f1c83547117 100644 --- a/addons/web/static/src/core/tooltip/tooltip.xml +++ b/addons/web/static/src/core/tooltip/tooltip.xml @@ -3,7 +3,9 @@
- + + +
diff --git a/addons/web/static/src/core/tooltip/tooltip_hook.js b/addons/web/static/src/core/tooltip/tooltip_hook.js index 96c6d0065cb..1ac73eff3d8 100644 --- a/addons/web/static/src/core/tooltip/tooltip_hook.js +++ b/addons/web/static/src/core/tooltip/tooltip_hook.js @@ -4,7 +4,6 @@ import { browser } from "@web/core/browser/browser"; import { useListener } from "@web/core/utils/hooks"; import { usePopover } from "@web/core/popover/popover_hook"; import { Tooltip } from "./tooltip"; -import { registry } from "@web/core/registry"; /** * The useTooltip hook allows to display custom tooltips on every elements with @@ -18,6 +17,19 @@ import { registry } from "@web/core/registry"; * The ideal position of the tooltip can be specified thanks to the attribute * "data-tooltip-position": * + * + * 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: + * + *
    + *
  • info.x
  • + *
  • info.y
  • + *
+ *
+ * This template can then be used in a tooltip as follows: + * + * with "info" being a stringified object with two keys "x" and "y". */ const OPEN_DELAY = 400; const CLOSE_DELAY = 200; @@ -46,13 +58,12 @@ export function useTooltip() { function onMouseEnter(ev) { const dataset = ev.target.dataset; const tooltip = dataset.tooltip; - - let Component, props; - if ("tooltipComponent" in dataset) { - ({ Component, props } = JSON.parse(dataset["tooltipComponent"])); - Component = registry.category("tooltips").get(Component, null); + let template, info; + if ("tooltipTemplate" in dataset) { + template = dataset.tooltipTemplate; + info = dataset.tooltipInfo ? JSON.parse(dataset.tooltipInfo) : null; } - if (tooltip || Component) { + if (tooltip || template) { cleanup(); target = ev.target; openTooltipTimeout = browser.setTimeout(() => { @@ -60,7 +71,7 @@ export function useTooltip() { closeTooltip = popover.add( target, Tooltip, - { tooltip, Component, props }, + { tooltip, template, info }, { position } ); }, OPEN_DELAY); @@ -97,6 +108,7 @@ export function useTooltip() { }, CLOSE_DELAY); // Listen (using event delegation) to "mouseenter" events on all nodes with - // the "data-tooltip" attribute, to open the tooltip. - useListener("mouseenter", "[data-tooltip]", onMouseEnter, { capture: true }); + // the "data-tooltip" or "data-tooltip-template" attribute, to open the tooltip. + const selector = "[data-tooltip], [data-tooltip-template]"; + useListener("mouseenter", selector, onMouseEnter, { capture: true }); } diff --git a/addons/web/static/tests/core/tooltip/tooltip_hook_tests.js b/addons/web/static/tests/core/tooltip/tooltip_hook_tests.js index 252fae3e06d..0e099f7d3f8 100644 --- a/addons/web/static/tests/core/tooltip/tooltip_hook_tests.js +++ b/addons/web/static/tests/core/tooltip/tooltip_hook_tests.js @@ -203,4 +203,53 @@ QUnit.module("Tooltip hook", () => { assert.strictEqual(parent.el.querySelector(".o_popover").innerText, "left"); assert.hasClass(parent.el.querySelector(".o_popover"), "o-popper-position--lm"); }); + + QUnit.test("tooltip with a template, no info", async (assert) => { + class MyComponent extends Component {} + MyComponent.template = xml` + + `; + const parent = await makeParent(MyComponent); + parent.env.qweb.addTemplate("my_tooltip_template", "tooltip"); + + assert.containsNone(parent, ".o_popover_container .o-tooltip"); + parent.el.querySelector("button").dispatchEvent(new Event("mouseenter")); + await nextTick(); + assert.containsOnce(parent, ".o_popover_container .o-tooltip"); + assert.strictEqual(parent.el.querySelector(".o-tooltip").innerHTML, "tooltip"); + }); + + QUnit.test("tooltip with a template and info", async (assert) => { + class MyComponent extends Component { + get info() { + return JSON.stringify({ x: 3, y: "abc" }); + } + } + MyComponent.template = xml` + + `; + const parent = await makeParent(MyComponent); + parent.env.qweb.addTemplate( + "my_tooltip_template", + ` + + ` + ); + + assert.containsNone(parent, ".o_popover_container .o-tooltip"); + parent.el.querySelector("button").dispatchEvent(new Event("mouseenter")); + await nextTick(); + assert.containsOnce(parent, ".o_popover_container .o-tooltip"); + assert.strictEqual( + parent.el.querySelector(".o-tooltip").innerHTML, + "" + ); + }); });