diff --git a/modules/controller.js b/modules/controller.js index 7e25cca2d..062df9e80 100644 --- a/modules/controller.js +++ b/modules/controller.js @@ -7,7 +7,6 @@ var $pageContainer, newTopicController, - $overlay, featuresEnabled = mw.config.get( 'wgDiscussionToolsFeaturesEnabled' ) || {}, Parser = require( './Parser.js' ), ThreadItem = require( './ThreadItem.js' ), @@ -36,20 +35,23 @@ function highlight( comment ) { var padding = 5, $highlight = $( '
' ).addClass( 'ext-discussiontools-init-highlight' ); - if ( !$overlay ) { - // $overlay must be position:relative/absolute - $overlay = $( '
' ).addClass( 'oo-ui-defaultOverlay' ).appendTo( 'body' ); - } + // We insert the highlight in the DOM near the comment, so that it remains positioned correctly + // when it shifts (e.g. collapsing the table of contents), and disappears when it is hidden (e.g. + // opening visual editor). + var range = comment.getNativeRange(); + // Support: Firefox, IE 11 + // The highlight node must be inserted after the start marker node (data-mw-comment-start), not + // before, otherwise Node#getBoundingClientRect() returns wrong results. + range.insertNode( $highlight[ 0 ] ); - var overlayRect = $overlay[ 0 ].getBoundingClientRect(); - var rect = RangeFix.getBoundingClientRect( comment.getNativeRange() ); + var baseRect = $highlight[ 0 ].getBoundingClientRect(); + var rect = RangeFix.getBoundingClientRect( range ); $highlight.css( { - top: rect.top - overlayRect.top - padding, - left: rect.left - overlayRect.left - padding, + 'margin-top': rect.top - baseRect.top - padding, + 'margin-left': rect.left - baseRect.left - padding, width: rect.width + ( padding * 2 ), height: rect.height + ( padding * 2 ) } ); - $overlay.prepend( $highlight ); return $highlight; } @@ -287,7 +289,6 @@ var $highlightedTarget = null; function highlightTargetComment( parser ) { if ( $highlightedTarget ) { $highlightedTarget.remove(); - $overlay.removeClass( 'ext-discussiontools-init-highlight-overlay' ); $highlightedTarget = null; } // eslint-disable-next-line no-jquery/no-global-selector @@ -297,7 +298,6 @@ function highlightTargetComment( parser ) { $highlightedTarget = highlight( comment ); $highlightedTarget.addClass( 'ext-discussiontools-init-targetcomment' ); $highlightedTarget.addClass( 'ext-discussiontools-init-highlight-fadein' ); - $overlay.addClass( 'ext-discussiontools-init-highlight-overlay' ); } } @@ -460,15 +460,13 @@ function init( $container, state ) { // Show a highlight with the same timing as the post-edit message (mediawiki.action.view.postEdit): // show for 3000ms, fade out for 250ms (animation duration is defined in CSS). OO.ui.Element.static.scrollIntoView( $highlight[ 0 ], { padding: { top: 10, bottom: 10 } } ).then( function () { - // Toggle the 'ext-discussiontools-init-highlight-overlay' class only when needed, because using mix-blend-mode - // affects the text rendering of the whole page, disabling subpixel antialiasing on Windows - $overlay.addClass( 'ext-discussiontools-init-highlight-overlay' ); $highlight.addClass( 'ext-discussiontools-init-highlight-fadein' ); setTimeout( function () { $highlight.addClass( 'ext-discussiontools-init-highlight-fadeout' ); setTimeout( function () { + // Remove the node when no longer needed, because it's using CSS 'mix-blend-mode', which + // affects the text rendering of the whole page, disabling subpixel antialiasing on Windows $highlight.remove(); - $overlay.removeClass( 'ext-discussiontools-init-highlight-overlay' ); }, 250 ); }, 3000 ); } ); diff --git a/modules/dt.init.less b/modules/dt.init.less index 9c404fe7e..84ba7220d 100644 --- a/modules/dt.init.less +++ b/modules/dt.init.less @@ -74,7 +74,7 @@ span[ data-mw-comment-start ] { } @supports ( mix-blend-mode: multiply ) { - .ext-discussiontools-init-highlight-overlay { + .ext-discussiontools-init-highlight { mix-blend-mode: multiply; // Support: Safari // Safari doesn't blend this overlay with the text unless GPU rendering is forced.