services
feedback
tooltip
Odoo 19 services — tooltip (core)
Live preview
Interactive
Source excerpt
web/static/src/core/tooltip/tooltip_service.js
import { browser } from "@web/core/browser/browser";
import { registry } from "@web/core/registry";
import { Tooltip } from "./tooltip";
import { hasTouch } from "@web/core/browser/feature_detection";
import { whenReady } from "@odoo/owl";
/**
* The tooltip service allows to display custom tooltips on every elements with
* a "data-tooltip" attribute. This attribute can be set on elements for which
* we prefer a custom tooltip instead of the native one displaying the value of
* the "title" attribute.
*
* Usage:
* <button data-tooltip="This is a tooltip">Do something</button>
*
* 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>
*
* The opening delay can be modified with the "data-tooltip-delay" attribute (default: 400):
* <button data-tooltip="This is a tooltip" data-tooltip-delay="0">Do something</button>
*
* 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:
* <button data-tooltip="This is a tooltip" data-tooltip-touch-tap-to-show="true">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".
*/
export const OPEN_DELAY = 400;
export const CLOSE_DELAY = 200;
export const SHOW_AFTER_DELAY = 250;
export const tooltipService = {
dependencies: ["popover"],
start(env, { popover }) {
let openTooltipTimeout;
let closeTooltip;
let showTimer;
let target = null;
const elementsWithTooltips = new WeakMap();
/**
* Detect if the current node is the `sup` tooltip node
* @param {HTMLElement} el
* @return {boolean}
*/
function isHelpNode(el) {
return (
el.textContent === "?" &&
(el.hasAttribute("data-tooltip") || el.hasAttribute("data-tooltip-template"))
);
}
/**
* Closes the currently opened tooltip if any, or prevent it from opening.
*/
function cleanup() {
target = null;
browser.clearTimeout(openTooltipTimeout);
openTooltipTimeout = null;
if (closeTooltip) {
closeTooltip();
closeTooltip = null;
}
}
/**
* Checks that the target is in the DOM and we're hovering the target.
* @returns {boolean}
*/
function shouldCleanup() {
if (!target) {
return false;
}
if (!document.body.contains(target)) {
return true; // target is no longer in the DOM
}
return false;
}
/**
* Checks whether there is a tooltip registered on the event target, and
* if there is, creates a timeout to open the corresponding tooltip
* after a delay.
*
* @param {HTMLElement} el the element on which to add the tooltip
* @param {object} param1
* @param {string} [param1.tooltip] the string to add as a tooltip, if
* no tooltip template is specified
* @param {string} [param1.template] the name of the template to use for
* tooltip, if any
* @param {object} [param1.info] info for the tooltip template
* @param {'top'|'bottom'|'left'|'right'} param1.position
* @param {number} [param1.delay] delay after which the popover should
* open
*/
function openTooltip(el, { tooltip = "", template, info, position, delay = OPEN_DELAY }) {
cleanup();
if (!tooltip && !template) {
return;
}
target = el;
// Prevent title from showing on a parent at the same time
target.title = "";
const timeoutDelay = isHelpNode(el) ? 0 : delay;
openTooltipTimeout = browser.setTimeout(() => {
Registry / API
- Registry name
tooltip- Category
services- Module
web- Slug
tooltip- Nav group
feedback