refactor: move node to core/document

This commit is contained in:
Lucas.Xu 2022-10-09 14:30:55 +08:00
parent 8d6e1cdaa1
commit 11eca2b3d9
58 changed files with 283 additions and 284 deletions

View File

@ -60,7 +60,7 @@ SelectionMenuItem codeBlockMenuItem = SelectionMenuItem(
if (selection == null || textNodes.isEmpty) { if (selection == null || textNodes.isEmpty) {
return; return;
} }
if (textNodes.first.toRawString().isEmpty) { if (textNodes.first.toPlainText().isEmpty) {
TransactionBuilder(editorState) TransactionBuilder(editorState)
..updateNode(textNodes.first, { ..updateNode(textNodes.first, {
'subtype': 'code_block', 'subtype': 'code_block',
@ -74,7 +74,6 @@ SelectionMenuItem codeBlockMenuItem = SelectionMenuItem(
..insertNode( ..insertNode(
selection.end.path.next, selection.end.path.next,
TextNode( TextNode(
type: 'text',
children: LinkedList(), children: LinkedList(),
attributes: { attributes: {
'subtype': 'code_block', 'subtype': 'code_block',
@ -149,7 +148,7 @@ class __CodeBlockNodeWidgeState extends State<_CodeBlockNodeWidge>
Widget _buildCodeBlock(BuildContext context) { Widget _buildCodeBlock(BuildContext context) {
final result = highlight.highlight.parse( final result = highlight.highlight.parse(
widget.textNode.toRawString(), widget.textNode.toPlainText(),
language: _language, language: _language,
autoDetection: _language == null, autoDetection: _language == null,
); );

View File

@ -17,7 +17,7 @@ ShortcutEventHandler _insertHorzaontalRule = (editorState, event) {
return KeyEventResult.ignored; return KeyEventResult.ignored;
} }
final textNode = textNodes.first; final textNode = textNodes.first;
if (textNode.toRawString() == '--') { if (textNode.toPlainText() == '--') {
TransactionBuilder(editorState) TransactionBuilder(editorState)
..deleteText(textNode, 0, 2) ..deleteText(textNode, 0, 2)
..insertNode( ..insertNode(
@ -53,7 +53,7 @@ SelectionMenuItem horizontalRuleMenuItem = SelectionMenuItem(
return; return;
} }
final textNode = textNodes.first; final textNode = textNodes.first;
if (textNode.toRawString().isEmpty) { if (textNode.toPlainText().isEmpty) {
TransactionBuilder(editorState) TransactionBuilder(editorState)
..insertNode( ..insertNode(
textNode.path, textNode.path,
@ -71,7 +71,6 @@ SelectionMenuItem horizontalRuleMenuItem = SelectionMenuItem(
..insertNode( ..insertNode(
selection.end.path.next, selection.end.path.next,
TextNode( TextNode(
type: 'text',
children: LinkedList(), children: LinkedList(),
attributes: { attributes: {
'subtype': 'horizontal_rule', 'subtype': 'horizontal_rule',

View File

@ -21,7 +21,7 @@ SelectionMenuItem teXBlockMenuItem = SelectionMenuItem(
return; return;
} }
final Path texNodePath; final Path texNodePath;
if (textNodes.first.toRawString().isEmpty) { if (textNodes.first.toPlainText().isEmpty) {
texNodePath = selection.end.path; texNodePath = selection.end.path;
TransactionBuilder(editorState) TransactionBuilder(editorState)
..insertNode( ..insertNode(

View File

@ -18,7 +18,7 @@ ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
} }
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString(); final text = textNode.toPlainText();
// Determine if an 'underscore' already exists in the text node and only once. // Determine if an 'underscore' already exists in the text node and only once.
final firstUnderscore = text.indexOf('_'); final firstUnderscore = text.indexOf('_');
final lastUnderscore = text.lastIndexOf('_'); final lastUnderscore = text.lastIndexOf('_');

View File

@ -3,7 +3,7 @@ library appflowy_editor;
export 'src/infra/log.dart'; export 'src/infra/log.dart';
export 'src/render/style/editor_style.dart'; export 'src/render/style/editor_style.dart';
export 'src/document/node.dart'; export 'src/core/document/node.dart';
export 'src/document/path.dart'; export 'src/document/path.dart';
export 'src/document/position.dart'; export 'src/document/position.dart';
export 'src/document/selection.dart'; export 'src/document/selection.dart';

View File

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:appflowy_editor/src/commands/text_command_infra.dart'; import 'package:appflowy_editor/src/commands/text_command_infra.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart'; import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -2,7 +2,7 @@ import 'package:appflowy_editor/src/commands/format_text.dart';
import 'package:appflowy_editor/src/commands/text_command_infra.dart'; import 'package:appflowy_editor/src/commands/text_command_infra.dart';
import 'package:appflowy_editor/src/document/attributes.dart'; import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart'; import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:appflowy_editor/src/commands/text_command_infra.dart'; import 'package:appflowy_editor/src/commands/text_command_infra.dart';
import 'package:appflowy_editor/src/document/attributes.dart'; import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';

View File

@ -1,47 +1,21 @@
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/text_delta.dart'; import 'package:appflowy_editor/src/document/text_delta.dart';
import 'package:flutter/material.dart';
import './attributes.dart';
class Node extends ChangeNotifier with LinkedListEntry<Node> { class Node extends ChangeNotifier with LinkedListEntry<Node> {
Node? parent;
final String type;
final LinkedList<Node> children;
Attributes _attributes;
GlobalKey? key;
// TODO: abstract a selectable node??
final layerLink = LayerLink();
String? get subtype {
// TODO: make 'subtype' as a const value.
if (_attributes.containsKey('subtype')) {
assert(_attributes['subtype'] is String?,
'subtype must be a [String] or [null]');
return _attributes['subtype'] as String?;
}
return null;
}
String get id {
if (subtype != null) {
return '$type/$subtype';
}
return type;
}
Path get path => _path();
Attributes get attributes => _attributes;
Node({ Node({
required this.type, required this.type,
required this.children, Attributes? attributes,
required Attributes attributes,
this.parent, this.parent,
}) : _attributes = attributes { LinkedList<Node>? children,
for (final child in children) { }) : children = children ?? LinkedList<Node>(),
_attributes = attributes ?? {} {
for (final child in this.children) {
child.parent = this; child.parent = this;
} }
} }
@ -49,14 +23,13 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
factory Node.fromJson(Map<String, Object> json) { factory Node.fromJson(Map<String, Object> json) {
assert(json['type'] is String); assert(json['type'] is String);
// TODO: check the type that not exist on plugins.
final jType = json['type'] as String; final jType = json['type'] as String;
final jChildren = json['children'] as List?; final jChildren = json['children'] as List?;
final jAttributes = json['attributes'] != null final jAttributes = json['attributes'] != null
? Attributes.from(json['attributes'] as Map) ? Attributes.from(json['attributes'] as Map)
: Attributes.from({}); : Attributes.from({});
final LinkedList<Node> children = LinkedList(); final children = LinkedList<Node>();
if (jChildren != null) { if (jChildren != null) {
children.addAll( children.addAll(
jChildren.map( jChildren.map(
@ -69,14 +42,14 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
Node node; Node node;
if (jType == "text") { if (jType == 'text') {
final jDelta = json['delta'] as List<dynamic>?; final jDelta = json['delta'] as List<dynamic>?;
final delta = jDelta == null ? Delta() : Delta.fromJson(jDelta); final delta = jDelta == null ? Delta() : Delta.fromJson(jDelta);
node = TextNode( node = TextNode(
type: jType, children: children,
children: children, attributes: jAttributes,
attributes: jAttributes, delta: delta,
delta: delta); );
} else { } else {
node = Node( node = Node(
type: jType, type: jType,
@ -92,20 +65,48 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
return node; return node;
} }
final String type;
final LinkedList<Node> children;
Node? parent;
Attributes _attributes;
// Renderable
GlobalKey? key;
final layerLink = LayerLink();
Attributes get attributes => {..._attributes};
String get id {
if (subtype != null) {
return '$type/$subtype';
}
return type;
}
String? get subtype {
if (attributes[BuiltInAttributeKey.subtype] is String) {
return attributes[BuiltInAttributeKey.subtype] as String;
}
return null;
}
Path get path => _computePath();
void updateAttributes(Attributes attributes) { void updateAttributes(Attributes attributes) {
final oldAttributes = {..._attributes}; final oldAttributes = this.attributes;
_attributes = composeAttributes(_attributes, attributes) ?? {};
_attributes = composeAttributes(this.attributes, attributes) ?? {};
// Notifies the new attributes // Notifies the new attributes
// if attributes contains 'subtype', should notify parent to rebuild node // if attributes contains 'subtype', should notify parent to rebuild node
// else, just notify current node. // else, just notify current node.
bool shouldNotifyParent = bool shouldNotifyParent =
_attributes['subtype'] != oldAttributes['subtype']; this.attributes['subtype'] != oldAttributes['subtype'];
shouldNotifyParent ? parent?.notifyListeners() : notifyListeners(); shouldNotifyParent ? parent?.notifyListeners() : notifyListeners();
} }
Node? childAtIndex(int index) { Node? childAtIndex(int index) {
if (children.length <= index) { if (children.length <= index || index < 0) {
return null; return null;
} }
@ -121,7 +122,8 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
} }
void insert(Node entry, {int? index}) { void insert(Node entry, {int? index}) {
index ??= children.length; final length = children.length;
index ??= length;
if (children.isEmpty) { if (children.isEmpty) {
entry.parent = this; entry.parent = this;
@ -130,8 +132,9 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
return; return;
} }
final length = children.length; // If index is out of range, insert at the end.
// If index is negative, insert at the beginning.
// If index is positive, insert at the index.
if (index >= length) { if (index >= length) {
children.last.insertAfter(entry); children.last.insertAfter(entry);
} else if (index <= 0) { } else if (index <= 0) {
@ -173,28 +176,14 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
}; };
if (children.isNotEmpty) { if (children.isNotEmpty) {
map['children'] = map['children'] =
(children.map((node) => node.toJson())).toList(growable: false); children.map((node) => node.toJson()).toList(growable: false);
} }
if (_attributes.isNotEmpty) { if (attributes.isNotEmpty) {
map['attributes'] = _attributes; map['attributes'] = attributes;
} }
return map; return map;
} }
Path _path([Path previous = const []]) {
if (parent == null) {
return previous;
}
var index = 0;
for (var child in parent!.children) {
if (child == this) {
break;
}
index += 1;
}
return parent!._path([index, ...previous]);
}
Node copyWith({ Node copyWith({
String? type, String? type,
LinkedList<Node>? children, LinkedList<Node>? children,
@ -202,8 +191,8 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
}) { }) {
final node = Node( final node = Node(
type: type ?? this.type, type: type ?? this.type,
attributes: attributes ?? {..._attributes}, attributes: attributes ?? {...this.attributes},
children: children ?? LinkedList(), children: children,
); );
if (children == null && this.children.isNotEmpty) { if (children == null && this.children.isNotEmpty) {
for (final child in this.children) { for (final child in this.children) {
@ -214,19 +203,31 @@ class Node extends ChangeNotifier with LinkedListEntry<Node> {
} }
return node; return node;
} }
Path _computePath([Path previous = const []]) {
if (parent == null) {
return previous;
}
var index = 0;
for (final child in parent!.children) {
if (child == this) {
break;
}
index += 1;
}
return parent!._computePath([index, ...previous]);
}
} }
class TextNode extends Node { class TextNode extends Node {
Delta _delta;
TextNode({ TextNode({
required super.type,
required Delta delta, required Delta delta,
LinkedList<Node>? children, LinkedList<Node>? children,
Attributes? attributes, Attributes? attributes,
}) : _delta = delta, }) : _delta = delta,
super( super(
children: children ?? LinkedList(), type: 'text',
children: children,
attributes: attributes ?? {}, attributes: attributes ?? {},
); );
@ -234,14 +235,11 @@ class TextNode extends Node {
: _delta = Delta([TextInsert('')]), : _delta = Delta([TextInsert('')]),
super( super(
type: 'text', type: 'text',
children: LinkedList(),
attributes: attributes ?? {}, attributes: attributes ?? {},
); );
Delta get delta { Delta _delta;
return _delta; Delta get delta => _delta;
}
set delta(Delta v) { set delta(Delta v) {
_delta = v; _delta = v;
notifyListeners(); notifyListeners();
@ -250,21 +248,20 @@ class TextNode extends Node {
@override @override
Map<String, Object> toJson() { Map<String, Object> toJson() {
final map = super.toJson(); final map = super.toJson();
map['delta'] = _delta.toJson(); map['delta'] = delta.toJson();
return map; return map;
} }
@override @override
TextNode copyWith({ TextNode copyWith({
String? type, String? type = 'text',
LinkedList<Node>? children, LinkedList<Node>? children,
Attributes? attributes, Attributes? attributes,
Delta? delta, Delta? delta,
}) { }) {
final textNode = TextNode( final textNode = TextNode(
type: type ?? this.type,
children: children, children: children,
attributes: attributes ?? _attributes, attributes: attributes ?? this.attributes,
delta: delta ?? this.delta, delta: delta ?? this.delta,
); );
if (children == null && this.children.isNotEmpty) { if (children == null && this.children.isNotEmpty) {
@ -277,5 +274,5 @@ class TextNode extends Node {
return textNode; return textNode;
} }
String toRawString() => _delta.toRawString(); String toPlainText() => _delta.toPlainText();
} }

View File

@ -1,42 +1,45 @@
/// Attributes is used to describe the Node's information.
///
/// Please note: The keywords in [BuiltInAttributeKey] are reserved.
typedef Attributes = Map<String, dynamic>; typedef Attributes = Map<String, dynamic>;
int hashAttributes(Attributes attributes) { Attributes? composeAttributes(
return Object.hashAllUnordered( Attributes? base,
attributes.entries.map((e) => Object.hash(e.key, e.value))); Attributes? other, {
} keepNull = false,
}) {
Attributes invertAttributes(Attributes? attr, Attributes? base) {
attr ??= {};
base ??= {}; base ??= {};
final Attributes baseInverted = base.keys.fold({}, (memo, key) { other ??= {};
if (base![key] != attr![key] && attr.containsKey(key)) { Attributes attributes = {
memo[key] = base[key]; ...base,
} ...other,
return memo; };
});
return attr.keys.fold(baseInverted, (memo, key) {
if (attr![key] != base![key] && !base.containsKey(key)) {
memo[key] = null;
}
return memo;
});
}
Attributes? composeAttributes(Attributes? a, Attributes? b,
[bool keepNull = false]) {
a ??= {};
b ??= {};
Attributes attributes = {...b};
if (!keepNull) { if (!keepNull) {
attributes = Map.from(attributes)..removeWhere((_, value) => value == null); attributes = Attributes.from(attributes)
} ..removeWhere((_, value) => value == null);
for (final entry in a.entries) {
if (!b.containsKey(entry.key)) {
attributes[entry.key] = entry.value;
}
} }
return attributes.isNotEmpty ? attributes : null; return attributes.isNotEmpty ? attributes : null;
} }
Attributes invertAttributes(Attributes? base, Attributes? other) {
base ??= {};
other ??= {};
final Attributes attributes = base.keys.fold({}, (previousValue, key) {
if (other!.containsKey(key) && other[key] != base![key]) {
previousValue[key] = base[key];
}
return previousValue;
});
return other.keys.fold(attributes, (previousValue, key) {
if (!base!.containsKey(key) && other![key] != base[key]) {
previousValue[key] = null;
}
return previousValue;
});
}
int hashAttributes(Attributes base) => Object.hashAllUnordered(
base.entries.map((e) => Object.hash(e.key, e.value)),
);

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import './state_tree.dart'; import './state_tree.dart';

View File

@ -1,6 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/text_delta.dart'; import 'package:appflowy_editor/src/document/text_delta.dart';
import './attributes.dart'; import './attributes.dart';

View File

@ -47,7 +47,9 @@ class TextInsert extends TextOperation {
final contentHash = content.hashCode; final contentHash = content.hashCode;
final attrs = _attributes; final attrs = _attributes;
return Object.hash( return Object.hash(
contentHash, attrs == null ? null : hashAttributes(attrs)); contentHash,
attrs != null ? hashAttributes(attrs) : null,
);
} }
@override @override
@ -101,7 +103,10 @@ class TextRetain extends TextOperation {
@override @override
int get hashCode { int get hashCode {
final attrs = _attributes; final attrs = _attributes;
return Object.hash(_length, attrs == null ? null : hashAttributes(attrs)); return Object.hash(
_length,
attrs != null ? hashAttributes(attrs) : null,
);
} }
@override @override
@ -401,7 +406,11 @@ class Delta extends Iterable<TextOperation> {
final thisOp = thisIter._next(length); final thisOp = thisIter._next(length);
final otherOp = otherIter._next(length); final otherOp = otherIter._next(length);
final attributes = composeAttributes( final attributes = composeAttributes(
thisOp.attributes, otherOp.attributes, thisOp is TextRetain); thisOp.attributes,
otherOp.attributes,
keepNull: thisOp is TextRetain,
);
if (otherOp is TextRetain && otherOp.length > 0) { if (otherOp is TextRetain && otherOp.length > 0) {
TextOperation? newOp; TextOperation? newOp;
if (thisOp is TextRetain) { if (thisOp is TextRetain) {
@ -480,8 +489,10 @@ class Delta extends Iterable<TextOperation> {
if (op is TextDelete) { if (op is TextDelete) {
inverted.add(baseOp); inverted.add(baseOp);
} else if (op is TextRetain && op.attributes != null) { } else if (op is TextRetain && op.attributes != null) {
inverted.retain(baseOp.length, inverted.retain(
invertAttributes(op.attributes, baseOp.attributes)); baseOp.length,
invertAttributes(baseOp.attributes, op.attributes),
);
} }
} }
return previousValue + length; return previousValue + length;
@ -520,7 +531,7 @@ class Delta extends Iterable<TextOperation> {
/// ///
/// This method can help you to compute the position of the next character. /// This method can help you to compute the position of the next character.
int nextRunePosition(int pos) { int nextRunePosition(int pos) {
final stringContent = toRawString(); final stringContent = toPlainText();
if (pos >= stringContent.length - 1) { if (pos >= stringContent.length - 1) {
return stringContent.length; return stringContent.length;
} }
@ -535,7 +546,7 @@ class Delta extends Iterable<TextOperation> {
return stringContent.length; return stringContent.length;
} }
String toRawString() { String toPlainText() {
_rawString ??= _rawString ??=
_operations.whereType<TextInsert>().map((op) => op.content).join(); _operations.whereType<TextInsert>().map((op) => op.content).join();
return _rawString!; return _rawString!;

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/extensions/object_extensions.dart'; import 'package:appflowy_editor/src/extensions/object_extensions.dart';
import 'package:appflowy_editor/src/extensions/path_extensions.dart'; import 'package:appflowy_editor/src/extensions/path_extensions.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
@ -171,7 +171,7 @@ extension TextNodesExtension on List<TextNode> {
if (i == 0 && pathEquals(node.path, selection.start.path)) { if (i == 0 && pathEquals(node.path, selection.start.path)) {
if (selection.isBackward) { if (selection.isBackward) {
newSelection = selection.copyWith( newSelection = selection.copyWith(
end: Position(path: node.path, offset: node.toRawString().length), end: Position(path: node.path, offset: node.toPlainText().length),
); );
} else { } else {
newSelection = selection.copyWith( newSelection = selection.copyWith(
@ -187,13 +187,13 @@ extension TextNodesExtension on List<TextNode> {
} else { } else {
newSelection = selection.copyWith( newSelection = selection.copyWith(
start: start:
Position(path: node.path, offset: node.toRawString().length), Position(path: node.path, offset: node.toPlainText().length),
); );
} }
} else { } else {
newSelection = Selection( newSelection = Selection(
start: Position(path: node.path, offset: 0), start: Position(path: node.path, offset: 0),
end: Position(path: node.path, offset: node.toRawString().length), end: Position(path: node.path, offset: node.toPlainText().length),
); );
} }
if (!node.allSatisfyInSelection(newSelection, styleKey, test)) { if (!node.allSatisfyInSelection(newSelection, styleKey, test)) {

View File

@ -2,7 +2,7 @@ import 'dart:collection';
import 'dart:ui'; import 'dart:ui';
import 'package:appflowy_editor/src/document/attributes.dart'; import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/text_delta.dart'; import 'package:appflowy_editor/src/document/text_delta.dart';
import 'package:appflowy_editor/src/extensions/color_extension.dart'; import 'package:appflowy_editor/src/extensions/color_extension.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -89,7 +89,7 @@ class HTMLToNodesConverter {
} }
} }
if (delta.isNotEmpty) { if (delta.isNotEmpty) {
result.add(TextNode(type: "text", delta: delta)); result.add(TextNode(delta: delta));
} }
return result; return result;
} }
@ -134,7 +134,7 @@ class HTMLToNodesConverter {
final delta = Delta(); final delta = Delta();
delta.insert(element.text); delta.insert(element.text);
if (delta.isNotEmpty) { if (delta.isNotEmpty) {
return [TextNode(type: "text", delta: delta)]; return [TextNode(delta: delta)];
} }
} }
return []; return [];
@ -271,8 +271,7 @@ class HTMLToNodesConverter {
} }
} }
final textNode = final textNode = TextNode(delta: delta, attributes: attributes);
TextNode(type: "text", delta: delta, attributes: attributes);
if (isCheckbox) { if (isCheckbox) {
textNode.attributes["subtype"] = BuiltInAttributeKey.checkbox; textNode.attributes["subtype"] = BuiltInAttributeKey.checkbox;
textNode.attributes["checkbox"] = checked; textNode.attributes["checkbox"] = checked;
@ -315,7 +314,6 @@ class HTMLToNodesConverter {
final delta = Delta(); final delta = Delta();
delta.insert(element.text); delta.insert(element.text);
return TextNode( return TextNode(
type: "text",
attributes: {"subtype": "heading", "heading": headingStyle}, attributes: {"subtype": "heading", "heading": headingStyle},
delta: delta); delta: delta);
} }

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
class Infra { class Infra {
// find the forward nearest text node // find the forward nearest text node

View File

@ -2,7 +2,7 @@ import 'dart:collection';
import 'dart:math'; import 'dart:math';
import 'package:appflowy_editor/src/document/attributes.dart'; import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
@ -42,8 +42,7 @@ class TransactionBuilder {
/// Updates the attributes of nodes. /// Updates the attributes of nodes.
updateNode(Node node, Attributes attributes) { updateNode(Node node, Attributes attributes) {
beforeSelection = state.cursorSelection; beforeSelection = state.cursorSelection;
final inverted = invertAttributes(node.attributes, attributes);
final inverted = invertAttributes(attributes, node.attributes);
add(UpdateOperation( add(UpdateOperation(
node.path, node.path,
{...attributes}, {...attributes},

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/service/render_plugin_service.dart'; import 'package:appflowy_editor/src/service/render_plugin_service.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart'; import 'package:appflowy_editor/src/operation/transaction_builder.dart';
import 'package:appflowy_editor/src/service/render_plugin_service.dart'; import 'package:appflowy_editor/src/service/render_plugin_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy_editor/src/extensions/object_extensions.dart'; import 'package:appflowy_editor/src/extensions/object_extensions.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart'; import 'package:appflowy_editor/src/infra/flowy_svg.dart';

View File

@ -1,6 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart'; import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart'; import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart'; import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart'; import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';

View File

@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/path.dart'; import 'package:appflowy_editor/src/document/path.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
@ -163,7 +163,7 @@ class _FlowyRichTextState extends State<FlowyRichText> with SelectableMixin {
Widget _buildRichText(BuildContext context) { Widget _buildRichText(BuildContext context) {
return MouseRegion( return MouseRegion(
cursor: SystemMouseCursors.text, cursor: SystemMouseCursors.text,
child: widget.textNode.toRawString().isEmpty child: widget.textNode.toPlainText().isEmpty
? Stack( ? Stack(
children: [ children: [
_buildPlaceholderText(context), _buildPlaceholderText(context),

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart'; import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart'; import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart'; import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart'; import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart'; import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart'; import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart'; import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart'; import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart';

View File

@ -44,7 +44,7 @@ class SelectionMenuItem {
if (selection != null && nodes.length == 1) { if (selection != null && nodes.length == 1) {
final node = nodes.first as TextNode; final node = nodes.first as TextNode;
final end = selection.start.offset; final end = selection.start.offset;
final start = node.toRawString().substring(0, end).lastIndexOf('/'); final start = node.toPlainText().substring(0, end).lastIndexOf('/');
TransactionBuilder(editorState) TransactionBuilder(editorState)
..deleteText( ..deleteText(
node, node,

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/attributes_extension.dart'; import 'package:appflowy_editor/src/extensions/attributes_extension.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy_editor/src/document/attributes.dart'; import 'package:appflowy_editor/src/document/attributes.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
@ -125,7 +125,7 @@ bool formatTextNodes(EditorState editorState, Attributes attributes) {
..afterSelection = Selection.collapsed( ..afterSelection = Selection.collapsed(
Position( Position(
path: textNode.path, path: textNode.path,
offset: textNode.toRawString().length, offset: textNode.toPlainText().length,
), ),
); );
} }
@ -232,10 +232,10 @@ bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
for (var i = 0; i < textNodes.length; i++) { for (var i = 0; i < textNodes.length; i++) {
final textNode = textNodes[i]; final textNode = textNodes[i];
var index = 0; var index = 0;
var length = textNode.toRawString().length; var length = textNode.toPlainText().length;
if (i == 0 && textNode == nodes.first) { if (i == 0 && textNode == nodes.first) {
index = selection.start.offset; index = selection.start.offset;
length = textNode.toRawString().length - selection.start.offset; length = textNode.toPlainText().length - selection.start.offset;
} else if (i == textNodes.length - 1 && textNode == nodes.last) { } else if (i == textNodes.length - 1 && textNode == nodes.last) {
length = selection.end.offset; length = selection.end.offset;
} }

View File

@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/extensions/node_extensions.dart'; import 'package:appflowy_editor/src/extensions/node_extensions.dart';
@ -282,7 +282,7 @@ class _AppFlowyInputState extends State<AppFlowyInput>
// FIXME: upward and selection update. // FIXME: upward and selection update.
if (textNodes.isNotEmpty && selection != null) { if (textNodes.isNotEmpty && selection != null) {
final text = textNodes.fold<String>( final text = textNodes.fold<String>(
'', (sum, textNode) => '$sum${textNode.toRawString()}\n'); '', (sum, textNode) => '$sum${textNode.toPlainText()}\n');
attach( attach(
TextEditingValue( TextEditingValue(
text: text, text: text,

View File

@ -163,7 +163,7 @@ KeyEventResult _backDeleteToPreviousTextNode(
transactionBuilder.afterSelection = Selection.collapsed( transactionBuilder.afterSelection = Selection.collapsed(
Position( Position(
path: previousTextNode.path, path: previousTextNode.path,
offset: previousTextNode.toRawString().length, offset: previousTextNode.toPlainText().length,
), ),
); );
} }
@ -267,7 +267,7 @@ void _deleteTextNodes(TransactionBuilder transactionBuilder,
List<TextNode> textNodes, Selection selection) { List<TextNode> textNodes, Selection selection) {
final first = textNodes.first; final first = textNodes.first;
final last = textNodes.last; final last = textNodes.last;
var content = textNodes.last.toRawString(); var content = textNodes.last.toPlainText();
content = content.substring(selection.end.offset, content.length); content = content.substring(selection.end.offset, content.length);
// Merge the fist and the last text node content, // Merge the fist and the last text node content,
// and delete the all nodes expect for the first. // and delete the all nodes expect for the first.

View File

@ -136,10 +136,10 @@ void _pasteMultipleLinesInText(
final tailTextNode = tailNodes.last as TextNode; final tailTextNode = tailNodes.last as TextNode;
tailTextNode.delta = tailTextNode.delta + remain; tailTextNode.delta = tailTextNode.delta + remain;
} else if (remain.isNotEmpty) { } else if (remain.isNotEmpty) {
tailNodes.add(TextNode(type: "text", delta: remain)); tailNodes.add(TextNode(delta: remain));
} }
} else { } else {
tailNodes.add(TextNode(type: "text", delta: remain)); tailNodes.add(TextNode(delta: remain));
} }
tb.setAfterSelection(afterSelection); tb.setAfterSelection(afterSelection);
@ -261,9 +261,8 @@ void _handlePastePlainText(EditorState editorState, String plainText) {
path[path.length - 1]++; path[path.length - 1]++;
final tb = TransactionBuilder(editorState); final tb = TransactionBuilder(editorState);
final List<TextNode> nodes = remains final List<TextNode> nodes =
.map((e) => TextNode(type: "text", delta: _lineContentToDelta(e))) remains.map((e) => TextNode(delta: _lineContentToDelta(e))).toList();
.toList();
final afterSelection = final afterSelection =
_computeSelectionAfterPasteMultipleNodes(editorState, nodes); _computeSelectionAfterPasteMultipleNodes(editorState, nodes);
@ -272,7 +271,7 @@ void _handlePastePlainText(EditorState editorState, String plainText) {
if (nodes.isNotEmpty) { if (nodes.isNotEmpty) {
final last = nodes.last; final last = nodes.last;
nodes[nodes.length - 1] = nodes[nodes.length - 1] =
TextNode(type: "text", delta: last.delta..addAll(insertedLineSuffix)); TextNode(delta: last.delta..addAll(insertedLineSuffix));
} }
// insert first line // insert first line

View File

@ -43,7 +43,7 @@ ShortcutEventHandler enterWithoutShiftInTextNodesHandler =
..deleteText( ..deleteText(
textNodes.first, textNodes.first,
selection.start.offset, selection.start.offset,
textNodes.first.toRawString().length, textNodes.first.toPlainText().length,
) )
..deleteNodes(subTextNodes) ..deleteNodes(subTextNodes)
..deleteText( ..deleteText(
@ -73,7 +73,7 @@ ShortcutEventHandler enterWithoutShiftInTextNodesHandler =
// If selection is collapsed and position.start.offset == 0, // If selection is collapsed and position.start.offset == 0,
// insert a empty text node before. // insert a empty text node before.
if (selection.isCollapsed && selection.start.offset == 0) { if (selection.isCollapsed && selection.start.offset == 0) {
if (textNode.toRawString().isEmpty && textNode.subtype != null) { if (textNode.toPlainText().isEmpty && textNode.subtype != null) {
final afterSelection = Selection.collapsed( final afterSelection = Selection.collapsed(
Position(path: textNode.path, offset: 0), Position(path: textNode.path, offset: 0),
); );
@ -156,7 +156,7 @@ ShortcutEventHandler enterWithoutShiftInTextNodesHandler =
transactionBuilder.deleteText( transactionBuilder.deleteText(
textNode, textNode,
selection.start.offset, selection.start.offset,
textNode.toRawString().length - selection.start.offset, textNode.toPlainText().length - selection.start.offset,
); );
if (textNode.children.isNotEmpty) { if (textNode.children.isNotEmpty) {
final children = textNode.children.toList(growable: false); final children = textNode.children.toList(growable: false);

View File

@ -2,7 +2,7 @@ import 'package:appflowy_editor/src/service/default_text_operations/format_rich_
import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart'; import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
ShortcutEventHandler formatBoldEventHandler = (editorState, event) { ShortcutEventHandler formatBoldEventHandler = (editorState, event) {
final selection = editorState.service.selectionService.currentSelection.value; final selection = editorState.service.selectionService.currentSelection.value;

View File

@ -44,7 +44,7 @@ ShortcutEventHandler backquoteToCodeHandler = (editorState, event) {
final textNode = textNodes.first; final textNode = textNodes.first;
final selectionText = textNode final selectionText = textNode
.toRawString() .toPlainText()
.substring(selection.start.offset, selection.end.offset); .substring(selection.start.offset, selection.end.offset);
// toggle code style when selected some text // toggle code style when selected some text
@ -53,7 +53,7 @@ ShortcutEventHandler backquoteToCodeHandler = (editorState, event) {
return KeyEventResult.handled; return KeyEventResult.handled;
} }
final text = textNode.toRawString().substring(0, selection.end.offset); final text = textNode.toPlainText().substring(0, selection.end.offset);
final backquoteIndexes = _findBackquoteIndexes(text, textNode); final backquoteIndexes = _findBackquoteIndexes(text, textNode);
if (backquoteIndexes.isEmpty) { if (backquoteIndexes.isEmpty) {
return KeyEventResult.ignored; return KeyEventResult.ignored;
@ -134,7 +134,7 @@ ShortcutEventHandler doubleTildeToStrikethrough = (editorState, event) {
} }
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString().substring(0, selection.end.offset); final text = textNode.toPlainText().substring(0, selection.end.offset);
// make sure the last two characters are ~~. // make sure the last two characters are ~~.
if (text.length < 2 || text[selection.end.offset - 1] != '~') { if (text.length < 2 || text[selection.end.offset - 1] != '~') {
@ -199,7 +199,7 @@ ShortcutEventHandler markdownLinkToLinkHandler = (editorState, event) {
// find all of the indexs for important characters // find all of the indexs for important characters
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString(); final text = textNode.toPlainText();
final firstOpeningBracket = text.indexOf('['); final firstOpeningBracket = text.indexOf('[');
final firstClosingBracket = text.indexOf(']'); final firstClosingBracket = text.indexOf(']');

View File

@ -11,7 +11,7 @@ ShortcutEventHandler doubleAsterisksToBold = (editorState, event) {
} }
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString().substring(0, selection.end.offset); final text = textNode.toPlainText().substring(0, selection.end.offset);
// make sure the last two characters are **. // make sure the last two characters are **.
if (text.length < 2 || text[selection.end.offset - 1] != '*') { if (text.length < 2 || text[selection.end.offset - 1] != '*') {
@ -75,7 +75,7 @@ ShortcutEventHandler doubleUnderscoresToBold = (editorState, event) {
} }
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString().substring(0, selection.end.offset); final text = textNode.toPlainText().substring(0, selection.end.offset);
// make sure the last two characters are __. // make sure the last two characters are __.
if (text.length < 2 || text[selection.end.offset - 1] != '_') { if (text.length < 2 || text[selection.end.offset - 1] != '_') {

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart'; import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart'; import 'package:appflowy_editor/src/operation/transaction_builder.dart';
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service.dart'; import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service.dart';
import 'package:appflowy_editor/src/extensions/node_extensions.dart'; import 'package:appflowy_editor/src/extensions/node_extensions.dart';

View File

@ -2,7 +2,7 @@ import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handle
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart'; import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
@ -44,7 +44,7 @@ ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
} }
final textNode = textNodes.first; final textNode = textNodes.first;
final text = textNode.toRawString().substring(0, selection.end.offset); final text = textNode.toPlainText().substring(0, selection.end.offset);
final numberMatch = _numberRegex.firstMatch(text); final numberMatch = _numberRegex.firstMatch(text);
@ -140,13 +140,13 @@ KeyEventResult _toCheckboxList(EditorState editorState, TextNode textNode) {
final String symbol; final String symbol;
bool check = false; bool check = false;
final symbols = List<String>.from(_checkboxListSymbols) final symbols = List<String>.from(_checkboxListSymbols)
..retainWhere(textNode.toRawString().startsWith); ..retainWhere(textNode.toPlainText().startsWith);
if (symbols.isNotEmpty) { if (symbols.isNotEmpty) {
symbol = symbols.first; symbol = symbols.first;
check = true; check = true;
} else { } else {
symbol = (List<String>.from(_unCheckboxListSymbols) symbol = (List<String>.from(_unCheckboxListSymbols)
..retainWhere(textNode.toRawString().startsWith)) ..retainWhere(textNode.toPlainText().startsWith))
.first; .first;
check = false; check = false;
} }
@ -170,7 +170,7 @@ KeyEventResult _toCheckboxList(EditorState editorState, TextNode textNode) {
KeyEventResult _toHeadingStyle( KeyEventResult _toHeadingStyle(
EditorState editorState, TextNode textNode, Selection selection) { EditorState editorState, TextNode textNode, Selection selection) {
final x = _countOfSign( final x = _countOfSign(
textNode.toRawString(), textNode.toPlainText(),
selection, selection,
); );
final hX = 'h$x'; final hX = 'h$x';

View File

@ -1,4 +1,4 @@
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/log.dart'; import 'package:appflowy_editor/src/infra/log.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -1,7 +1,7 @@
import 'package:appflowy_editor/src/infra/log.dart'; import 'package:appflowy_editor/src/infra/log.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/document/node_iterator.dart'; import 'package:appflowy_editor/src/document/node_iterator.dart';
import 'package:appflowy_editor/src/document/position.dart'; import 'package:appflowy_editor/src/document/position.dart';
import 'package:appflowy_editor/src/document/selection.dart'; import 'package:appflowy_editor/src/document/selection.dart';

View File

@ -57,7 +57,6 @@ void main() async {
test('test textNode copyWith', () { test('test textNode copyWith', () {
final textNode = TextNode( final textNode = TextNode(
type: 'example',
children: LinkedList(), children: LinkedList(),
attributes: { attributes: {
'example': 'example', 'example': 'example',
@ -65,7 +64,7 @@ void main() async {
delta: Delta()..insert('AppFlowy'), delta: Delta()..insert('AppFlowy'),
); );
expect(textNode.toJson(), { expect(textNode.toJson(), {
'type': 'example', 'type': 'text',
'attributes': { 'attributes': {
'example': 'example', 'example': 'example',
}, },
@ -79,7 +78,6 @@ void main() async {
); );
final textNodeWithChildren = TextNode( final textNodeWithChildren = TextNode(
type: 'example',
children: LinkedList()..add(textNode), children: LinkedList()..add(textNode),
attributes: { attributes: {
'example': 'example', 'example': 'example',
@ -87,7 +85,7 @@ void main() async {
delta: Delta()..insert('AppFlowy'), delta: Delta()..insert('AppFlowy'),
); );
expect(textNodeWithChildren.toJson(), { expect(textNodeWithChildren.toJson(), {
'type': 'example', 'type': 'text',
'attributes': { 'attributes': {
'example': 'example', 'example': 'example',
}, },
@ -96,7 +94,7 @@ void main() async {
], ],
'children': [ 'children': [
{ {
'type': 'example', 'type': 'text',
'attributes': { 'attributes': {
'example': 'example', 'example': 'example',
}, },

View File

@ -15,7 +15,6 @@ void main() async {
const text = 'Welcome to Appflowy 😁'; const text = 'Welcome to Appflowy 😁';
TextNode textNode() { TextNode textNode() {
return TextNode( return TextNode(
type: 'text',
delta: Delta()..insert(text), delta: Delta()..insert(text),
); );
} }

View File

@ -63,7 +63,6 @@ class EditorWidgetTester {
void insertTextNode(String? text, {Attributes? attributes, Delta? delta}) { void insertTextNode(String? text, {Attributes? attributes, Delta? delta}) {
insert( insert(
TextNode( TextNode(
type: 'text',
delta: delta ?? Delta([TextInsert(text ?? 'Test')]), delta: delta ?? Delta([TextInsert(text ?? 'Test')]),
attributes: attributes, attributes: attributes,
), ),
@ -103,7 +102,7 @@ class EditorWidgetTester {
{Selection? selection}) async { {Selection? selection}) async {
await apply([ await apply([
TextEditingDeltaInsertion( TextEditingDeltaInsertion(
oldText: textNode.toRawString(), oldText: textNode.toPlainText(),
textInserted: text, textInserted: text,
insertionOffset: offset, insertionOffset: offset,
selection: selection != null selection: selection != null

View File

@ -318,12 +318,12 @@ void main() {
}); });
group("attributes", () { group("attributes", () {
test("compose", () { test("compose", () {
final attrs = composeAttributes({"a": null}, {"b": null}, true); final attrs = composeAttributes({'a': null}, {'b': null}, keepNull: true);
expect(attrs != null, true); expect(attrs != null, true);
expect(attrs!.containsKey("a"), true); expect(attrs?.containsKey("a"), true);
expect(attrs.containsKey("b"), true); expect(attrs?.containsKey("b"), true);
expect(attrs["a"], null); expect(attrs?["a"], null);
expect(attrs["b"], null); expect(attrs?["b"], null);
}); });
}); });
} }

View File

@ -1,6 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:appflowy_editor/src/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy_editor/src/operation/operation.dart'; import 'package:appflowy_editor/src/operation/operation.dart';
import 'package:appflowy_editor/src/operation/transaction_builder.dart'; import 'package:appflowy_editor/src/operation/transaction_builder.dart';

View File

@ -21,12 +21,12 @@ void main() async {
final editorState = EditorState(document: document); final editorState = EditorState(document: document);
final historyItem = HistoryItem(); final historyItem = HistoryItem();
historyItem.add(DeleteOperation( historyItem
[0], [TextNode(type: 'text', delta: Delta()..insert('0'))])); .add(DeleteOperation([0], [TextNode(delta: Delta()..insert('0'))]));
historyItem.add(DeleteOperation( historyItem
[0], [TextNode(type: 'text', delta: Delta()..insert('1'))])); .add(DeleteOperation([0], [TextNode(delta: Delta()..insert('1'))]));
historyItem.add(DeleteOperation( historyItem
[0], [TextNode(type: 'text', delta: Delta()..insert('2'))])); .add(DeleteOperation([0], [TextNode(delta: Delta()..insert('2'))]));
final transaction = historyItem.toTransaction(editorState); final transaction = historyItem.toTransaction(editorState);
assert(isInsertAndPathEqual(transaction.operations[0], [0], '2')); assert(isInsertAndPathEqual(transaction.operations[0], [0], '2'));
@ -39,8 +39,8 @@ void main() async {
final editorState = EditorState(document: document); final editorState = EditorState(document: document);
final historyItem = HistoryItem(); final historyItem = HistoryItem();
historyItem.add(DeleteOperation( historyItem
[0], [TextNode(type: 'text', delta: Delta()..insert('0'))])); .add(DeleteOperation([0], [TextNode(delta: Delta()..insert('0'))]));
historyItem historyItem
.add(UpdateOperation([0], {"subType": "number"}, {"subType": null})); .add(UpdateOperation([0], {"subType": "number"}, {"subType": null}));
historyItem.add(DeleteOperation([0], [TextNode.empty(), TextNode.empty()])); historyItem.add(DeleteOperation([0], [TextNode.empty(), TextNode.empty()]));
@ -72,5 +72,5 @@ bool isInsertAndPathEqual(Operation operation, Path path, [String? content]) {
return true; return true;
} }
return firstNode.delta.toRawString() == content; return firstNode.delta.toPlainText() == content;
} }

View File

@ -147,7 +147,7 @@ Future<void> _testDefaultSelectionMenuItems(
int index, EditorWidgetTester editor) async { int index, EditorWidgetTester editor) async {
expect(editor.documentLength, 4); expect(editor.documentLength, 4);
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 0)); expect(editor.documentSelection, Selection.single(path: [2], startOffset: 0));
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), expect((editor.nodeAtPath([1]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁'); 'Welcome to Appflowy 😁');
final node = editor.nodeAtPath([2]); final node = editor.nodeAtPath([2]);
final item = defaultSelectionMenuItems[index]; final item = defaultSelectionMenuItems[index];

View File

@ -117,7 +117,7 @@ void main() async {
expect(editor.documentLength, 1); expect(editor.documentLength, 1);
expect(editor.documentSelection, expect(editor.documentSelection,
Selection.single(path: [0], startOffset: text.length)); Selection.single(path: [0], startOffset: text.length));
expect((editor.nodeAtPath([0]) as TextNode).toRawString(), text * 2); expect((editor.nodeAtPath([0]) as TextNode).toPlainText(), text * 2);
}); });
// Before // Before
@ -275,7 +275,6 @@ void main() async {
// * Welcome to Appflowy 😁 // * Welcome to Appflowy 😁
const text = 'Welcome to Appflowy 😁'; const text = 'Welcome to Appflowy 😁';
final node = TextNode( final node = TextNode(
type: 'text',
delta: Delta()..insert(text), delta: Delta()..insert(text),
attributes: { attributes: {
BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList, BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList,
@ -320,7 +319,7 @@ void main() async {
editor.documentSelection, editor.documentSelection,
Selection.single(path: [0, 0], startOffset: text.length), Selection.single(path: [0, 0], startOffset: text.length),
); );
expect((editor.nodeAtPath([0, 0]) as TextNode).toRawString(), text * 2); expect((editor.nodeAtPath([0, 0]) as TextNode).toPlainText(), text * 2);
}); });
testWidgets('Delete the complicated nested bulleted list', (tester) async { testWidgets('Delete the complicated nested bulleted list', (tester) async {
@ -331,7 +330,6 @@ void main() async {
// * Welcome to Appflowy 😁 // * Welcome to Appflowy 😁
const text = 'Welcome to Appflowy 😁'; const text = 'Welcome to Appflowy 😁';
final node = TextNode( final node = TextNode(
type: 'text',
delta: Delta()..insert(text), delta: Delta()..insert(text),
attributes: { attributes: {
BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList, BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList,
@ -390,7 +388,7 @@ void main() async {
true, true,
); );
expect( expect(
(editor.nodeAtPath([0, 0]) as TextNode).toRawString() == text * 2, (editor.nodeAtPath([0, 0]) as TextNode).toPlainText() == text * 2,
true, true,
); );
expect( expect(
@ -496,7 +494,7 @@ Future<void> _deleteStyledTextByBackspace(
expect(editor.documentSelection, expect(editor.documentSelection,
Selection.single(path: [1], startOffset: text.length)); Selection.single(path: [1], startOffset: text.length));
expect(editor.nodeAtPath([1])?.subtype, style); expect(editor.nodeAtPath([1])?.subtype, style);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text * 2); expect((editor.nodeAtPath([1]) as TextNode).toPlainText(), text * 2);
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [1], startOffset: 0), Selection.single(path: [1], startOffset: 0),
@ -538,7 +536,7 @@ Future<void> _deleteStyledTextByDelete(
expect( expect(
editor.documentSelection, Selection.single(path: [1], startOffset: 0)); editor.documentSelection, Selection.single(path: [1], startOffset: 0));
expect(editor.nodeAtPath([1])?.subtype, style); expect(editor.nodeAtPath([1])?.subtype, style);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), expect((editor.nodeAtPath([1]) as TextNode).toPlainText(),
text.safeSubString(i)); text.safeSubString(i));
} }
@ -548,7 +546,7 @@ Future<void> _deleteStyledTextByDelete(
expect(editor.documentLength, 2); expect(editor.documentLength, 2);
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 0)); expect(editor.documentSelection, Selection.single(path: [1], startOffset: 0));
expect(editor.nodeAtPath([1])?.subtype, style); expect(editor.nodeAtPath([1])?.subtype, style);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text); expect((editor.nodeAtPath([1]) as TextNode).toPlainText(), text);
} }
Future<void> _deleteTextByBackspace( Future<void> _deleteTextByBackspace(
@ -568,7 +566,7 @@ Future<void> _deleteTextByBackspace(
expect(editor.documentLength, 3); expect(editor.documentLength, 3);
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9)); expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9));
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), expect((editor.nodeAtPath([1]) as TextNode).toPlainText(),
'Welcome t Appflowy 😁'); 'Welcome t Appflowy 😁');
// delete 'to ' // delete 'to '
@ -578,7 +576,7 @@ Future<void> _deleteTextByBackspace(
await editor.pressLogicKey(LogicalKeyboardKey.backspace); await editor.pressLogicKey(LogicalKeyboardKey.backspace);
expect(editor.documentLength, 3); expect(editor.documentLength, 3);
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8)); expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8));
expect((editor.nodeAtPath([2]) as TextNode).toRawString(), expect((editor.nodeAtPath([2]) as TextNode).toPlainText(),
'Welcome Appflowy 😁'); 'Welcome Appflowy 😁');
// delete 'Appflowy 😁 // delete 'Appflowy 😁
@ -593,7 +591,7 @@ Future<void> _deleteTextByBackspace(
expect(editor.documentLength, 1); expect(editor.documentLength, 1);
expect( expect(
editor.documentSelection, Selection.single(path: [0], startOffset: 11)); editor.documentSelection, Selection.single(path: [0], startOffset: 11));
expect((editor.nodeAtPath([0]) as TextNode).toRawString(), expect((editor.nodeAtPath([0]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁'); 'Welcome to Appflowy 😁');
} }
@ -614,7 +612,7 @@ Future<void> _deleteTextByDelete(
expect(editor.documentLength, 3); expect(editor.documentLength, 3);
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9)); expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9));
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), expect((editor.nodeAtPath([1]) as TextNode).toPlainText(),
'Welcome t Appflowy 😁'); 'Welcome t Appflowy 😁');
// delete 'to ' // delete 'to '
@ -624,7 +622,7 @@ Future<void> _deleteTextByDelete(
await editor.pressLogicKey(LogicalKeyboardKey.delete); await editor.pressLogicKey(LogicalKeyboardKey.delete);
expect(editor.documentLength, 3); expect(editor.documentLength, 3);
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8)); expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8));
expect((editor.nodeAtPath([2]) as TextNode).toRawString(), expect((editor.nodeAtPath([2]) as TextNode).toPlainText(),
'Welcome Appflowy 😁'); 'Welcome Appflowy 😁');
// delete 'Appflowy 😁 // delete 'Appflowy 😁
@ -639,6 +637,6 @@ Future<void> _deleteTextByDelete(
expect(editor.documentLength, 1); expect(editor.documentLength, 1);
expect( expect(
editor.documentSelection, Selection.single(path: [0], startOffset: 11)); editor.documentSelection, Selection.single(path: [0], startOffset: 11));
expect((editor.nodeAtPath([0]) as TextNode).toRawString(), expect((editor.nodeAtPath([0]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁'); 'Welcome to Appflowy 😁');
} }

View File

@ -74,10 +74,10 @@ void main() async {
expect(lastNode != null, true); expect(lastNode != null, true);
expect(lastNode is TextNode, true); expect(lastNode is TextNode, true);
lastNode = lastNode as TextNode; lastNode = lastNode as TextNode;
expect(lastNode.delta.toRawString(), text); expect(lastNode.delta.toPlainText(), text);
expect((lastNode.previous as TextNode).delta.toRawString(), ''); expect((lastNode.previous as TextNode).delta.toPlainText(), '');
expect( expect(
(lastNode.previous!.previous as TextNode).delta.toRawString(), text); (lastNode.previous!.previous as TextNode).delta.toPlainText(), text);
}); });
// Before // Before
@ -134,7 +134,7 @@ void main() async {
); );
await editor.pressLogicKey(LogicalKeyboardKey.enter); await editor.pressLogicKey(LogicalKeyboardKey.enter);
expect(editor.documentLength, 2); expect(editor.documentLength, 2);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text); expect((editor.nodeAtPath([1]) as TextNode).toPlainText(), text);
}); });
}); });
} }
@ -227,6 +227,6 @@ Future<void> _testMultipleSelection(
); );
expect(editor.documentLength, 2); expect(editor.documentLength, 2);
expect((editor.nodeAtPath([0]) as TextNode).toRawString(), 'Welcome'); expect((editor.nodeAtPath([0]) as TextNode).toPlainText(), 'Welcome');
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), 'to Appflowy 😁'); expect((editor.nodeAtPath([1]) as TextNode).toPlainText(), 'to Appflowy 😁');
} }

View File

@ -39,11 +39,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('App**Flowy** to bold AppFlowy', (tester) async { testWidgets('App**Flowy** to bold AppFlowy', (tester) async {
@ -62,11 +62,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('***AppFlowy** to bold *AppFlowy', (tester) async { testWidgets('***AppFlowy** to bold *AppFlowy', (tester) async {
@ -85,11 +85,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), '*AppFlowy'); expect(textNode.toPlainText(), '*AppFlowy');
}); });
testWidgets('**AppFlowy** application to bold AppFlowy only', testWidgets('**AppFlowy** application to bold AppFlowy only',
@ -115,7 +115,7 @@ void main() async {
), ),
); );
expect(appFlowyBold, true); expect(appFlowyBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('**** nothing changes', (tester) async { testWidgets('**** nothing changes', (tester) async {
@ -134,11 +134,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, false); expect(allBold, false);
expect(textNode.toRawString(), text); expect(textNode.toPlainText(), text);
}); });
}); });
@ -171,11 +171,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('App__Flowy__ to bold AppFlowy', (tester) async { testWidgets('App__Flowy__ to bold AppFlowy', (tester) async {
@ -194,11 +194,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('___AppFlowy__ to bold _AppFlowy', (tester) async { testWidgets('___AppFlowy__ to bold _AppFlowy', (tester) async {
@ -217,11 +217,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, true); expect(allBold, true);
expect(textNode.toRawString(), '_AppFlowy'); expect(textNode.toPlainText(), '_AppFlowy');
}); });
testWidgets('__AppFlowy__ application to bold AppFlowy only', testWidgets('__AppFlowy__ application to bold AppFlowy only',
@ -247,7 +247,7 @@ void main() async {
), ),
); );
expect(appFlowyBold, true); expect(appFlowyBold, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('____ nothing changes', (tester) async { testWidgets('____ nothing changes', (tester) async {
@ -266,11 +266,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allBold, false); expect(allBold, false);
expect(textNode.toRawString(), text); expect(textNode.toPlainText(), text);
}); });
}); });
}); });

View File

@ -38,11 +38,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allCode, true); expect(allCode, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('App`Flowy` to code AppFlowy', (tester) async { testWidgets('App`Flowy` to code AppFlowy', (tester) async {
@ -61,11 +61,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allCode, true); expect(allCode, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('`` nothing changes', (tester) async { testWidgets('`` nothing changes', (tester) async {
@ -84,11 +84,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allCode, false); expect(allCode, false);
expect(textNode.toRawString(), text); expect(textNode.toPlainText(), text);
}); });
}); });
@ -120,11 +120,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allCode, true); expect(allCode, true);
expect(textNode.toRawString(), '`AppFlowy'); expect(textNode.toPlainText(), '`AppFlowy');
}); });
testWidgets('```` nothing changes', (tester) async { testWidgets('```` nothing changes', (tester) async {
@ -143,11 +143,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allCode, false); expect(allCode, false);
expect(textNode.toRawString(), text); expect(textNode.toPlainText(), text);
}); });
}); });
@ -180,11 +180,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allStrikethrough, true); expect(allStrikethrough, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('App~~Flowy~~ to strikethrough AppFlowy', (tester) async { testWidgets('App~~Flowy~~ to strikethrough AppFlowy', (tester) async {
@ -203,11 +203,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allStrikethrough, true); expect(allStrikethrough, true);
expect(textNode.toRawString(), 'AppFlowy'); expect(textNode.toPlainText(), 'AppFlowy');
}); });
testWidgets('~~~AppFlowy~~ to bold ~AppFlowy', (tester) async { testWidgets('~~~AppFlowy~~ to bold ~AppFlowy', (tester) async {
@ -226,11 +226,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allStrikethrough, true); expect(allStrikethrough, true);
expect(textNode.toRawString(), '~AppFlowy'); expect(textNode.toPlainText(), '~AppFlowy');
}); });
testWidgets('~~~~ nothing changes', (tester) async { testWidgets('~~~~ nothing changes', (tester) async {
@ -249,11 +249,11 @@ void main() async {
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toRawString().length, endOffset: textNode.toPlainText().length,
), ),
); );
expect(allStrikethrough, false); expect(allStrikethrough, false);
expect(textNode.toRawString(), text); expect(textNode.toPlainText(), text);
}); });
}); });
}); });

View File

@ -56,7 +56,7 @@ Future<void> _testBackspaceUndoRedo(
} }
expect(editor.documentLength, 3); expect(editor.documentLength, 3);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text); expect((editor.nodeAtPath([1]) as TextNode).toPlainText(), text);
expect(editor.documentSelection, selection); expect(editor.documentSelection, selection);
if (Platform.isWindows || Platform.isLinux) { if (Platform.isWindows || Platform.isLinux) {

View File

@ -26,7 +26,7 @@ void main() async {
); );
await editor.pressLogicKey(LogicalKeyboardKey.space); await editor.pressLogicKey(LogicalKeyboardKey.space);
expect( expect(
(editor.nodeAtPath([i]) as TextNode).toRawString(), (editor.nodeAtPath([i]) as TextNode).toPlainText(),
'W elcome to Appflowy 😁', 'W elcome to Appflowy 😁',
); );
} }
@ -36,7 +36,7 @@ void main() async {
); );
await editor.pressLogicKey(LogicalKeyboardKey.space); await editor.pressLogicKey(LogicalKeyboardKey.space);
expect( expect(
(editor.nodeAtPath([i]) as TextNode).toRawString(), (editor.nodeAtPath([i]) as TextNode).toPlainText(),
'W elcome to Appflowy 😁 ', 'W elcome to Appflowy 😁 ',
); );
} }

View File

@ -87,7 +87,7 @@ void main() async {
expect(textNode.subtype, BuiltInAttributeKey.heading); expect(textNode.subtype, BuiltInAttributeKey.heading);
// BuiltInAttributeKey.h1 ~ BuiltInAttributeKey.h6 // BuiltInAttributeKey.h1 ~ BuiltInAttributeKey.h6
expect(textNode.attributes.heading, 'h$i'); expect(textNode.attributes.heading, 'h$i');
expect(textNode.toRawString().startsWith('##'), true); expect(textNode.toPlainText().startsWith('##'), true);
} }
}); });
@ -211,7 +211,7 @@ void main() async {
await editor.pressLogicKey(LogicalKeyboardKey.space); await editor.pressLogicKey(LogicalKeyboardKey.space);
expect(textNode.subtype, BuiltInAttributeKey.checkbox); expect(textNode.subtype, BuiltInAttributeKey.checkbox);
expect(textNode.attributes.check, true); expect(textNode.attributes.check, true);
expect(textNode.toRawString(), insertedText); expect(textNode.toPlainText(), insertedText);
}); });
}); });
} }