From 61551d0a48beae9e92c8e4d0d888b60d983df9ad Mon Sep 17 00:00:00 2001 From: Michael Allen Date: Wed, 2 Mar 2022 15:08:32 -0800 Subject: [PATCH] - Refactor getPlainText (better handling of blank lines and lines with multiple markups) (#700) --- lib/src/models/documents/nodes/line.dart | 89 ++++++++++-------------- lib/src/widgets/raw_editor.dart | 29 ++++---- 2 files changed, 55 insertions(+), 63 deletions(-) diff --git a/lib/src/models/documents/nodes/line.dart b/lib/src/models/documents/nodes/line.dart index a5608bd9..35f70dda 100644 --- a/lib/src/models/documents/nodes/line.dart +++ b/lib/src/models/documents/nodes/line.dart @@ -460,66 +460,53 @@ class Line extends Container { /// Returns plain text within the specified text range. String getPlainText(int offset, int len) { - final res = _getPlainText(offset, len); - if (res.length == 1) { - final data = queryChild(offset, true); - final text = res.single.item2; - return text == Embed.kObjectReplacementCharacter - ? '' - : text.substring(data.offset, data.offset + len); - } - - final total = []; - // Adjust first node - final firstNodeLen = res[1].item1; - var text = res[0].item2; - if (text != Embed.kObjectReplacementCharacter) { - total.add(text.substring(text.length - firstNodeLen)); - } - - var middleNodesLen = 0; - for (var i = 1; i < res.length - 1; i++) { - if (res[i].item2 != Embed.kObjectReplacementCharacter) { - middleNodesLen += res[i].item1; - total.add(res[i].item2); - } - } + final plainText = StringBuffer(); + _getPlainText(offset, len, plainText); + return plainText.toString(); + } - // Adjust last node - final lastNodeLen = len - middleNodesLen - res[res.length - 1].item1; - text = res[res.length - 1].item2; - if (text != Embed.kObjectReplacementCharacter) { - total.add(text.substring(0, lastNodeLen)); + int _getNodeText(Leaf node, StringBuffer buffer, int offset, int remaining) { + final text = node.toPlainText(); + if (text == Embed.kObjectReplacementCharacter) { + return remaining - node.length; } - return total.join(); - } - List> _getPlainText(int offset, int len, {int beg = 0}) { - final local = math.min(length - offset, len); - final result = >[]; + final end = math.min(offset + remaining, text.length); + buffer.write(text.substring(offset, end)); + return remaining - (end - offset); + } + int _getPlainText(int offset, int len, StringBuffer plainText) { + var _len = len; final data = queryChild(offset, true); var node = data.node as Leaf?; - if (node != null) { - var pos = node.length - data.offset; - result.add(Tuple2(beg, node.toPlainText())); - while (!node!.isLast && pos < local) { - node = node.next as Leaf; - result.add(Tuple2(pos + beg, node.toPlainText())); - pos += node.length; + + while (_len > 0) { + if (node == null) { + // blank line + plainText.write('\n'); + _len -= 1; } - } + else { + _len = _getNodeText(node, plainText, offset, _len); - final remaining = len - local; - if (remaining > 0) { - final lastElem = result[result.length - 1]; - result - ..removeLast() - ..add(Tuple2(lastElem.item1, '${lastElem.item2}\n')); - final rest = nextLine!._getPlainText(0, remaining, beg: local); - result.addAll(rest); + while (!node!.isLast && _len > 0) { + node = node.next as Leaf; + _len = _getNodeText(node, plainText, 0, _len); + } + + if (_len > 0) { + // end of this line + plainText.write('\n'); + _len -= 1; + } + } + + if (_len > 0) { + _len = nextLine!._getPlainText(0, _len, plainText); + } } - return result; + return _len; } } diff --git a/lib/src/widgets/raw_editor.dart b/lib/src/widgets/raw_editor.dart index 05cd99ef..3ef2cf73 100644 --- a/lib/src/widgets/raw_editor.dart +++ b/lib/src/widgets/raw_editor.dart @@ -904,19 +904,20 @@ class RawEditorState extends EditorState if (cause == SelectionChangedCause.toolbar) { bringIntoView(textEditingValue.selection.extent); + // on iOS, Safari does not hide the selection after copy + // however, most other iOS apps do as well as other platforms + // so we'll hide toolbar & selection after copy hideToolbar(false); - if (!Platform.isIOS) { - // Collapse the selection and hide the toolbar and handles. - userUpdateTextEditingValue( - TextEditingValue( - text: textEditingValue.text, - selection: - TextSelection.collapsed(offset: textEditingValue.selection.end), - ), - SelectionChangedCause.toolbar, - ); - } + // Collapse the selection and hide the toolbar and handles. + userUpdateTextEditingValue( + TextEditingValue( + text: textEditingValue.text, + selection: + TextSelection.collapsed(offset: textEditingValue.selection.end), + ), + SelectionChangedCause.toolbar, + ); } } @@ -983,7 +984,11 @@ class RawEditorState extends EditorState ReplaceTextIntent(textEditingValue, data.text!, selection, cause)); if (cause == SelectionChangedCause.toolbar) { - bringIntoView(textEditingValue.selection.extent); + try { + // ignore exception when paste window is at end of document + bringIntoView(textEditingValue.selection.extent); + } + catch(_){}; hideToolbar(); } }