rect gslate

 avatar
user_8454105
typescript
a month ago
5.6 kB
2
Indexable
Never
/** @prettier */

const overlayCssClass: string = "hotkey-overlay";

function getTooltips() {
	return $("." + overlayCssClass);
}

function areTooltipsDisplayed() {
	return getTooltips().length > 0;
}

function removeTooltipsDOMElements() {
	getTooltips().remove();
	return;
}

function insertTooltipDOMElement(hotkey, element) {
	
	if( !(element[0] instanceof Element)){
		console.error("invalid element provided " + typeof element);
		return;
	}

	// Check if the element is hidden
	const computedStyle = window.getComputedStyle(element[0]);
	if (computedStyle.display === 'none') {
		// Execute certain code if the display property is 'none'
		console.warn("Element is hidden. Cannot attach tooltip.");
		return;
	}

	const tooltipId = 'Tooltip_' + hotkey.name.replace(/\s+/g, '').replace(/\+/g, '_');
	let tooltipSpan = document.getElementById(tooltipId);
    if (!tooltipSpan) {
        tooltipSpan = document.createElement('span');
        tooltipSpan.id = tooltipId;
        tooltipSpan.className = overlayCssClass; 
        document.body.appendChild(tooltipSpan);
    }
	
	const replacements = {
        "CONTROL": "CTRL",
        "ALTERNATIVE": "ALT",
        "ARROWUP": "↑",
        "ARROWDOWN": "↓",
        "ARROWLEFT": "←",
        "ARROWRIGHT": "→",
        // Add other replacements as needed
    };
    
	let modifierKbds = "";

	hotkey.modifiers.forEach(modifier => {
        const replacedModifier = replacements[modifier] || modifier;

		const kbd = '<kbd>' + replacedModifier + '</kbd> + ';
		modifierKbds = modifierKbds + kbd;
	});

	let kbdKey = replacements[hotkey.key] || hotkey.key;

	tooltipSpan.innerHTML = '<span class="htk-name">' + hotkey.name + '</span><span class="htk-key"> '+ modifierKbds + ' <kbd>' + kbdKey + '</kbd></span>';
	document.body.appendChild(tooltipSpan);

	//positioning start *****************************
    const rect = element[0].getBoundingClientRect();
    tooltipSpan.style.position = 'absolute';
	
	const padding = 5; // Add some padding from the element
    let tooltipRect = tooltipSpan.getBoundingClientRect();

    let top, left, hotkeyClass, arrowClass;

    // Position tooltip based on the element's parent
    if (isDescendant(element[0], '#leftNav')) {
        // Position to the right and top of the element
		hotkeyClass = 'leftNav-hotkey';
		arrowClass = 'element-left-center';
        top = window.scrollY + rect.top;
        left = window.scrollX + rect.right + padding;
    } else if (isDescendant(element[0], '#header')) {
        // Position to the bottom of the element
		hotkeyClass = 'header-hotkey';
		arrowClass = 'element-top-center';

        top = window.scrollY + rect.bottom + padding;
        left = window.scrollX + rect.left;
    } else if (isDescendant(element[0], '#content')) {
        // Position to the bottom and align to the left of the element
		hotkeyClass = 'content-hotkey';
		arrowClass = 'element-top-center';

        top = window.scrollY + rect.bottom + padding;
        left = window.scrollX + rect.left;
    } else if (isDescendant(element[0], '.app-footer')) {
        // Position to the bottom left of the element
		hotkeyClass = 'footer-hotkey';
		arrowClass = 'element-bottom-center';

        top = window.scrollY + rect.bottom + padding;
        left = window.scrollX + rect.left;
    } else {
        // Default position to the bottom of the element
		hotkeyClass = 'free-hotkey';
		arrowClass = '';

        top = window.scrollY + rect.bottom + padding;
        left = window.scrollX + rect.left;
    }
	tooltipSpan.classList.add(hotkeyClass);
	tooltipSpan.classList.add(arrowClass);

    // Adjust position if the tooltip goes beyond the viewport boundaries
    if (top + tooltipRect.height > window.innerHeight) {
        top = window.scrollY + rect.top - tooltipRect.height - padding; // Move above the element
    }
    if (left + tooltipRect.width > window.innerWidth) {
        left = window.scrollX + rect.right - tooltipRect.width; // Align to the right edge of the element
    } else if (left < 0) {
        left = window.scrollX + rect.left; // Align to the left edge of the element
    }

    // Update tooltip dimensions after adjustments
    tooltipSpan.style.left = left + 'px';
    tooltipSpan.style.top = top + 'px';
    tooltipRect = tooltipSpan.getBoundingClientRect();

    //Check if tooltip overlaps with other tooltips and adjust position
	const existingTooltips = document.querySelectorAll('.' + overlayCssClass);
	existingTooltips.forEach(existingTooltip => {
		if (existingTooltip !== tooltipSpan) {
			const existingRect = existingTooltip.getBoundingClientRect();
			if (tooltipRect.top < existingRect.bottom && tooltipRect.bottom > existingRect.top &&
				tooltipRect.left < existingRect.right && tooltipRect.right > existingRect.left) {
				// Adjust the position to avoid overlap
				top = existingRect.bottom + padding;
				tooltipSpan.style.top = top + 'px';
				tooltipRect = tooltipSpan.getBoundingClientRect(); // Update the tooltip dimensions
			}
		}
	});
    //positioning ENDS

	return;
}

function isDescendant(child, parentSelector) {
    const parent = document.querySelector(parentSelector);
    let node = child;
    while (node !== null) {
        if (node === parent) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
}
export {
	areTooltipsDisplayed,
	removeTooltipsDOMElements,
	insertTooltipDOMElement
}