ui-lib/lib/ui/tooltip.js

177 lines
7.0 KiB
JavaScript

import './css/tooltip.scss';
import { createElement } from "../functions";
// import { global } from "../utility";
export function setTooltip(container, content, flag = false, parent = null) {
const isParent = parent instanceof HTMLElement;
if (isParent) {
const tipid = container.dataset.tipId;
const tip = parent.querySelector(`.ui-tooltip-wrapper[data-tip-id="${tipid}"]`);
tip?.remove();
} else {
const tip = container.querySelector('.ui-tooltip-wrapper');
tip?.remove();
}
const wrapper = createElement('div', wrapper => {
wrapper.className = 'ui-tooltip-wrapper ui-tooltip-color';
// wrapper.style.visibility = 'hidden';
// wrapper.style.opacity = 0;
// wrapper.style.top = '0';
// wrapper.style.left = '0';
wrapper.style.cssText += 'display: none; visibility: hidden; opacity: 0; top: 0; left: 0';
},
createElement('div', 'ui-tooltip-pointer ui-tooltip-color'),
createElement('div', 'ui-tooltip-curtain ui-tooltip-color'),
createElement('div', cnt => {
cnt.className = 'ui-tooltip-content';
if (content instanceof Element) {
cnt.appendChild(content);
} else {
cnt.innerText = content;
}
})
);
// container.insertAdjacentElement('afterend', wrapper);
if (isParent) {
const tipId = String(Math.random()).substring(2);
container.dataset.tipId = tipId;
wrapper.dataset.tipId = tipId;
parent.appendChild(wrapper);
} else {
container.appendChild(wrapper);
}
let tid;
container.addEventListener('mouseenter', () => {
tid && clearTimeout(tid);
let c = container;
while (c?.offsetWidth == null) {
c = c.parentElement;
}
if (c == null) {
return;
}
if (!flag || c.scrollWidth > c.offsetWidth) {
tid = setTimeout(() => {
let p;
let left;
let top;
left = c.offsetLeft;
top = c.offsetTop;
if (isParent) {
p = c.offsetParent;
while (p != null && p !== parent) {
left += p.offsetLeft;
top += p.offsetTop;
p = p.offsetParent;
}
}
p = c.parentElement;
const offsetParent = isParent ? parent : c.offsetParent;
while (p != null && p !== offsetParent) {
left -= p.scrollLeft;
top -= p.scrollTop;
p = p.parentElement;
}
wrapper.style.display = '';
const offsetHeight = wrapper.offsetHeight;
const offsetWidth = wrapper.offsetWidth;
if (isParent) {
top -= offsetHeight + 14;
if (top < -offsetHeight) {
top += c.offsetHeight + offsetHeight + 14;
wrapper.classList.add('ui-tooltip-down');
}
left += (c.offsetWidth - offsetWidth) / 2;
if (left < 1) {
left = 1;
}
} else {
// check overflow
let t = c.offsetTop;
let l = c.offsetLeft;
p = c.offsetParent;
let lastWidth = p.clientWidth;
let lastHeight = p.clientHeight;
while (p != null) {
const overflow = window.getComputedStyle(p).overflow;
if (overflow !== 'visible') {
break;
}
t += p.offsetTop;
l += p.offsetLeft;
const parent = p.offsetParent;
while (p != null) {
const w = p.clientWidth;
if (w < lastWidth) {
lastWidth += l;
} else {
lastWidth = p.clientWidth;
}
const h = p.clientHeight;
if (h < lastHeight) {
lastHeight += t;
} else {
lastHeight = p.clientHeight;
}
t -= p.scrollTop;
l -= p.scrollLeft;
if (p === parent) {
break;
}
p = p.parentElement;
}
}
if (t - offsetHeight - 14 < 0) {
const containerOffsetHeight = c.offsetHeight;
if (t + containerOffsetHeight + offsetHeight + 14 > lastHeight) {
top = t + (containerOffsetHeight - offsetHeight) / 2;
if (top + offsetHeight + 1 > lastHeight) {
top = lastHeight - offsetHeight - 1;
}
wrapper.classList.add('ui-tooltip-no');
} else {
top += containerOffsetHeight + 14;
wrapper.classList.add('ui-tooltip-down');
}
} else {
top -= offsetHeight + 14;
wrapper.classList.remove('ui-tooltip-down');
}
left += (c.offsetWidth - offsetWidth) / 2;
if (l - offsetWidth < 0) {
left = 1;
} else if (left + offsetWidth + 1 > lastWidth) {
left = lastWidth - offsetWidth - 1;
}
}
// wrapper.style.left = `${left}px`;
// wrapper.style.top = `${top}px`;
// wrapper.style.visibility = 'visible';
// wrapper.style.opacity = 1;
wrapper.style.cssText += `left: ${left}px; top: ${top}px; visibility: visible; opacity: 1`;
}, 100);
}
});
container.addEventListener('mouseleave', () => {
tid && clearTimeout(tid);
tid = setTimeout(() => {
wrapper.style.visibility = 'hidden';
wrapper.style.opacity = 0;
tid = setTimeout(() => wrapper.style.display = 'none', 120);
}, 300);
});
return container;
}
export function resolveTooltip(container = document.body) {
const tips = container.querySelectorAll('[title]');
for (let tip of tips) {
const title = tip.getAttribute('title');
if (title != null) {
tip.removeAttribute('title');
setTooltip(tip, title);
}
}
return container;
}