Skip to content

Commit 2d943e4

Browse files
Remove nodes list from Document to make Document immutable at API level (Resolves #2156) (#2158)
1 parent cfe51ce commit 2d943e4

File tree

72 files changed

+1305
-1275
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1305
-1275
lines changed

super_editor/clones/quill/lib/app.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class _AlwaysTrailingParagraphReaction extends EditReaction {
126126
@override
127127
void modifyContent(EditContext editorContext, RequestDispatcher requestDispatcher, List<EditEvent> changeList) {
128128
final document = editorContext.find<MutableDocument>(Editor.documentKey);
129-
final lastNode = document.nodes.lastOrNull;
129+
final lastNode = document.lastOrNull;
130130

131131
if (lastNode != null &&
132132
lastNode is ParagraphNode &&
@@ -140,7 +140,7 @@ class _AlwaysTrailingParagraphReaction extends EditReaction {
140140
// We need to insert a trailing empty paragraph.
141141
requestDispatcher.execute([
142142
InsertNodeAtIndexRequest(
143-
nodeIndex: document.nodes.length,
143+
nodeIndex: document.nodeCount,
144144
newNode: ParagraphNode(
145145
id: Editor.createNodeId(),
146146
text: AttributedText(""),

super_editor/example/lib/demos/in_the_lab/feature_action_tags.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class _ActionTagsFeatureDemoState extends State<ActionTagsFeatureDemo> {
6363
setState(() {
6464
_actions.clear();
6565

66-
for (final node in _document.nodes) {
66+
for (final node in _document) {
6767
if (node is! TextNode) {
6868
continue;
6969
}

super_editor/example/lib/demos/in_the_lab/feature_stable_tags.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class _UserTagsFeatureDemoState extends State<UserTagsFeatureDemo> {
6464
setState(() {
6565
_users.clear();
6666

67-
for (final node in _document.nodes) {
67+
for (final node in _document) {
6868
if (node is! TextNode) {
6969
continue;
7070
}

super_editor/example/lib/demos/super_reader/demo_super_reader.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,18 @@ class _SuperReaderDemoState extends State<SuperReaderDemo> {
109109
}
110110

111111
void _selectAll() {
112-
final nodes = _document.nodes;
113-
if (nodes.isEmpty) {
112+
if (_document.isEmpty) {
114113
return;
115114
}
116115

117116
_selection.value = DocumentSelection(
118117
base: DocumentPosition(
119-
nodeId: nodes.first.id,
120-
nodePosition: nodes.first.beginningPosition,
118+
nodeId: _document.first.id,
119+
nodePosition: _document.first.beginningPosition,
121120
),
122121
extent: DocumentPosition(
123-
nodeId: nodes.last.id,
124-
nodePosition: nodes.last.endPosition,
122+
nodeId: _document.last.id,
123+
nodePosition: _document.last.endPosition,
125124
),
126125
);
127126
}

super_editor/example/lib/marketing_video/main_marketing_video.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class _MarketingVideoState extends State<MarketingVideo> {
3131
_composer = MutableDocumentComposer(
3232
initialSelection: DocumentSelection.collapsed(
3333
position: DocumentPosition(
34-
nodeId: _document.nodes.first.id,
35-
nodePosition: _document.nodes.first.endPosition,
34+
nodeId: _document.first.id,
35+
nodePosition: _document.first.endPosition,
3636
),
3737
),
3838
);
@@ -309,12 +309,12 @@ class DocumentEditingRobot {
309309
ChangeSelectionRequest(
310310
DocumentSelection(
311311
base: DocumentPosition(
312-
nodeId: _document.nodes.first.id,
313-
nodePosition: _document.nodes.first.beginningPosition,
312+
nodeId: _document.first.id,
313+
nodePosition: _document.first.beginningPosition,
314314
),
315315
extent: DocumentPosition(
316-
nodeId: _document.nodes.last.id,
317-
nodePosition: _document.nodes.last.endPosition,
316+
nodeId: _document.last.id,
317+
nodePosition: _document.last.endPosition,
318318
),
319319
),
320320
SelectionChangeType.expandSelection,

super_editor/lib/src/core/document.dart

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,22 @@ import 'package:flutter/widgets.dart';
1717
/// content.
1818
///
1919
/// To edit the content of a document, see [DocumentEditor].
20-
abstract class Document {
21-
/// Returns all of the content within the document as a list
22-
/// of [DocumentNode]s.
23-
List<DocumentNode> get nodes;
20+
abstract class Document implements Iterable<DocumentNode> {
21+
/// The number of [DocumentNode]s in this [Document].
22+
int get nodeCount;
23+
24+
/// Returns `true` if this [Document] has zero nodes, or `false` if it
25+
/// has `1+ nodes.
26+
@override
27+
bool get isEmpty;
28+
29+
/// Returns the first [DocumentNode] in this [Document], or `null` if this
30+
/// [Document] is empty.
31+
DocumentNode? get firstOrNull;
32+
33+
/// Returns the last [DocumentNode] in this [Document], or `null` if this
34+
/// [Document] is empty.
35+
DocumentNode? get lastOrNull;
2436

2537
/// Returns the [DocumentNode] with the given [nodeId], or [null]
2638
/// if no such node exists.
@@ -240,7 +252,7 @@ class DocumentPosition {
240252
///
241253
/// ```dart
242254
/// final documentPosition = DocumentPosition(
243-
/// nodeId: documentEditor.document.nodes.first.id,
255+
/// nodeId: documentEditor.document.first.id,
244256
/// nodePosition: TextNodePosition(offset: 1),
245257
/// );
246258
/// ```

super_editor/lib/src/core/document_selection.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,9 @@ extension InspectDocumentSelection on Document {
376376
/// from upstream to downstream.
377377
List<DocumentNode> getNodesInContentOrder(DocumentSelection selection) {
378378
final upstreamPosition = selectUpstreamPosition(selection.base, selection.extent);
379-
final upstreamIndex = getNodeIndexById(upstreamPosition.nodeId);
380379
final downstreamPosition = selectDownstreamPosition(selection.base, selection.extent);
381-
final downstreamIndex = getNodeIndexById(downstreamPosition.nodeId);
382380

383-
return nodes.sublist(upstreamIndex, downstreamIndex + 1);
381+
return getNodesInside(upstreamPosition, downstreamPosition);
384382
}
385383

386384
/// Given [docPosition1] and [docPosition2], returns the `DocumentPosition` that

super_editor/lib/src/core/editor.dart

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ class MergeRapidTextInputPolicy implements HistoryGroupingPolicy {
631631
return TransactionMerge.noOpinion;
632632
}
633633

634-
if (newTransaction.firstChangeTime.difference(previousTransaction.lastChangeTime!) > _maxMergeTime) {
634+
if (newTransaction.firstChangeTime.difference(previousTransaction.lastChangeTime) > _maxMergeTime) {
635635
// The text insertions were far enough apart in time that we don't want to merge them.
636636
return TransactionMerge.noOpinion;
637637
}
@@ -989,7 +989,7 @@ class FunctionalEditListener implements EditListener {
989989
}
990990

991991
/// An in-memory, mutable [Document].
992-
class MutableDocument implements Document, Editable {
992+
class MutableDocument with Iterable<DocumentNode> implements Document, Editable {
993993
/// Creates an in-memory, mutable version of a [Document].
994994
///
995995
/// Initializes the content of this [MutableDocument] with the given [nodes],
@@ -1026,7 +1026,10 @@ class MutableDocument implements Document, Editable {
10261026
final List<DocumentNode> _nodes;
10271027

10281028
@override
1029-
List<DocumentNode> get nodes => UnmodifiableListView(_nodes);
1029+
int get nodeCount => _nodes.length;
1030+
1031+
@override
1032+
bool get isEmpty => _nodes.isEmpty;
10301033

10311034
/// Maps a node id to its index in the node list.
10321035
final Map<String, int> _nodeIndicesById = {};
@@ -1036,6 +1039,15 @@ class MutableDocument implements Document, Editable {
10361039

10371040
final _listeners = <DocumentChangeListener>[];
10381041

1042+
@override
1043+
Iterator<DocumentNode> get iterator => _nodes.iterator;
1044+
1045+
@override
1046+
DocumentNode? get firstOrNull => _nodes.lastOrNull;
1047+
1048+
@override
1049+
DocumentNode? get lastOrNull => _nodes.lastOrNull;
1050+
10391051
@override
10401052
DocumentNode? getNodeById(String nodeId) {
10411053
return _nodesById[nodeId];
@@ -1206,13 +1218,12 @@ class MutableDocument implements Document, Editable {
12061218
/// ignores the runtime type of the [Document], itself.
12071219
@override
12081220
bool hasEquivalentContent(Document other) {
1209-
final otherNodes = other.nodes;
1210-
if (_nodes.length != otherNodes.length) {
1221+
if (_nodes.length != other.nodeCount) {
12111222
return false;
12121223
}
12131224

12141225
for (int i = 0; i < _nodes.length; ++i) {
1215-
if (!_nodes[i].hasEquivalentContent(otherNodes[i])) {
1226+
if (!_nodes[i].hasEquivalentContent(other.getNodeAt(i)!)) {
12161227
return false;
12171228
}
12181229
}
@@ -1277,7 +1288,7 @@ class MutableDocument implements Document, Editable {
12771288
identical(this, other) ||
12781289
other is MutableDocument &&
12791290
runtimeType == other.runtimeType &&
1280-
const DeepCollectionEquality().equals(_nodes, other.nodes);
1291+
const DeepCollectionEquality().equals(_nodes, other._nodes);
12811292

12821293
@override
12831294
int get hashCode => _nodes.hashCode;

super_editor/lib/src/core/styles.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class _LastBlockMatcher implements _BlockMatcher {
216216

217217
@override
218218
bool matches(Document document, DocumentNode node) {
219-
return document.getNodeIndexById(node.id) == document.nodes.length - 1;
219+
return document.getNodeIndexById(node.id) == document.nodeCount - 1;
220220
}
221221
}
222222

super_editor/lib/src/default_editor/common_editor_operations.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,21 +209,20 @@ class CommonEditorOperations {
209209
///
210210
/// Always returns [true].
211211
bool selectAll() {
212-
final nodes = document.nodes;
213-
if (nodes.isEmpty) {
212+
if (document.isEmpty) {
214213
return false;
215214
}
216215

217216
editor.execute([
218217
ChangeSelectionRequest(
219218
DocumentSelection(
220219
base: DocumentPosition(
221-
nodeId: nodes.first.id,
222-
nodePosition: nodes.first.beginningPosition,
220+
nodeId: document.first.id,
221+
nodePosition: document.first.beginningPosition,
223222
),
224223
extent: DocumentPosition(
225-
nodeId: nodes.last.id,
226-
nodePosition: nodes.last.endPosition,
224+
nodeId: document.last.id,
225+
nodePosition: document.last.endPosition,
227226
),
228227
),
229228
SelectionChangeType.expandSelection,
@@ -665,11 +664,11 @@ class CommonEditorOperations {
665664
return false;
666665
}
667666

668-
if (document.nodes.isEmpty) {
667+
if (document.isEmpty) {
669668
return false;
670669
}
671670

672-
final firstNode = document.nodes.first;
671+
final firstNode = document.first;
673672

674673
if (expand) {
675674
final currentExtentNode = document.getNodeById(composer.selection!.extent.nodeId);
@@ -729,11 +728,11 @@ class CommonEditorOperations {
729728
return false;
730729
}
731730

732-
if (document.nodes.isEmpty) {
731+
if (document.isEmpty) {
733732
return false;
734733
}
735734

736-
final lastNode = document.nodes.last;
735+
final lastNode = document.last;
737736

738737
if (expand) {
739738
final currentExtentNode = document.getNodeById(composer.selection!.extent.nodeId);

0 commit comments

Comments
 (0)