Fix more Scribe mobile issues
- Add getSavedSelection to check saved selection without consuming it - Distinguish between setText (replace all) and insertText (at cursor) operations - Fix replace callback to use setText when no selection exists - Clean up saved selection state after restoration in HTML utils - Move mobile editor focus and selection restore to appropriate callbacks
This commit is contained in:
@@ -235,6 +235,7 @@ class HtmlUtils {
|
|||||||
if (selection) {
|
if (selection) {
|
||||||
selection.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
selection.addRange(window._savedRange);
|
selection.addRange(window._savedRange);
|
||||||
|
delete window._savedRange;
|
||||||
return selection.toString();
|
return selection.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,6 +243,17 @@ class HtmlUtils {
|
|||||||
})();''',
|
})();''',
|
||||||
name: 'restoreSelection');
|
name: 'restoreSelection');
|
||||||
|
|
||||||
|
static const getSavedSelection = (
|
||||||
|
script: '''
|
||||||
|
(() => {
|
||||||
|
if(window._savedRange) {
|
||||||
|
return window._savedRange.toString();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
})();''',
|
||||||
|
name: 'getSavedSelection');
|
||||||
|
|
||||||
static const clearSavedSelection = (
|
static const clearSavedSelection = (
|
||||||
script: '''
|
script: '''
|
||||||
(() => {
|
(() => {
|
||||||
|
|||||||
+59
-23
@@ -34,11 +34,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> insertTextInEditor(String text) async {
|
Future<void> insertTextInEditor(String text) async {
|
||||||
if (PlatformInfo.isMobile) {
|
|
||||||
await ensureMobileEditorFocused();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final htmlContent = StringConvert.convertTextContentToHtmlContent(text);
|
final htmlContent = StringConvert.convertTextContentToHtmlContent(text);
|
||||||
|
|
||||||
@@ -57,6 +53,18 @@ extension HandleAiScribeInComposerExtension on ComposerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> 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<void> collapseSelection() async {
|
Future<void> collapseSelection() async {
|
||||||
try {
|
try {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb) {
|
||||||
@@ -117,6 +125,28 @@ extension HandleAiScribeInComposerExtension on ComposerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> 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<void> clearSavedSelection() async {
|
Future<void> clearSavedSelection() async {
|
||||||
try {
|
try {
|
||||||
if (PlatformInfo.isWeb) {
|
if (PlatformInfo.isWeb) {
|
||||||
@@ -158,21 +188,15 @@ extension HandleAiScribeInComposerExtension on ComposerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> 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<void> onInsertTextCallback(String text) async {
|
Future<void> onInsertTextCallback(String text) async {
|
||||||
|
if (PlatformInfo.isMobile) {
|
||||||
|
await ensureMobileEditorFocused();
|
||||||
|
|
||||||
|
await restoreSelection();
|
||||||
|
}
|
||||||
|
|
||||||
await collapseSelection();
|
await collapseSelection();
|
||||||
|
|
||||||
await insertTextInEditor(text);
|
await insertTextInEditor(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,13 +204,25 @@ extension HandleAiScribeInComposerExtension on ComposerController {
|
|||||||
Future<void> onReplaceTextCallback(String text) async {
|
Future<void> onReplaceTextCallback(String text) async {
|
||||||
final selection = editorTextSelection.value?.selectedText;
|
final selection = editorTextSelection.value?.selectedText;
|
||||||
|
|
||||||
final isSelectionRestored = PlatformInfo.isMobile ? await restoreSelection() : "";
|
final savedSelection = PlatformInfo.isMobile ? await getSavedSelection() : "";
|
||||||
|
|
||||||
if ((selection == null || selection.isEmpty) && isSelectionRestored.isEmpty) {
|
final shouldReplaceEverything = (selection == null || selection.isEmpty) && savedSelection.isEmpty;
|
||||||
await clearTextInEditor();
|
|
||||||
|
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<void> openAIAssistantModal(Offset? position, Size? size) async {
|
Future<void> openAIAssistantModal(Offset? position, Size? size) async {
|
||||||
|
|||||||
Reference in New Issue
Block a user