1111import DomUtil from "WoltLabSuite/Core/Dom/Util" ;
1212import { getPhrase } from "WoltLabSuite/Core/Language" ;
1313import { wheneverFirstSeen } from "WoltLabSuite/Core/Helper/Selector" ;
14- import { set as setAlignment } from "WoltLabSuite/Core/Ui/Alignment" ;
1514import { CKEditor } from "WoltLabSuite/Core/Component/Ckeditor" ;
1615import {
1716 saveQuote ,
@@ -38,6 +37,13 @@ let selectedMessage:
3837 container : Container ;
3938 } ;
4039
40+ interface ElementBoundaries {
41+ bottom : number ;
42+ left : number ;
43+ right : number ;
44+ top : number ;
45+ }
46+
4147const containers = new Map < string , Container > ( ) ;
4248const quoteMessageButtons = new Map < string , HTMLElement > ( ) ;
4349let activeMessageId = "" ;
@@ -456,7 +462,7 @@ function onMouseUp(event?: MouseEvent): void {
456462 copyQuote . classList . remove ( "touchForceInaccessible" ) ;
457463 }
458464
459- setAlignment ( copyQuote , endContainer ) ;
465+ alignQuoteButtons ( content ) ;
460466
461467 copyQuote . classList . remove ( "active" ) ;
462468 if ( wasInaccessible ) {
@@ -492,3 +498,42 @@ function removeSelection(): void {
492498 selection . removeAllRanges ( ) ;
493499 }
494500}
501+
502+ function alignQuoteButtons ( content : HTMLElement ) : void {
503+ const coordinates = getElementBoundaries ( window . getSelection ( ) ) ! ;
504+ const dimensions = { height : copyQuote . offsetHeight , width : copyQuote . offsetWidth } ;
505+ let left = ( coordinates . right - coordinates . left ) / 2 - dimensions . width / 2 + coordinates . left ;
506+
507+ // Prevent the overlay from overflowing the left or right boundary of the container.
508+ const containerBoundaries = content . getBoundingClientRect ( ) ;
509+ if ( left < containerBoundaries . left ) {
510+ left = containerBoundaries . left ;
511+ } else if ( left + dimensions . width > containerBoundaries . right ) {
512+ left = containerBoundaries . right - dimensions . width ;
513+ }
514+
515+ copyQuote . style . setProperty ( "top" , `${ coordinates . bottom + 7 } px` ) ;
516+ copyQuote . style . setProperty ( "left" , `${ left } px` ) ;
517+ }
518+
519+ function getElementBoundaries ( selection : Selection | null ) : ElementBoundaries | null {
520+ if ( ! selection ) {
521+ return null ;
522+ }
523+
524+ if ( selection . rangeCount <= 0 ) {
525+ return null ;
526+ }
527+
528+ // The coordinates returned by getBoundingClientRect() are relative to the
529+ // viewport, not the document.
530+ const rect = selection . getRangeAt ( 0 ) . getBoundingClientRect ( ) ;
531+
532+ const scrollTop = window . scrollY ;
533+ return {
534+ bottom : rect . bottom + scrollTop ,
535+ left : rect . left ,
536+ right : rect . right ,
537+ top : rect . top + scrollTop ,
538+ } ;
539+ }
0 commit comments