H5P.Tooltip=(function (){
const Position={
allowed: ['top', 'bottom', 'left', 'right'],
default: 'top',
};
const DELAY_SHOW_MS=500;
const DELAY_HIDE_MS=500;
function parseString(text){
if(text===null||text===undefined){
return '';
}
const div=document.createElement('div');
div.innerHTML=text;
return div.textContent;
}
let usingMouse;
function debounce(callback, delay){
let timeout=null;
return function (...args){
clearTimeout(timeout);
timeout=setTimeout(()=> {
callback(...args);
}, delay);
};}
document.addEventListener('mousemove', debounce(()=> usingMouse=true, 100));
document.addEventListener('mousedown', ()=> usingMouse=true);
document.addEventListener('keydown', ()=> usingMouse=false);
function Tooltip(triggeringElement, options){
H5P.Tooltip.uniqueId +=1;
const tooltipId=`h5p-tooltip-${H5P.Tooltip.uniqueId}`;
options=options||{};
options.classes=options.classes||[];
options.ariaHidden=options.ariaHidden||true;
options.tooltipSource=options.tooltipSource||'aria-label';
options.position=(options.position&&Position.allowed.includes(options.position))
? options.position
: Position.default;
options.classes.push('h5p-tooltip');
if(options.position==='left'||options.position==='right'){
options.classes.push('h5p-tooltip-narrow');
}
let hover=false;
let focus=false;
const hideOnEscape=function (event){
if(event.key==='Escape'){
tooltip.classList.remove('h5p-tooltip-visible');
}};
const tooltip=document.createElement('div');
tooltip.id=tooltipId;
tooltip.role='tooltip';
tooltip.textContent=parseString(options.text||triggeringElement.getAttribute(options.tooltipSource)||'');
tooltip.setAttribute('aria-hidden', options.ariaHidden);
tooltip.classList.add(...options.classes);
document.body.appendChild(tooltip);
if(!options.ariaHidden){
triggeringElement.setAttribute('aria-describedby', tooltipId);
}
this.observer=new MutationObserver((mutations)=> {
const updatedText=mutations[0].target.getAttribute(options.tooltipSource);
if(tooltip.parentNode===null){
triggeringElement.appendChild(tooltip);
}
tooltip.textContent=parseString(options.text||updatedText);
if(tooltip.textContent.trim().length===0&&tooltip.classList.contains('h5p-tooltip-visible')){
tooltip.classList.remove('h5p-tooltip-visible');
}});
this.observer.observe(triggeringElement, {
attributes: true,
attributeFilter: [options.tooltipSource, 'class'],
});
let h5pContainer;
let showTooltipTimer;
let hideTooltipTimer;
let triggerMouseLeaveTimer;
const showTooltip=function (event, wait=true){
if(!event.target||event.target.disabled||event.target.getAttribute('aria-disabled')==='true'){
return;
}
clearTimeout(hideTooltipTimer);
if(wait===true){
clearTimeout(showTooltipTimer);
showTooltipTimer=setTimeout(()=> {
showTooltip(event, false);
}, DELAY_SHOW_MS);
return;
}
if(tooltip.textContent.trim().length===0){
return;
}
if(event.type==='mouseenter'){
hover=true;
}else{
focus=true;
}
tooltip.style.left='';
tooltip.style.top='';
tooltip.classList.add('h5p-tooltip-visible');
document.body.addEventListener('keydown', hideOnEscape, true);
if(h5pContainer===undefined){
h5pContainer=triggeringElement.closest('.h5p-container');
}
const rootRect=h5pContainer ? h5pContainer.getBoundingClientRect():document.documentElement.getBoundingClientRect();
const triggerRect=triggeringElement.getBoundingClientRect();
let tooltipRect=tooltip.getBoundingClientRect();
if(options.position==='top'){
tooltip.style.left=`${triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2)}px`;
tooltip.style.top=`${triggerRect.top - tooltipRect.height}px`;
}
else if(options.position==='bottom'){
tooltip.style.left=`${triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2)}px`;
tooltip.style.top=`${triggerRect.bottom}px`;
}
else if(options.position==='left'){
tooltip.style.left=`${triggerRect.left - tooltipRect.width}px`;
tooltip.style.top=`${triggerRect.top + (triggerRect.height - tooltipRect.height) / 2}px`;
return;
}
else if(options.position==='right'){
tooltip.style.left=`${triggerRect.right}px`;
tooltip.style.top=`${triggerRect.top + (triggerRect.height - tooltipRect.height) / 2}px`;
return;
}
tooltipRect=tooltip.getBoundingClientRect();
const isVisible=tooltipRect.left >=0
&& tooltipRect.top >=0
&& tooltipRect.right <=rootRect.width
&& tooltipRect.bottom <=rootRect.height;
if(!isVisible){
tooltipRect=tooltip.getBoundingClientRect();
if(tooltipRect.left < 0){
tooltip.style.left=0;
}
else if(tooltipRect.right > rootRect.width){
tooltip.style.left='';
tooltip.style.right=0;
}}
};
const hideTooltip=function (event){
let hide=false;
let wait=false;
if(event.type==='click'){
hide=true;
}else{
if(event.type==='mouseleave'){
wait=true;
hover=false;
}else{
focus=false;
}
hide=(!hover&&!focus);
}
if(hide){
clearTimeout(showTooltipTimer);
const cleanupTooltip=()=> {
tooltip.classList.remove('h5p-tooltip-visible');
document.body.removeEventListener('keydown', hideOnEscape, true);
};
if(wait){
clearTimeout(hideTooltipTimer);
hideTooltipTimer=setTimeout(()=> {
cleanupTooltip();
}, DELAY_HIDE_MS);
}else{
cleanupTooltip();
}}
};
triggeringElement.addEventListener('mouseenter', showTooltip);
triggeringElement.addEventListener('mouseleave', (event)=> {
triggerMouseLeaveTimer=setTimeout(()=> {
hideTooltip(event);
}, 1);
});
triggeringElement.addEventListener('focusin', (event)=> {
if(!usingMouse){
showTooltip(event);
}});
triggeringElement.addEventListener('focusout', hideTooltip);
triggeringElement.addEventListener('click', hideTooltip);
tooltip.addEventListener('mouseenter', ()=> {
clearTimeout(triggerMouseLeaveTimer);
});
tooltip.addEventListener('mouseleave', hideTooltip);
tooltip.addEventListener('click', (event)=> {
event.stopPropagation();
event.preventDefault();
hideTooltip(event);
});
this.setText=function (text){
options.text=text;
tooltip.textContent=parseString(options.text||triggeringElement.getAttribute(options.tooltipSource)||'');
};
this.hide=function (){
hover=focus=false;
tooltip.classList.remove('h5p-tooltip-visible');
};
this.getElement=function (){
return tooltip;
};
this.remove=function (){
this.observer?.disconnect();
tooltip.remove();
};
return {
setText: this.setText,
hide: this.hide,
getElement: this.getElement,
remove: this.remove,
observer: this.observer,
};}
return Tooltip;
}());
H5P.Tooltip.uniqueId=-1;