[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
This commit is contained in:
Aaron Bohy
2021-09-24 09:45:43 +00:00
parent 37086aa554
commit 9d98d1e870
4 changed files with 77 additions and 14 deletions
@@ -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 },
};
@@ -3,7 +3,9 @@
<t t-name="web.Tooltip" owl="1">
<div class="o-tooltip px-2 py-1">
<t t-if="props.Component" t-component="props.Component" t-props="props.props" />
<t t-if="props.template" t-call="{{props.template}}">
<t t-set="info" t-value="props.info"/>
</t>
<small t-else="" t-esc="props.tooltip"/>
</div>
</t>
@@ -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":
* <button data-tooltip="This is a tooltip" data-tooltip-position="left">Do something</button>
*
* 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:
* <t t-name="some_template">
* <ul>
* <li>info.x</li>
* <li>info.y</li>
* </ul>
* </t>
* This template can then be used in a tooltip as follows:
* <button data-tooltip-template="some_template" data-tooltip-info="info">Do something</button>
* 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 });
}
@@ -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`
<button data-tooltip-template="my_tooltip_template">Action</button>
`;
const parent = await makeParent(MyComponent);
parent.env.qweb.addTemplate("my_tooltip_template", "<i>tooltip</i>");
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, "<i>tooltip</i>");
});
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`
<button
data-tooltip-template="my_tooltip_template"
t-att-data-tooltip-info="info">
Action
</button>
`;
const parent = await makeParent(MyComponent);
parent.env.qweb.addTemplate(
"my_tooltip_template",
`
<ul>
<li>X: <t t-esc="info.x"/></li>
<li>Y: <t t-esc="info.y"/></li>
</ul>
`
);
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,
"<ul><li>X: 3</li><li>Y: abc</li></ul>"
);
});
});