1- import { Directive , ElementRef , EventEmitter , NgZone , OnDestroy , OnInit , Output } from '@angular/core' ;
1+ import {
2+ ApplicationRef , ComponentFactoryResolver ,
3+ ComponentRef ,
4+ Directive ,
5+ ElementRef ,
6+ EmbeddedViewRef ,
7+ Injector ,
8+ NgZone ,
9+ OnDestroy ,
10+ OnInit
11+ } from '@angular/core' ;
12+ import { TextSelectionTooltipComponent } from './text-selection-tooltip/text-selection-tooltip.component' ;
213
314// Define the structure of the event that will be emitted when text is selected.
415export interface TextSelectEvent {
@@ -15,22 +26,24 @@ interface SelectionRectangle {
1526 height : number ;
1627}
1728
29+
1830// This directive emits an event when the user selects text within the host element.
1931@Directive ( {
20- selector : '[dsTextSelect ]' ,
32+ selector : '[dsTextSelectTooltip ]' ,
2133} )
2234export class TextSelectDirective implements OnInit , OnDestroy {
2335
24- // Event emitter for the text select event.
25- @Output ( )
26- dsTextSelect : EventEmitter < TextSelectEvent > = new EventEmitter ( ) ;
27-
2836 hasSelection = false ;
2937
38+ private componentRef : ComponentRef < any > = null ;
39+
3040 // Initialize the directive.
3141 constructor (
3242 private elementRef : ElementRef ,
33- private zone : NgZone
43+ private zone : NgZone ,
44+ private appRef : ApplicationRef ,
45+ private componentFactoryResolver : ComponentFactoryResolver ,
46+ private injector : Injector
3447 ) {
3548 }
3649
@@ -42,6 +55,7 @@ export class TextSelectDirective implements OnInit, OnDestroy {
4255
4356 // Set up event listeners when the directive is initialized.
4457 public ngOnInit ( ) : void {
58+ this . elementRef . nativeElement . style . position = 'relative' ;
4559 this . zone . runOutsideAngular ( ( ) => {
4660 this . elementRef . nativeElement . addEventListener ( 'mousedown' , this . handleMousedown , false ) ;
4761 } ) ;
@@ -75,45 +89,44 @@ export class TextSelectDirective implements OnInit, OnDestroy {
7589 // this solves the issue of the previous selection not being cleared before the mouseup event
7690 setTimeout ( ( ) => {
7791 const selection = document . getSelection ( ) ;
92+ const stringSelection = selection . toString ( ) . trim ( ) ;
7893 if ( this . hasSelection ) {
7994 this . zone . runGuarded ( ( ) => {
8095 this . hasSelection = false ;
81- this . dsTextSelect . next ( {
82- text : '' ,
83- viewportRectangle : null ,
84- hostRectangle : null
85- } ) ;
8696 } ) ;
97+ this . componentRef . destroy ( ) ;
98+ this . componentRef = null ;
8799 }
88- if ( ! selection . rangeCount || ! selection . toString ( ) ) {
100+ if ( ! selection . rangeCount || ! stringSelection ) {
89101 return ;
90102 }
91103 let range = selection . getRangeAt ( 0 ) ;
92104 let rangeContainer = this . getRangeContainer ( range ) ;
93105 if ( this . elementRef . nativeElement . contains ( rangeContainer ) ) {
94106 let viewportRectangle = range . getBoundingClientRect ( ) ;
95107 let localRectangle = this . viewportToHost ( viewportRectangle , rangeContainer ) ;
96- const stringSelection = selection . toString ( ) ;
97108 if ( stringSelection ) {
98109 this . zone . runGuarded ( ( ) => {
99110 this . hasSelection = true ;
100- this . dsTextSelect . emit ( {
101- text : stringSelection ,
102- viewportRectangle : {
103- left : viewportRectangle . left ,
104- top : viewportRectangle . top ,
105- width : viewportRectangle . width ,
106- height : viewportRectangle . height
107- } ,
108- hostRectangle : {
109- left : localRectangle . left ,
110- top : localRectangle . top ,
111- width : localRectangle . width ,
112- height : localRectangle . height
113- }
114- } ) ;
115111 } ) ;
116112 }
113+ if ( this . componentRef === null ) {
114+ const componentFactory =
115+ this . componentFactoryResolver . resolveComponentFactory ( TextSelectionTooltipComponent ) ;
116+ this . componentRef = componentFactory . create ( this . injector ) ;
117+
118+ this . appRef . attachView ( this . componentRef . hostView ) ;
119+
120+ const domElem =
121+ ( this . componentRef . hostView as EmbeddedViewRef < any > )
122+ . rootNodes [ 0 ] as HTMLElement ;
123+
124+ document . body . appendChild ( domElem ) ;
125+
126+ this . componentRef . instance . left = localRectangle . left + localRectangle . width / 2 ;
127+ this . componentRef . instance . top = localRectangle . top ;
128+ this . componentRef . instance . text = stringSelection ;
129+ }
117130 }
118131 } ) ;
119132 }
0 commit comments