From b8f9ff58f61c3a0cfb96100435b7280cf8cb89fd Mon Sep 17 00:00:00 2001 From: AtlasAutocode Date: Fri, 26 Jul 2024 10:52:19 -0600 Subject: [PATCH] Paste multiline selection --- lib/src/controller/quill_controller.dart | 34 +++++++++--------------- lib/src/delta/delta_diff.dart | 13 +++++---- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/lib/src/controller/quill_controller.dart b/lib/src/controller/quill_controller.dart index c328cf77..4ceb788a 100644 --- a/lib/src/controller/quill_controller.dart +++ b/lib/src/controller/quill_controller.dart @@ -477,10 +477,13 @@ class QuillController extends ChangeNotifier { /// Clipboard caches last copy to allow paste with styles. Static to allow paste between multiple instances of editor. static String _pastePlainText = ''; + static Delta _pasteDelta = Delta(); static List _pasteStyleAndEmbed = []; String get pastePlainText => _pastePlainText; + Delta get pasteDelta => _pasteDelta; List get pasteStyleAndEmbed => _pasteStyleAndEmbed; + bool readOnly; /// Used to give focus to the editor following a toolbar action @@ -507,6 +510,9 @@ class QuillController extends ChangeNotifier { /// Get the internal representation so it can be pasted into a QuillEditor with style retained. _pasteStyleAndEmbed = getAllIndividualSelectionStylesAndEmbed(); + /// Get the deltas for the selection so they can be pasted into a QuillEditor with styles and embeds retained. + _pasteDelta = document.toDelta().slice(selection.start, selection.end); + if (!selection.isCollapsed) { Clipboard.setData(ClipboardData(text: _pastePlainText)); if (!copy) { @@ -547,27 +553,13 @@ class QuillController extends ChangeNotifier { // See https://github.com/flutter/flutter/issues/11427 final plainTextClipboardData = await Clipboard.getData(Clipboard.kTextPlain); - if (plainTextClipboardData != null) { - final lines = plainTextClipboardData.text!.split('\n'); - for (var i = 0; i < lines.length; ++i) { - final line = lines[i]; - if (line.isNotEmpty) { - replaceTextWithEmbeds( - selection.start, - selection.end - selection.start, - line, - TextSelection.collapsed(offset: selection.start + line.length), - ); - } - if (i != lines.length - 1) { - document.insert(selection.extentOffset, '\n'); - _updateSelection( - TextSelection.collapsed( - offset: selection.extentOffset + 1, - ), - insertNewline: true, - ); - } + if (plainTextClipboardData?.text != null) { + + /// Internal copy-paste preserves styles and embeds + if ( plainTextClipboardData!.text == _pastePlainText && _pastePlainText.isNotEmpty && _pasteDelta.isNotEmpty ) { + replaceText(selection.start, selection.end - selection.start, _pasteDelta, TextSelection.collapsed(offset: selection.end)); + } else { + replaceText(selection.start, selection.end - selection.start, plainTextClipboardData.text, TextSelection.collapsed(offset: selection.end + plainTextClipboardData.text!.length)); } updateEditor?.call(); return true; diff --git a/lib/src/delta/delta_diff.dart b/lib/src/delta/delta_diff.dart index 82dccf5a..29df932e 100644 --- a/lib/src/delta/delta_diff.dart +++ b/lib/src/delta/delta_diff.dart @@ -70,19 +70,18 @@ int getPositionDelta(Delta user, Delta actual) { ); } if (userOperation.key == actualOperation.key) { + /// Insertions must update diff allowing for type mismatch of Operation + if ( userOperation.key == Operation.insertKey) { + if ( userOperation.data is Delta && actualOperation.data is String ) { + diff += actualOperation.length!; + } + } continue; } else if (userOperation.isInsert && actualOperation.isRetain) { diff -= userOperation.length!; } else if (userOperation.isDelete && actualOperation.isRetain) { diff += userOperation.length!; } else if (userOperation.isRetain && actualOperation.isInsert) { - String? operationTxt = ''; - if (actualOperation.data is String) { - operationTxt = actualOperation.data as String?; - } - if (operationTxt!.startsWith('\n')) { - continue; - } diff += actualOperation.length!; } }