- Add abbrs field to Established verdict taxonomy item - Add peptide_starter_render_desc() helper — builds safe HTML from esc_html/esc_attr components; replaces abbr terms with <abbr> tap-targets - Update front-page.php description output to use render_desc() - Add assets/js/abbr-tooltip.js — popover open/close, outside-click dismissal, keyboard accessibility (Enter/Space/Escape), ARIA attrs - Enqueue abbr-tooltip.js on is_front_page() only - Add .pr-abbr and .pr-abbr-popover CSS with dashed underline affordance, fade-in animation, dark-mode-safe surface variables - Fix PEPTIDE_STARTER_VERSION drift: 2.0.0-alpha.3 → 2.2.1 Routing note: this is a theme change (not PR Core). Term 'RCT' is scoped to the verdict legend strip only; monograph bodies are unaffected.
135 lines
3.7 KiB
JavaScript
135 lines
3.7 KiB
JavaScript
/**
|
|
* 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();
|
|
}
|
|
} );
|
|
} )();
|