feat: implement converting 1. to numbered list style
This commit is contained in:
parent
6df42d4b8a
commit
f624f3a308
11 changed files with 377 additions and 149 deletions
|
|
@ -84,6 +84,9 @@ class SimpleEditor extends StatelessWidget {
|
||||||
formatAsteriskToBulletedList,
|
formatAsteriskToBulletedList,
|
||||||
formatMinusToBulletedList,
|
formatMinusToBulletedList,
|
||||||
|
|
||||||
|
// numbered list
|
||||||
|
formatNumberToNumberedList,
|
||||||
|
|
||||||
// slash
|
// slash
|
||||||
slashCommand,
|
slashCommand,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ class Position {
|
||||||
this.offset = 0,
|
this.offset = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Position.invalid()
|
||||||
|
: path = [-1],
|
||||||
|
offset = -1;
|
||||||
|
|
||||||
factory Position.fromJson(Map<String, dynamic> json) {
|
factory Position.fromJson(Map<String, dynamic> json) {
|
||||||
final path = Path.from(json['path'] as List);
|
final path = Path.from(json['path'] as List);
|
||||||
final offset = json['offset'];
|
final offset = json['offset'];
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ class Selection {
|
||||||
: start = position,
|
: start = position,
|
||||||
end = position;
|
end = position;
|
||||||
|
|
||||||
|
Selection.invalid()
|
||||||
|
: start = Position.invalid(),
|
||||||
|
end = Position.invalid();
|
||||||
|
|
||||||
final Position start;
|
final Position start;
|
||||||
final Position end;
|
final Position end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
|
||||||
|
/// Formats the current node to specified markdown style.
|
||||||
|
///
|
||||||
|
/// For example,
|
||||||
|
/// bulleted list: '- '
|
||||||
|
/// numbered list: '1. '
|
||||||
|
/// quote: '> '
|
||||||
|
/// ...
|
||||||
|
Future<bool> formatMarkdownSymbol(
|
||||||
|
EditorState editorState,
|
||||||
|
bool Function(Node node) shouldFormat,
|
||||||
|
bool Function(
|
||||||
|
String text,
|
||||||
|
Selection selection,
|
||||||
|
)
|
||||||
|
predicate,
|
||||||
|
Node Function(
|
||||||
|
String text,
|
||||||
|
Node node,
|
||||||
|
Delta delta,
|
||||||
|
)
|
||||||
|
nodeBuilder,
|
||||||
|
) async {
|
||||||
|
final selection = editorState.selection;
|
||||||
|
if (selection == null || !selection.isCollapsed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final position = selection.end;
|
||||||
|
final node = editorState.getNodeAtPath(position.path);
|
||||||
|
|
||||||
|
if (node == null || !shouldFormat(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the text from the start of the document until the selection.
|
||||||
|
final delta = node.delta;
|
||||||
|
if (delta == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final text = delta.toPlainText().substring(0, selection.end.offset);
|
||||||
|
|
||||||
|
// If the text doesn't match the predicate, then we don't want to
|
||||||
|
// format it.
|
||||||
|
if (!predicate(text, selection)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final afterSelection = Selection.collapsed(
|
||||||
|
Position(
|
||||||
|
path: node.path,
|
||||||
|
offset: 0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final formattedNode = nodeBuilder(text, node, delta);
|
||||||
|
|
||||||
|
// Create a transaction that replaces the current node with the
|
||||||
|
// formatted node.
|
||||||
|
final transaction = editorState.transaction
|
||||||
|
..insertNode(
|
||||||
|
node.path,
|
||||||
|
formattedNode,
|
||||||
|
)
|
||||||
|
..deleteNode(node)
|
||||||
|
..afterSelection = afterSelection;
|
||||||
|
|
||||||
|
await editorState.apply(transaction);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ export 'bulleted_list_block_component/bulleted_list_character_shortcut.dart';
|
||||||
|
|
||||||
// numbered list
|
// numbered list
|
||||||
export 'numbered_list_block_component/numbered_list_block_component.dart';
|
export 'numbered_list_block_component/numbered_list_block_component.dart';
|
||||||
|
export 'numbered_list_block_component/numbered_list_character_shortcut.dart';
|
||||||
|
|
||||||
// quote
|
// quote
|
||||||
export 'quote_block_component/quote_block_component.dart';
|
export 'quote_block_component/quote_block_component.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:appflowy_editor/src/editor/block_component/base_component/markdown_format_helper.dart';
|
||||||
|
|
||||||
/// Convert '* ' to bulleted list
|
/// Convert '* ' to bulleted list
|
||||||
///
|
///
|
||||||
|
|
@ -38,45 +39,15 @@ Future<bool> _formatSymbolToBulletedList(
|
||||||
) async {
|
) async {
|
||||||
assert(symbol.length == 1);
|
assert(symbol.length == 1);
|
||||||
|
|
||||||
final selection = editorState.selection;
|
return formatMarkdownSymbol(
|
||||||
if (selection == null || !selection.isCollapsed) {
|
editorState,
|
||||||
return false;
|
(node) => node.type != 'bulleted_list',
|
||||||
}
|
(text, _) => text == symbol,
|
||||||
|
(_, node, delta) => Node(
|
||||||
final nodes = editorState.getNodesInSelection(selection);
|
type: 'bulleted_list',
|
||||||
if (nodes.length != 1 || nodes.first.type == 'bulleted_list') {
|
attributes: {
|
||||||
return false;
|
'delta': delta.compose(Delta()..delete(symbol.length)).toJson(),
|
||||||
}
|
},
|
||||||
|
|
||||||
final node = nodes.first;
|
|
||||||
final delta = node.delta;
|
|
||||||
if (delta == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final text = delta.toPlainText().substring(0, selection.end.offset);
|
|
||||||
if (symbol != text) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final afterSelection = Selection.collapsed(
|
|
||||||
Position(
|
|
||||||
path: node.path,
|
|
||||||
offset: 0,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final bulletedListNode = Node(
|
|
||||||
type: 'bulleted_list',
|
|
||||||
attributes: {
|
|
||||||
'delta': delta.compose(Delta()..delete(symbol.length)).toJson(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
final transaction = editorState.transaction
|
|
||||||
..insertNode(
|
|
||||||
node.path,
|
|
||||||
bulletedListNode,
|
|
||||||
)
|
|
||||||
..deleteNode(node)
|
|
||||||
..afterSelection = afterSelection;
|
|
||||||
await editorState.apply(transaction);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:appflowy_editor/src/editor/block_component/base_component/markdown_format_helper.dart';
|
||||||
|
|
||||||
|
final _numberRegex = RegExp(r'^(\d+)\.');
|
||||||
|
|
||||||
|
/// Convert 'num. ' to bulleted list
|
||||||
|
///
|
||||||
|
/// - support
|
||||||
|
/// - desktop
|
||||||
|
/// - mobile
|
||||||
|
/// - web
|
||||||
|
///
|
||||||
|
CharacterShortcutEvent formatNumberToNumberedList = CharacterShortcutEvent(
|
||||||
|
key: 'format number to numbered list',
|
||||||
|
character: ' ',
|
||||||
|
handler: (editorState) async => await formatMarkdownSymbol(
|
||||||
|
editorState,
|
||||||
|
(node) => node.type != 'numbered_list',
|
||||||
|
(text, selection) {
|
||||||
|
final match = _numberRegex.firstMatch(text);
|
||||||
|
final matchText = match?.group(0);
|
||||||
|
final numberText = match?.group(1);
|
||||||
|
return match != null &&
|
||||||
|
matchText != null &&
|
||||||
|
numberText != null &&
|
||||||
|
selection.endIndex == matchText.length;
|
||||||
|
},
|
||||||
|
(text, node, delta) {
|
||||||
|
final match = _numberRegex.firstMatch(text)!;
|
||||||
|
final matchText = match.group(0)!;
|
||||||
|
return Node(
|
||||||
|
type: 'numbered_list',
|
||||||
|
attributes: {
|
||||||
|
'delta': delta.compose(Delta()..delete(matchText.length)).toJson(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
@ -28,6 +28,7 @@ dependencies:
|
||||||
markdown: ^7.0.1
|
markdown: ^7.0.1
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
tuple: ^2.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../../util/util.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
setUpAll(() {
|
||||||
|
if (kDebugMode) {
|
||||||
|
activateLog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDownAll(() {
|
||||||
|
if (kDebugMode) {
|
||||||
|
deactivateLog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
group('formatNumberToNumberedList', () {
|
||||||
|
// Before
|
||||||
|
// 1|Welcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// 1|Welcome to AppFlowy Editor 🔥!
|
||||||
|
test('mock inputting a ` ` after the number but not dot', () async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank().addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('1$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// 1|Welcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [0], offset: 1),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final before = editorState.getNodesInSelection(selection).first;
|
||||||
|
final result = await formatNumberToNumberedList.execute(editorState);
|
||||||
|
final after = editorState.getNodesInSelection(selection).first;
|
||||||
|
|
||||||
|
// nothing happens
|
||||||
|
expect(result, false);
|
||||||
|
expect(before.toJson(), after.toJson());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
// 1.|Welcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// [numbered_list]Welcome to AppFlowy Editor 🔥!
|
||||||
|
test(
|
||||||
|
'mock inputting a ` ` after the number which is located at the front of the text',
|
||||||
|
() async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank().addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('1.$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// 1.|Welcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [0], offset: 2),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final result = await formatNumberToNumberedList.execute(editorState);
|
||||||
|
|
||||||
|
expect(result, true);
|
||||||
|
final after = editorState.getNodeAtPath([0])!;
|
||||||
|
expect(after.delta!.toPlainText(), text);
|
||||||
|
expect(after.type, 'numbered_list');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
// 1.W|elcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// 1.W|elcome to AppFlowy Editor 🔥!
|
||||||
|
test('mock inputting a ` ` in the middle of the node', () async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank().addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('1.$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// 1.W|elcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [0], offset: 3),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final before = editorState.getNodesInSelection(selection).first;
|
||||||
|
final result = await formatNumberToNumberedList.execute(editorState);
|
||||||
|
final after = editorState.getNodesInSelection(selection).first;
|
||||||
|
|
||||||
|
// nothing happens
|
||||||
|
expect(result, false);
|
||||||
|
expect(before.toJson(), after.toJson());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
// 1.|Welcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
//[numbered_list] Welcome to AppFlowy Editor 🔥!
|
||||||
|
test(
|
||||||
|
'mock inputting a ` ` in the middle of the node, and there\'s a other node at the front of it.',
|
||||||
|
() async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank()
|
||||||
|
.addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert(text),
|
||||||
|
)
|
||||||
|
.addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('1.$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
// *|Welcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [1], offset: 2),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final result = await formatNumberToNumberedList.execute(editorState);
|
||||||
|
final after = editorState.getNodeAtPath([1])!;
|
||||||
|
|
||||||
|
// the second line will be formatted as the bulleted list style
|
||||||
|
expect(result, true);
|
||||||
|
expect(after.type, 'numbered_list');
|
||||||
|
expect(after.delta!.toPlainText(), text);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
import '../../util/util.dart';
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
group('bulleted_list_shortcut.dart', () {
|
|
||||||
setUpAll(() {
|
|
||||||
if (kDebugMode) {
|
|
||||||
activateLog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() {
|
|
||||||
if (kDebugMode) {
|
|
||||||
deactivateLog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
group('formatAsteriskToBulletedList', () {
|
|
||||||
// Before
|
|
||||||
// *|Welcome to AppFlowy Editor 🔥!
|
|
||||||
// After
|
|
||||||
// [bulleted_list]Welcome to AppFlowy Editor 🔥!
|
|
||||||
test(
|
|
||||||
'mock inputting a ` ` after asterisk which is located at the front of the text',
|
|
||||||
() async {
|
|
||||||
const text = 'Welcome to AppFlowy Editor 🔥!';
|
|
||||||
final document = Document.blank().addParagraphs(
|
|
||||||
1,
|
|
||||||
builder: (index) => Delta()..insert('*$text'),
|
|
||||||
);
|
|
||||||
final editorState = EditorState(document: document);
|
|
||||||
|
|
||||||
// *|Welcome to AppFlowy Editor 🔥!
|
|
||||||
final selection = Selection.collapsed(
|
|
||||||
Position(path: [0], offset: 1),
|
|
||||||
);
|
|
||||||
editorState.selection = selection;
|
|
||||||
final result = await formatAsteriskToBulletedList.execute(editorState);
|
|
||||||
|
|
||||||
expect(result, true);
|
|
||||||
final after = editorState.getNodeAtPath([0])!;
|
|
||||||
expect(after.delta!.toPlainText(), text);
|
|
||||||
expect(after.type, 'bulleted_list');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Before
|
|
||||||
// *W|elcome to AppFlowy Editor 🔥!
|
|
||||||
// After
|
|
||||||
// *W|elcome to AppFlowy Editor 🔥!
|
|
||||||
test('mock inputting a ` ` in the middle of the text', () async {
|
|
||||||
const text = 'Welcome to AppFlowy Editor 🔥!';
|
|
||||||
final document = Document.blank().addParagraphs(
|
|
||||||
1,
|
|
||||||
builder: (index) => Delta()..insert('*$text'),
|
|
||||||
);
|
|
||||||
final editorState = EditorState(document: document);
|
|
||||||
|
|
||||||
// *W|elcome to AppFlowy Editor 🔥!
|
|
||||||
final selection = Selection.collapsed(
|
|
||||||
Position(path: [0], offset: 2),
|
|
||||||
);
|
|
||||||
editorState.selection = selection;
|
|
||||||
final before = editorState.getNodesInSelection(selection).first;
|
|
||||||
final result = await formatAsteriskToBulletedList.execute(editorState);
|
|
||||||
final after = editorState.getNodesInSelection(selection).first;
|
|
||||||
|
|
||||||
// nothing happens
|
|
||||||
expect(result, false);
|
|
||||||
expect(before.toJson(), after.toJson());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Before
|
|
||||||
// Welcome to AppFlowy Editor 🔥!
|
|
||||||
// *|Welcome to AppFlowy Editor 🔥!
|
|
||||||
// After
|
|
||||||
// Welcome to AppFlowy Editor 🔥!
|
|
||||||
//[bulleted_list] Welcome to AppFlowy Editor 🔥!
|
|
||||||
test('mock inputting a ` ` in the middle of the text', () async {
|
|
||||||
const text = 'Welcome to AppFlowy Editor 🔥!';
|
|
||||||
final document = Document.blank()
|
|
||||||
.addParagraphs(
|
|
||||||
1,
|
|
||||||
builder: (index) => Delta()..insert(text),
|
|
||||||
)
|
|
||||||
.addParagraphs(
|
|
||||||
1,
|
|
||||||
builder: (index) => Delta()..insert('*$text'),
|
|
||||||
);
|
|
||||||
final editorState = EditorState(document: document);
|
|
||||||
|
|
||||||
// Welcome to AppFlowy Editor 🔥!
|
|
||||||
// *|Welcome to AppFlowy Editor 🔥!
|
|
||||||
final selection = Selection.collapsed(
|
|
||||||
Position(path: [1], offset: 1),
|
|
||||||
);
|
|
||||||
editorState.selection = selection;
|
|
||||||
final result = await formatAsteriskToBulletedList.execute(editorState);
|
|
||||||
final after = editorState.getNodeAtPath([1])!;
|
|
||||||
|
|
||||||
// the second line will be formatted as the bulleted list style
|
|
||||||
expect(result, true);
|
|
||||||
expect(after.type, 'bulleted_list');
|
|
||||||
expect(after.delta!.toPlainText(), text);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../../util/util.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
setUpAll(() {
|
||||||
|
if (kDebugMode) {
|
||||||
|
activateLog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDownAll(() {
|
||||||
|
if (kDebugMode) {
|
||||||
|
deactivateLog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
group('formatAsteriskToBulletedList', () {
|
||||||
|
// Before
|
||||||
|
// *|Welcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// [bulleted_list]Welcome to AppFlowy Editor 🔥!
|
||||||
|
test(
|
||||||
|
'mock inputting a ` ` after asterisk which is located at the front of the text',
|
||||||
|
() async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank().addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('*$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// *|Welcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [0], offset: 1),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final result = await formatAsteriskToBulletedList.execute(editorState);
|
||||||
|
|
||||||
|
expect(result, true);
|
||||||
|
final after = editorState.getNodeAtPath([0])!;
|
||||||
|
expect(after.delta!.toPlainText(), text);
|
||||||
|
expect(after.type, 'bulleted_list');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
// *W|elcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// *W|elcome to AppFlowy Editor 🔥!
|
||||||
|
test('mock inputting a ` ` in the middle of the text', () async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank().addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('*$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// *W|elcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [0], offset: 2),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final before = editorState.getNodesInSelection(selection).first;
|
||||||
|
final result = await formatAsteriskToBulletedList.execute(editorState);
|
||||||
|
final after = editorState.getNodesInSelection(selection).first;
|
||||||
|
|
||||||
|
// nothing happens
|
||||||
|
expect(result, false);
|
||||||
|
expect(before.toJson(), after.toJson());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
// *|Welcome to AppFlowy Editor 🔥!
|
||||||
|
// After
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
//[bulleted_list] Welcome to AppFlowy Editor 🔥!
|
||||||
|
test('mock inputting a ` ` in the middle of the text', () async {
|
||||||
|
const text = 'Welcome to AppFlowy Editor 🔥!';
|
||||||
|
final document = Document.blank()
|
||||||
|
.addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert(text),
|
||||||
|
)
|
||||||
|
.addParagraphs(
|
||||||
|
1,
|
||||||
|
builder: (index) => Delta()..insert('*$text'),
|
||||||
|
);
|
||||||
|
final editorState = EditorState(document: document);
|
||||||
|
|
||||||
|
// Welcome to AppFlowy Editor 🔥!
|
||||||
|
// *|Welcome to AppFlowy Editor 🔥!
|
||||||
|
final selection = Selection.collapsed(
|
||||||
|
Position(path: [1], offset: 1),
|
||||||
|
);
|
||||||
|
editorState.selection = selection;
|
||||||
|
final result = await formatAsteriskToBulletedList.execute(editorState);
|
||||||
|
final after = editorState.getNodeAtPath([1])!;
|
||||||
|
|
||||||
|
// the second line will be formatted as the bulleted list style
|
||||||
|
expect(result, true);
|
||||||
|
expect(after.type, 'bulleted_list');
|
||||||
|
expect(after.delta!.toPlainText(), text);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue