diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart index 7c89c2ed83..00826e41f7 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart @@ -149,6 +149,46 @@ _pastRichClipboard(EditorState editorState, RichClipboardData data) { } } +_pasteSingleLine(EditorState editorState, Selection selection, String line) { + final node = editorState.document.nodeAtPath(selection.end.path)! as TextNode; + final beginOffset = selection.end.offset; + TransactionBuilder(editorState) + ..textEdit( + node, + () => Delta() + ..retain(beginOffset) + ..addAll(_lineContentToDelta(line))) + ..setAfterSelection(Selection.collapsed( + Position(path: selection.end.path, offset: beginOffset + line.length))) + ..commit(); +} + +/// parse url from the line text +/// reference: https://stackoverflow.com/questions/59444837/flutter-dart-regex-to-extract-urls-from-a-string +Delta _lineContentToDelta(String lineContent) { + final exp = RegExp(r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+'); + final Iterable matches = exp.allMatches(lineContent); + + final delta = Delta(); + + var lastUrlEndOffset = 0; + + for (final match in matches) { + if (lastUrlEndOffset < match.start) { + delta.insert(lineContent.substring(lastUrlEndOffset, match.start)); + } + final linkContent = lineContent.substring(match.start, match.end); + delta.insert(linkContent, {"href": linkContent}); + lastUrlEndOffset = match.end; + } + + if (lastUrlEndOffset < lineContent.length) { + delta.insert(lineContent.substring(lastUrlEndOffset, lineContent.length)); + } + + return delta; +} + _handlePastePlainText(EditorState editorState, String plainText) { final selection = editorState.cursorSelection?.normalize(); if (selection == null) { @@ -163,18 +203,8 @@ _handlePastePlainText(EditorState editorState, String plainText) { if (lines.isEmpty) { return; } else if (lines.length == 1) { - final node = - editorState.document.nodeAtPath(selection.end.path)! as TextNode; - final beginOffset = selection.end.offset; - TransactionBuilder(editorState) - ..textEdit( - node, - () => Delta() - ..retain(beginOffset) - ..insert(lines[0])) - ..setAfterSelection(Selection.collapsed(Position( - path: selection.end.path, offset: beginOffset + lines[0].length))) - ..commit(); + // single line + _pasteSingleLine(editorState, selection, lines.first); } else { final firstLine = lines[0]; final beginOffset = selection.end.offset; @@ -196,11 +226,9 @@ _handlePastePlainText(EditorState editorState, String plainText) { if (index++ == remains.length - 1) { return TextNode( type: "text", - delta: Delta() - ..insert(e) - ..addAll(insertedLineSuffix)); + delta: _lineContentToDelta(e)..addAll(insertedLineSuffix)); } - return TextNode(type: "text", delta: Delta()..insert(e)); + return TextNode(type: "text", delta: _lineContentToDelta(e)); }).toList(); // insert first line tb.textEdit(