feat: RCT inline abbreviation tooltip on verdict legend strip (v2.2.1) (#53)
CI green (PHP Lint 8.1/8.2/8.3 ✓, PHPCS ✓, PHPUnit 8.1/8.2/8.3 ✓). QA: PASS.
This commit is contained in:
134
assets/js/abbr-tooltip.js
Normal file
134
assets/js/abbr-tooltip.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* abbr-tooltip.js — Inline abbreviation popover for verdict legend screen.
|
||||
*
|
||||
* What: Opens a small popover anchored to any .pr-abbr element when tapped,
|
||||
* clicked, or activated via keyboard. Closes on outside click or Escape.
|
||||
* Who triggers: Enqueued by functions.php on is_front_page() requests only.
|
||||
* Depends on: .pr-abbr elements in the DOM with data-def attributes; CSS in
|
||||
* style.css (.pr-abbr-popover).
|
||||
*
|
||||
* @see inc/verdict-helpers.php — peptide_starter_render_desc() emits .pr-abbr elements
|
||||
* @see style.css — .pr-abbr, .pr-abbr-popover visual styles
|
||||
* @package peptide-starter
|
||||
*/
|
||||
|
||||
( function () {
|
||||
'use strict';
|
||||
|
||||
var POPOVER_CLASS = 'pr-abbr-popover';
|
||||
var ACTIVE_CLASS = 'pr-abbr--active';
|
||||
var activePopover = null;
|
||||
var activeAbbr = null;
|
||||
|
||||
/**
|
||||
* Remove the currently open popover, if any.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function closePopover() {
|
||||
if ( activePopover ) {
|
||||
activePopover.remove();
|
||||
activePopover = null;
|
||||
}
|
||||
if ( activeAbbr ) {
|
||||
activeAbbr.classList.remove( ACTIVE_CLASS );
|
||||
activeAbbr.removeAttribute( 'aria-expanded' );
|
||||
activeAbbr = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and position a popover anchored to the given abbr element.
|
||||
*
|
||||
* @param {HTMLElement} abbr - The .pr-abbr element that was activated.
|
||||
* @return {void}
|
||||
*/
|
||||
function openPopover( abbr ) {
|
||||
closePopover();
|
||||
|
||||
var def = abbr.getAttribute( 'data-def' );
|
||||
if ( ! def ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var popover = document.createElement( 'div' );
|
||||
popover.className = POPOVER_CLASS;
|
||||
popover.textContent = def;
|
||||
popover.setAttribute( 'role', 'tooltip' );
|
||||
popover.setAttribute( 'id', POPOVER_CLASS + '-' + Date.now() );
|
||||
|
||||
document.body.appendChild( popover );
|
||||
|
||||
// Position below the abbr, clamped to viewport width.
|
||||
var rect = abbr.getBoundingClientRect();
|
||||
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
||||
var top = rect.bottom + scrollTop + 6;
|
||||
var left = rect.left + scrollLeft;
|
||||
var maxLeft = window.innerWidth - popover.offsetWidth - 16;
|
||||
|
||||
popover.style.top = top + 'px';
|
||||
popover.style.left = Math.max( 8, Math.min( left, maxLeft ) ) + 'px';
|
||||
|
||||
abbr.classList.add( ACTIVE_CLASS );
|
||||
abbr.setAttribute( 'aria-expanded', 'true' );
|
||||
abbr.setAttribute( 'aria-describedby', popover.id );
|
||||
|
||||
activePopover = popover;
|
||||
activeAbbr = abbr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the popover for an abbr element (open if closed, close if open).
|
||||
*
|
||||
* @param {HTMLElement} abbr - The .pr-abbr element that was activated.
|
||||
* @return {void}
|
||||
*/
|
||||
function togglePopover( abbr ) {
|
||||
if ( activeAbbr === abbr ) {
|
||||
closePopover();
|
||||
} else {
|
||||
openPopover( abbr );
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Event listeners
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
document.addEventListener( 'click', function ( e ) {
|
||||
var abbr = e.target.closest( '.pr-abbr' );
|
||||
if ( abbr ) {
|
||||
e.stopPropagation();
|
||||
togglePopover( abbr );
|
||||
return;
|
||||
}
|
||||
// Click outside any abbr — close.
|
||||
closePopover();
|
||||
} );
|
||||
|
||||
document.addEventListener( 'keydown', function ( e ) {
|
||||
if ( e.key === 'Escape' ) {
|
||||
closePopover();
|
||||
return;
|
||||
}
|
||||
if ( e.key === 'Enter' || e.key === ' ' ) {
|
||||
var abbr = e.target.closest( '.pr-abbr' );
|
||||
if ( abbr ) {
|
||||
e.preventDefault();
|
||||
togglePopover( abbr );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
// Close when focus leaves the popover+abbr pair entirely.
|
||||
document.addEventListener( 'focusin', function ( e ) {
|
||||
if (
|
||||
activeAbbr &&
|
||||
! activeAbbr.contains( e.target ) &&
|
||||
( ! activePopover || ! activePopover.contains( e.target ) )
|
||||
) {
|
||||
closePopover();
|
||||
}
|
||||
} );
|
||||
} )();
|
||||
Reference in New Issue
Block a user