diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart index 6a4e4f3c80..05f0d61b8d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/document/text_delta.dart @@ -256,7 +256,12 @@ TextOperation? _textOperationFromJson(Map json) { return result; } -// basically copy from: https://github.com/quilljs/delta +/// Deltas are a simple, yet expressive format that can be used to describe contents and changes. +/// The format is JSON based, and is human readable, yet easily parsible by machines. +/// Deltas can describe any rich text document, includes all text and formatting information, without the ambiguity and complexity of HTML. +/// + +/// Basically borrowed from: https://github.com/quilljs/delta class Delta extends Iterable { final List _operations; String? _rawString; @@ -316,6 +321,9 @@ class Delta extends Iterable { _operations.add(textOp); } + /// The slice() method does not change the original string. + /// The start and end parameters specifies the part of the string to extract. + /// The end position is optional. Delta slice(int start, [int? end]) { final result = Delta(); final iterator = _OpIterator(_operations); @@ -336,19 +344,29 @@ class Delta extends Iterable { return result; } + /// Insert operations have an `insert` key defined. + /// A String value represents inserting text. void insert(String content, [Attributes? attributes]) => add(TextInsert(content, attributes)); + /// Retain operations have a Number `retain` key defined representing the number of characters to keep (other libraries might use the name keep or skip). + /// An optional `attributes` key can be defined with an Object to describe formatting changes to the character range. + /// A value of `null` in the `attributes` Object represents removal of that key. + /// + /// *Note: It is not necessary to retain the last characters of a document as this is implied.* void retain(int length, [Attributes? attributes]) => add(TextRetain(length, attributes)); + /// Delete operations have a Number `delete` key defined representing the number of characters to delete. void delete(int length) => add(TextDelete(length)); + /// The length of the string fo the [Delta]. int get length { return _operations.fold( 0, (previousValue, element) => previousValue + element.length); } + /// Returns a Delta that is equivalent to applying the operations of own Delta, followed by another Delta. Delta compose(Delta other) { final thisIter = _OpIterator(_operations); final otherIter = _OpIterator(other._operations); @@ -412,6 +430,7 @@ class Delta extends Iterable { return delta..chop(); } + /// This method joins two Delta together. Delta operator +(Delta other) { var ops = [..._operations]; if (other._operations.isNotEmpty) { @@ -445,6 +464,7 @@ class Delta extends Iterable { return hashList(_operations); } + /// Returned an inverted delta that has the opposite effect of against a base document delta. Delta invert(Delta base) { final inverted = Delta(); _operations.fold(0, (int previousValue, op) { @@ -475,6 +495,13 @@ class Delta extends Iterable { return _operations.map((e) => e.toJson()).toList(); } + /// This method will return the position of the previous rune. + /// + /// Since the encoding of the [String] in Dart is UTF-16. + /// If you want to find the previous character of a position, + /// you can' just use the `position - 1` simply. + /// + /// This method can help you to compute the position of the previous character. int prevRunePosition(int pos) { if (pos == 0) { return pos - 1; @@ -485,6 +512,13 @@ class Delta extends Iterable { return _runeIndexes![pos - 1]; } + /// This method will return the position of the next rune. + /// + /// Since the encoding of the [String] in Dart is UTF-16. + /// If you want to find the previous character of a position, + /// you can' just use the `position + 1` simply. + /// + /// This method can help you to compute the position of the next character. int nextRunePosition(int pos) { final stringContent = toRawString(); if (pos >= stringContent.length - 1) { diff --git a/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart b/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart index 5a8dc68b3b..f8cc80b161 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/src/operation/transaction_builder.dart @@ -14,7 +14,6 @@ import 'package:flowy_editor/src/operation/transaction.dart'; /// A [TransactionBuilder] is used to build the transaction from the state. /// It will save make a snapshot of the cursor selection state automatically. /// The cursor can be resorted if the transaction is undo. - class TransactionBuilder { final List operations = []; EditorState state; @@ -29,15 +28,18 @@ class TransactionBuilder { state.apply(transaction); } + /// Insert the nodes at the position of path. insertNode(Path path, Node node) { insertNodes(path, [node]); } + /// Insert a sequence of nodes at the position of path. insertNodes(Path path, List nodes) { beforeSelection = state.cursorSelection; add(InsertOperation(path, nodes)); } + /// Update the attributes of nodes. updateNode(Node node, Attributes attributes) { beforeSelection = state.cursorSelection; @@ -49,6 +51,7 @@ class TransactionBuilder { )); } + /// Delete a node in the document. deleteNode(Node node) { deleteNodesAtPath(node.path); } @@ -57,6 +60,9 @@ class TransactionBuilder { nodes.forEach(deleteNode); } + /// Delete a sequence of nodes at the path of the document. + /// The length specific the length of the following nodes to delete( + /// including the start one). deleteNodesAtPath(Path path, [int length = 1]) { if (path.isEmpty) { return; @@ -106,6 +112,9 @@ class TransactionBuilder { ); } + /// Insert content at a specified index. + /// Optionally, you may specify formatting attributes that are applied to the inserted string. + /// By default, the formatting attributes before the insert position will be used. insertText(TextNode node, int index, String content, [Attributes? attributes]) { var newAttributes = attributes; @@ -126,6 +135,7 @@ class TransactionBuilder { Position(path: node.path, offset: index + content.length)); } + /// Assign formatting attributes to a range of text. formatText(TextNode node, int index, int length, Attributes attributes) { textEdit( node, @@ -135,6 +145,7 @@ class TransactionBuilder { afterSelection = beforeSelection; } + /// Delete length characters starting from index. deleteText(TextNode node, int index, int length) { textEdit( node, @@ -169,6 +180,11 @@ class TransactionBuilder { ); } + /// Add an operation to the transaction. + /// This method will merge operations if they are both TextEdits. + /// + /// Also, this method will transform the path of the operations + /// to avoid conflicts. add(Operation op) { final Operation? last = operations.isEmpty ? null : operations.last; if (last != null) { @@ -190,6 +206,7 @@ class TransactionBuilder { operations.add(op); } + /// Generate a immutable [Transaction] to apply or transmit. Transaction finish() { return Transaction( operations: UnmodifiableListView(operations),