@@ -3,8 +3,7 @@ import { tracked } from "@glimmer/tracking";
33import { action } from " @ember/object" ;
44import { service } from " @ember/service" ;
55import DButton from " discourse/components/d-button" ;
6- import virtualElementFromTextRange from " discourse/lib/virtual-element-from-text-range" ;
7- import eq from " truth-helpers/helpers/eq" ;
6+ import { selectedRange } from " discourse/lib/utilities" ;
87import AiPostHelperMenu from " ../../components/ai-post-helper-menu" ;
98import { showPostAIHelper } from " ../../lib/show-ai-helper" ;
109
@@ -13,12 +12,8 @@ export default class AiPostHelperTrigger extends Component {
1312 return showPostAIHelper (outletArgs, helper);
1413 }
1514
16- @service site;
1715 @service menu;
1816
19- @tracked menuState = this .MENU_STATES .triggers ;
20- @tracked showMainButtons = true ;
21- @tracked showAiButtons = true ;
2217 @tracked postHighlighted = false ;
2318 @tracked currentMenu = this .menu .getByIdentifier (
2419 " post-text-selection-toolbar"
@@ -27,14 +22,20 @@ export default class AiPostHelperTrigger extends Component {
2722 MENU_STATES = {
2823 triggers: " TRIGGERS" ,
2924 options: " OPTIONS" ,
25+ // so we ensure change of state (selection change for example)
26+ // is not impacting the menu data
27+ menuData = {
28+ ... this .args .outletArgs .data ,
29+ quoteState: {
30+ buffer: this .args .outletArgs .data .quoteState .buffer ,
31+ opts: this .args .outletArgs .data .quoteState .opts ,
32+ postId: this .args .outletArgs .data .quoteState .postId ,
33+ },
34+ post: this .args .outletArgs .post ,
35+ selectedRange: selectedRange (),
3036 };
3137
32- willDestroy () {
33- super .willDestroy (... arguments );
34- this .removeHighlightedText ();
35- }
36-
37- highlightSelectedText () {
38+ highlightSelectedText (selection ) {
3839 const postId = this .args .outletArgs .data .quoteState .postId ;
3940 const postElement = document .querySelector (
4041 ` article[data-post-id='${ postId} '] .cooked`
@@ -44,14 +45,7 @@ export default class AiPostHelperTrigger extends Component {
4445 return ;
4546 }
4647
47- this .selectedText = this .args .outletArgs .data .quoteState .buffer ;
48-
49- const selection = window .getSelection ();
50- if (! selection .rangeCount ) {
51- return ;
52- }
53-
54- const range = selection .getRangeAt (0 );
48+ const range = this .menuData .selectedRange ;
5549
5650 // Split start/end text nodes at their range boundary
5751 if (
@@ -97,11 +91,10 @@ export default class AiPostHelperTrigger extends Component {
9791 // Replace textNode with highlighted clone
9892 const clone = textNode .cloneNode (true );
9993 highlight .appendChild (clone);
100-
10194 textNode .parentNode .replaceChild (highlight, textNode);
10295 }
10396
104- selection .removeAllRanges ();
97+ window . getSelection () .removeAllRanges ();
10598 this .postHighlighted = true ;
10699 }
107100
@@ -110,16 +103,7 @@ export default class AiPostHelperTrigger extends Component {
110103 return ;
111104 }
112105
113- const postId = this .args .outletArgs .data .quoteState .postId ;
114- const postElement = document .querySelector (
115- ` article[data-post-id='${ postId} '] .cooked`
116- );
117-
118- if (! postElement) {
119- return ;
120- }
121-
122- const highlightedSpans = postElement .querySelectorAll (
106+ const highlightedSpans = document .querySelectorAll (
123107 " span.ai-helper-highlighted-selection"
124108 );
125109
@@ -133,65 +117,44 @@ export default class AiPostHelperTrigger extends Component {
133117
134118 @action
135119 async showAiPostHelperMenu () {
136- this .highlightSelectedText ();
137- if (this .site .mobileView ) {
138- this .currentMenu .close ();
139-
140- await this .menu .show (virtualElementFromTextRange (), {
141- identifier: " ai-post-helper-menu" ,
142- component: AiPostHelperMenu,
143- inline: true ,
144- interactive: true ,
145- placement: this .shouldRenderUnder ? " bottom-start" : " top-start" ,
146- fallbackPlacements: this .shouldRenderUnder
147- ? [" bottom-end" , " top-start" ]
148- : [" bottom-start" ],
149- trapTab: false ,
150- closeOnScroll: false ,
151- modalForMobile: true ,
152- data: this .menuData ,
153- });
154- }
155-
156- this .showMainButtons = false ;
157- this .menuState = this .MENU_STATES .options ;
158- }
120+ const existingRect = this .currentMenu .trigger .rect ;
121+ const virtualElement = {
122+ getBoundingClientRect : () => existingRect,
123+ getClientRects : () => [existingRect],
124+ };
159125
160- get menuData () {
161- // Streamline of data model to be passed to the component when
162- // instantiated as a DMenu or a simple component in the template
163- return {
164- ... this .args .outletArgs .data ,
165- quoteState: {
166- buffer: this .args .outletArgs .data .quoteState .buffer ,
167- opts: this .args .outletArgs .data .quoteState .opts ,
168- postId: this .args .outletArgs .data .quoteState .postId ,
126+ await this .currentMenu .close ();
127+
128+ await this .menu .show (virtualElement, {
129+ identifier: " ai-post-helper-menu" ,
130+ component: AiPostHelperMenu,
131+ interactive: true ,
132+ trapTab: false ,
133+ closeOnScroll: false ,
134+ modalForMobile: true ,
135+ data: this .menuData ,
136+ placement: " bottom" ,
137+ fallbackPlacements: [" top" ],
138+ inline: true ,
139+ onClose : () => {
140+ this .removeHighlightedText ();
169141 },
170- post : this . args . outletArgs . post ,
171- selectedText : this . selectedText ,
172- } ;
142+ });
143+
144+ this . highlightSelectedText () ;
173145 }
174146
175147 <template >
176- {{#if this . showMainButtons }}
177- {{ yield }}
178- {{/if }}
179-
180- {{#if this . showAiButtons }}
181- <div class =" ai-post-helper" >
182- {{#if ( eq this . menuState this . MENU_STATES.triggers) }}
183- <DButton
184- @ icon =" discourse-sparkles"
185- @ title =" discourse_ai.ai_helper.post_options_menu.title"
186- @ label =" discourse_ai.ai_helper.post_options_menu.trigger"
187- @ action ={{this .showAiPostHelperMenu }}
188- class =" btn-flat ai-post-helper__trigger"
189- />
190-
191- {{else if ( eq this . menuState this . MENU_STATES.options) }}
192- <AiPostHelperMenu @ data ={{this .menuData }} />
193- {{/if }}
194- </div >
195- {{/if }}
148+ {{ yield }}
149+
150+ <div class =" ai-post-helper" >
151+ <DButton
152+ @ icon =" discourse-sparkles"
153+ @ title =" discourse_ai.ai_helper.post_options_menu.title"
154+ @ label =" discourse_ai.ai_helper.post_options_menu.trigger"
155+ @ action ={{this .showAiPostHelperMenu }}
156+ class =" btn-flat ai-post-helper__trigger"
157+ />
158+ </div >
196159 </template >
197160}
0 commit comments