mirror of
https://github.com/nodejs/node.git
synced 2025-05-15 14:41:29 +00:00

PR-URL: https://github.com/nodejs/node/pull/45579 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
148 lines
4.2 KiB
JavaScript
148 lines
4.2 KiB
JavaScript
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import {Debouncer, DOM, V8CustomElement} from './helper.mjs';
|
|
|
|
DOM.defineCustomElement('view/tool-tip',
|
|
(templateText) =>
|
|
class Tooltip extends V8CustomElement {
|
|
_targetNode;
|
|
_content;
|
|
_isHidden = true;
|
|
_debouncedSetData = new Debouncer((...args) => this._setData(...args), 500)
|
|
|
|
constructor() {
|
|
super(templateText);
|
|
this._intersectionObserver = new IntersectionObserver((entries) => {
|
|
if (entries[0].intersectionRatio <= 0) {
|
|
this.hide();
|
|
} else {
|
|
this.show();
|
|
this.requestUpdate(true);
|
|
}
|
|
});
|
|
document.addEventListener('click', (event) => {
|
|
// Only hide the tooltip if we click anywhere outside of it.
|
|
let target = event.target;
|
|
while (target) {
|
|
if (target == this) return;
|
|
target = target.parentNode;
|
|
}
|
|
this.hide()
|
|
});
|
|
}
|
|
|
|
_update() {
|
|
if (!this._targetNode || this._isHidden) return;
|
|
if (!this._targetNode.parentNode) return;
|
|
const rect = this._targetNode.getBoundingClientRect();
|
|
rect.x += rect.width / 2;
|
|
let atRight = this._useRight(rect.x);
|
|
let atBottom = this._useBottom(rect.y);
|
|
if (atBottom) rect.y += rect.height;
|
|
this._setPosition(rect, atRight, atBottom);
|
|
this.requestUpdate(true);
|
|
}
|
|
|
|
set data({content, positionOrTargetNode, immediate}) {
|
|
if (immediate) {
|
|
this._debouncedSetData.callNow(content, positionOrTargetNode)
|
|
} else {
|
|
this._debouncedSetData.call(content, positionOrTargetNode)
|
|
}
|
|
}
|
|
|
|
_setData(content, positionOrTargetNode) {
|
|
if (positionOrTargetNode.nodeType === undefined) {
|
|
this._targetNode = undefined;
|
|
const position = positionOrTargetNode;
|
|
this._setPosition(
|
|
position, this._useRight(position.x), this._useBottom(position.y));
|
|
} else {
|
|
this._setTargetNode(positionOrTargetNode);
|
|
}
|
|
this._setContent(content);
|
|
}
|
|
|
|
_setTargetNode(targetNode) {
|
|
this._intersectionObserver.disconnect();
|
|
this._targetNode = targetNode;
|
|
if (targetNode === undefined) return;
|
|
if (!(targetNode instanceof SVGElement)) {
|
|
this._intersectionObserver.observe(targetNode);
|
|
}
|
|
this.requestUpdate(true);
|
|
}
|
|
|
|
_setPosition(viewportPosition, atRight, atBottom) {
|
|
const horizontalMode = atRight ? 'right' : 'left';
|
|
const verticalMode = atBottom ? 'bottom' : 'top';
|
|
this.bodyNode.className = horizontalMode + ' ' + verticalMode;
|
|
const pageX = viewportPosition.x + window.scrollX;
|
|
this.style.left = `${pageX}px`;
|
|
const pageY = viewportPosition.y + window.scrollY;
|
|
this.style.top = `${pageY}px`;
|
|
}
|
|
|
|
_useBottom(viewportY) {
|
|
return viewportY <= 400;
|
|
}
|
|
|
|
_useRight(viewportX) {
|
|
return viewportX < document.documentElement.clientWidth / 2;
|
|
}
|
|
|
|
_setContent(content) {
|
|
if (!content) return this.hide();
|
|
this.show();
|
|
if (this._content === content) return;
|
|
this._content = content;
|
|
|
|
if (typeof content === 'string') {
|
|
this.contentNode.innerHTML = content;
|
|
this.contentNode.className = 'textContent';
|
|
} else if (content?.nodeType && content?.nodeName) {
|
|
this._setContentNode(content);
|
|
} else {
|
|
if (this.contentNode.firstChild?.localName == 'property-link-table') {
|
|
this.contentNode.firstChild.propertyDict = content;
|
|
} else {
|
|
const node = DOM.element('property-link-table');
|
|
node.instanceLinkButtons = true;
|
|
node.propertyDict = content;
|
|
this._setContentNode(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
_setContentNode(content) {
|
|
const newContent = DOM.div();
|
|
newContent.appendChild(content);
|
|
this.contentNode.replaceWith(newContent);
|
|
newContent.id = 'content';
|
|
}
|
|
|
|
hide() {
|
|
this._content = undefined;
|
|
if (this._isHidden) return;
|
|
this._isHidden = true;
|
|
this.bodyNode.style.display = 'none';
|
|
this.targetNode = undefined;
|
|
}
|
|
|
|
show() {
|
|
if (!this._isHidden) return;
|
|
this.bodyNode.style.display = 'block';
|
|
this._isHidden = false;
|
|
}
|
|
|
|
get bodyNode() {
|
|
return this.$('#body');
|
|
}
|
|
|
|
get contentNode() {
|
|
return this.$('#content');
|
|
}
|
|
});
|