@@ -850,18 +850,33 @@ function loadCss(cssUrl) {
850850 }
851851 hideNotable ( ) ;
852852 const ty = e . getAttribute ( "data-ty" ) ;
853- const tooltip = e . getElementsByClassName ( "notable-traits-tooltip" ) [ 0 ] ;
854853 const wrapper = document . createElement ( "div" ) ;
855854 wrapper . innerHTML = "<div class=\"docblock\">" + window . NOTABLE_TRAITS [ ty ] + "</div>" ;
856- wrapper . className = "notable-traits-tooltiptext" ;
857- tooltip . appendChild ( wrapper ) ;
858- const pos = wrapper . getBoundingClientRect ( ) ;
859- tooltip . removeChild ( wrapper ) ;
860- wrapper . style . top = ( pos . top + window . scrollY ) + "px" ;
861- wrapper . style . left = ( pos . left + window . scrollX ) + "px" ;
862- wrapper . style . width = pos . width + "px" ;
855+ wrapper . className = "notable popover" ;
856+ const focusCatcher = document . createElement ( "div" ) ;
857+ focusCatcher . setAttribute ( "tabindex" , "0" ) ;
858+ focusCatcher . onfocus = hideNotable ;
859+ wrapper . appendChild ( focusCatcher ) ;
860+ const pos = e . getBoundingClientRect ( ) ;
861+ // 5px overlap so that the mouse can easily travel from place to place
862+ wrapper . style . top = ( pos . top + window . scrollY + pos . height ) + "px" ;
863+ wrapper . style . left = 0 ;
864+ wrapper . style . right = "auto" ;
865+ wrapper . style . visibility = "hidden" ;
863866 const body = document . getElementsByTagName ( "body" ) [ 0 ] ;
864867 body . appendChild ( wrapper ) ;
868+ const wrapperPos = wrapper . getBoundingClientRect ( ) ;
869+ // offset so that the arrow points at the center of the "(i)"
870+ const finalPos = pos . left + window . scrollX - wrapperPos . width + 24 ;
871+ if ( finalPos > 0 ) {
872+ wrapper . style . left = finalPos + "px" ;
873+ } else {
874+ wrapper . style . setProperty (
875+ "--popover-arrow-offset" ,
876+ ( wrapperPos . right - pos . right + 4 ) + "px"
877+ ) ;
878+ }
879+ wrapper . style . visibility = "" ;
865880 window . CURRENT_NOTABLE_ELEMENT = wrapper ;
866881 window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE = e ;
867882 wrapper . onpointerleave = function ( ev ) {
@@ -875,9 +890,31 @@ function loadCss(cssUrl) {
875890 } ;
876891 }
877892
893+ function notableBlurHandler ( event ) {
894+ if ( window . CURRENT_NOTABLE_ELEMENT &&
895+ ! elemIsInParent ( document . activeElement , window . CURRENT_NOTABLE_ELEMENT ) &&
896+ ! elemIsInParent ( event . relatedTarget , window . CURRENT_NOTABLE_ELEMENT ) &&
897+ ! elemIsInParent ( document . activeElement , window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE ) &&
898+ ! elemIsInParent ( event . relatedTarget , window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE )
899+ ) {
900+ // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
901+ // When I click the button on an already-opened notable trait popover, Safari
902+ // hides the popover and then immediately shows it again, while everyone else hides it
903+ // and it stays hidden.
904+ //
905+ // To work around this, make sure the click finishes being dispatched before
906+ // hiding the popover. Since `hideNotable()` is idempotent, this makes Safari behave
907+ // consistently with the other two.
908+ setTimeout ( hideNotable , 0 ) ;
909+ }
910+ }
911+
878912 function hideNotable ( ) {
879913 if ( window . CURRENT_NOTABLE_ELEMENT ) {
880- window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE . NOTABLE_FORCE_VISIBLE = false ;
914+ if ( window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE . NOTABLE_FORCE_VISIBLE ) {
915+ window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE . focus ( ) ;
916+ window . CURRENT_NOTABLE_ELEMENT . NOTABLE_BASE . NOTABLE_FORCE_VISIBLE = false ;
917+ }
881918 const body = document . getElementsByTagName ( "body" ) [ 0 ] ;
882919 body . removeChild ( window . CURRENT_NOTABLE_ELEMENT ) ;
883920 window . CURRENT_NOTABLE_ELEMENT = null ;
@@ -891,7 +928,11 @@ function loadCss(cssUrl) {
891928 hideNotable ( ) ;
892929 } else {
893930 showNotable ( this ) ;
931+ window . CURRENT_NOTABLE_ELEMENT . setAttribute ( "tabindex" , "0" ) ;
932+ window . CURRENT_NOTABLE_ELEMENT . focus ( ) ;
933+ window . CURRENT_NOTABLE_ELEMENT . onblur = notableBlurHandler ;
894934 }
935+ return false ;
895936 } ;
896937 e . onpointerenter = function ( ev ) {
897938 // If this is a synthetic touch event, ignore it. A click event will be along shortly.
@@ -1018,6 +1059,7 @@ function loadCss(cssUrl) {
10181059 onEachLazy ( document . querySelectorAll ( ".search-form .popover" ) , elem => {
10191060 elem . style . display = "none" ;
10201061 } ) ;
1062+ hideNotable ( ) ;
10211063 } ;
10221064
10231065 /**
0 commit comments