diff --git a/core/lib/utils/html/html_utils.dart b/core/lib/utils/html/html_utils.dart
index d0c04dff4..614cb97ea 100644
--- a/core/lib/utils/html/html_utils.dart
+++ b/core/lib/utils/html/html_utils.dart
@@ -235,6 +235,7 @@ class HtmlUtils {
if (selection) {
selection.removeAllRanges();
selection.addRange(window._savedRange);
+ delete window._savedRange;
return selection.toString();
}
}
@@ -242,6 +243,17 @@ class HtmlUtils {
})();''',
name: 'restoreSelection');
+ static const getSavedSelection = (
+ script: '''
+ (() => {
+ if(window._savedRange) {
+ return window._savedRange.toString();
+ } else {
+ return "";
+ }
+ })();''',
+ name: 'getSavedSelection');
+
static const clearSavedSelection = (
script: '''
(() => {
diff --git a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
index 34a7ada6c..4178e8d8d 100644
--- a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
+++ b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
@@ -34,11 +34,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
}
}
- Future insertTextInEditor(String text) async {
- if (PlatformInfo.isMobile) {
- await ensureMobileEditorFocused();
- }
-
+ Future insertTextInEditor(String text) async {
try {
final htmlContent = StringConvert.convertTextContentToHtmlContent(text);
@@ -57,6 +53,18 @@ extension HandleAiScribeInComposerExtension on ComposerController {
}
}
+ Future setTextInEditor(String text) async {
+ try {
+ if (PlatformInfo.isWeb) {
+ richTextWebController?.editorController.setText(text);
+ } else {
+ await richTextMobileTabletController?.htmlEditorApi?.setText(text);
+ }
+ } catch (e) {
+ logError('$runtimeType::insertTextInEditor:Exception = $e');
+ }
+ }
+
Future collapseSelection() async {
try {
if (PlatformInfo.isWeb) {
@@ -117,6 +125,28 @@ extension HandleAiScribeInComposerExtension on ComposerController {
}
}
+ Future getSavedSelection() async {
+ try {
+ if (PlatformInfo.isWeb) {
+ final result = await richTextWebController?.editorController.evaluateJavascriptWeb(
+ HtmlUtils.getSavedSelection.name,
+ hasReturnValue: true,
+ );
+ return result;
+ } else {
+ final result = await richTextMobileTabletController?.htmlEditorApi?.webViewController
+ .evaluateJavascript(
+ source: HtmlUtils.getSavedSelection.script,
+ );
+ return result;
+ }
+ } catch (e) {
+ logError('$runtimeType::getSavedSelection:Exception = $e');
+ return "";
+ }
+ }
+
+
Future clearSavedSelection() async {
try {
if (PlatformInfo.isWeb) {
@@ -158,21 +188,15 @@ extension HandleAiScribeInComposerExtension on ComposerController {
}
}
- Future clearTextInEditor() async {
- try {
- if (PlatformInfo.isWeb) {
- richTextWebController?.editorController.setText('');
- } else {
- await richTextMobileTabletController?.htmlEditorApi?.setText('');
- }
- } catch (e) {
- logWarning('$runtimeType::clearTextInEditor:Exception = $e');
- }
- }
-
- // Ensure we only insert at cursor position by collapsing selection before inserting
Future onInsertTextCallback(String text) async {
+ if (PlatformInfo.isMobile) {
+ await ensureMobileEditorFocused();
+
+ await restoreSelection();
+ }
+
await collapseSelection();
+
await insertTextInEditor(text);
}
@@ -180,13 +204,25 @@ extension HandleAiScribeInComposerExtension on ComposerController {
Future onReplaceTextCallback(String text) async {
final selection = editorTextSelection.value?.selectedText;
- final isSelectionRestored = PlatformInfo.isMobile ? await restoreSelection() : "";
+ final savedSelection = PlatformInfo.isMobile ? await getSavedSelection() : "";
- if ((selection == null || selection.isEmpty) && isSelectionRestored.isEmpty) {
- await clearTextInEditor();
+ final shouldReplaceEverything = (selection == null || selection.isEmpty) && savedSelection.isEmpty;
+
+ if (shouldReplaceEverything) {
+ try {
+ await setTextInEditor(text);
+ } catch (e) {
+ logError('$runtimeType::onReplaceTextCallback:Exception = $e');
+ }
+ } else {
+ if (PlatformInfo.isMobile) {
+ await ensureMobileEditorFocused();
+
+ await restoreSelection();
+ }
+
+ await insertTextInEditor(text);
}
-
- await insertTextInEditor(text);
}
Future openAIAssistantModal(Offset? position, Size? size) async {