mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: workaround infinity formatting
This commit is contained in:
parent
c0964fad5d
commit
6a902a2b21
@ -37,6 +37,7 @@ class BuiltInAttributeKey {
|
||||
static String checkbox = 'checkbox';
|
||||
static String code = 'code';
|
||||
static String number = 'number';
|
||||
static String defaultFormating = 'defaultFormating';
|
||||
|
||||
static List<String> partialStyleKeys = [
|
||||
BuiltInAttributeKey.bold,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/document/attributes.dart';
|
||||
import 'package:appflowy_editor/src/document/node.dart';
|
||||
import 'package:appflowy_editor/src/document/path.dart';
|
||||
@ -114,21 +115,17 @@ class TransactionBuilder {
|
||||
|
||||
/// Inserts content at a specified index.
|
||||
/// Optionally, you may specify formatting attributes that are applied to the inserted string.
|
||||
/// By default, the formatting attributes before the insert position will be used.
|
||||
/// When no formatting attributes specified, the formating attributes before the insert position will be used if they don't have defaultFormatting flag set
|
||||
/// When defaultFormatting flag is set before the insert position, it will be cleared.
|
||||
/// When insert position is within a text having defaultFormatting flag set, the flag will be ignored and clear (formatting attributes of the text will be applied)
|
||||
insertText(
|
||||
TextNode node,
|
||||
int index,
|
||||
String content, {
|
||||
Attributes? attributes,
|
||||
}) {
|
||||
var newAttributes = attributes;
|
||||
if (index != 0 && attributes == null) {
|
||||
newAttributes =
|
||||
node.delta.slice(max(index - 1, 0), index).first.attributes;
|
||||
if (newAttributes != null) {
|
||||
newAttributes = Attributes.from(newAttributes);
|
||||
}
|
||||
}
|
||||
final newAttributes = attributes ?? _getAttributesAt(node, index);
|
||||
|
||||
textEdit(
|
||||
node,
|
||||
() => Delta()
|
||||
@ -227,4 +224,38 @@ class TransactionBuilder {
|
||||
afterSelection: afterSelection,
|
||||
);
|
||||
}
|
||||
|
||||
Attributes? _getAttributesAt(TextNode node, int index) {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final previousAttributes =
|
||||
node.delta.slice(index - 1, index).first.attributes;
|
||||
|
||||
final nextAttributes = node.delta.length > index
|
||||
? node.delta.slice(index, index + 1).first.attributes
|
||||
: null;
|
||||
|
||||
if (previousAttributes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (previousAttributes.containsKey(BuiltInAttributeKey.defaultFormating)) {
|
||||
Attributes newAttributes = Map.from(previousAttributes)
|
||||
..removeWhere((key, _) => key == BuiltInAttributeKey.defaultFormating);
|
||||
|
||||
if (node.previous != null) {
|
||||
updateNode(node.next!, newAttributes);
|
||||
if (previousAttributes == nextAttributes) {
|
||||
updateNode(node.next!, newAttributes);
|
||||
return newAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return Attributes.from(previousAttributes);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/extensions/path_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// convert **abc** to bold abc.
|
||||
@ -51,6 +52,7 @@ ShortcutEventHandler doubleAsterisksToBold = (editorState, event) {
|
||||
selection.end.offset - thirdToLastAsteriskIndex - 2,
|
||||
{
|
||||
BuiltInAttributeKey.bold: true,
|
||||
BuiltInAttributeKey.defaultFormating: true,
|
||||
},
|
||||
)
|
||||
..afterSelection = Selection.collapsed(
|
||||
@ -116,6 +118,7 @@ ShortcutEventHandler doubleUnderscoresToBold = (editorState, event) {
|
||||
selection.end.offset - thirdToLastUnderscoreIndex - 2,
|
||||
{
|
||||
BuiltInAttributeKey.bold: true,
|
||||
BuiltInAttributeKey.defaultFormating: true,
|
||||
},
|
||||
)
|
||||
..afterSelection = Selection.collapsed(
|
||||
@ -125,7 +128,6 @@ ShortcutEventHandler doubleUnderscoresToBold = (editorState, event) {
|
||||
),
|
||||
)
|
||||
..commit();
|
||||
editorState.editorStyle == EditorStyle.defaultStyle();
|
||||
|
||||
return KeyEventResult.handled;
|
||||
};
|
||||
|
@ -143,7 +143,7 @@ extension on LogicalKeyboardKey {
|
||||
return PhysicalKeyboardKey.digit8;
|
||||
}
|
||||
if (this == LogicalKeyboardKey.underscore) {
|
||||
return PhysicalKeyboardKey.minus gg;
|
||||
return PhysicalKeyboardKey.minus;
|
||||
}
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
@ -92,6 +92,45 @@ void main() async {
|
||||
expect(textNode.toRawString(), '*AppFlowy');
|
||||
});
|
||||
|
||||
testWidgets('**AppFlowy** application to bold AppFlowy only',
|
||||
(tester) async {
|
||||
const boldText = '**AppFlowy*';
|
||||
const normalText = ' application';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
|
||||
for (var i = 0; i < boldText.length; i++) {
|
||||
await editor.insertText(textNode, boldText[i], i);
|
||||
}
|
||||
await insertAsterisk(editor);
|
||||
for (var i = 0; i < normalText.length; i++) {
|
||||
await editor.insertText(
|
||||
textNode, normalText[i], i + boldText.length - 3);
|
||||
}
|
||||
final boldTextLength = boldText.replaceAll('*', '').length;
|
||||
final appFlowyBold = textNode.allSatisfyBoldInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: boldTextLength,
|
||||
),
|
||||
);
|
||||
final applicationNormal = textNode.allSatisfyBoldInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: boldTextLength,
|
||||
endOffset: textNode.toRawString().length,
|
||||
),
|
||||
);
|
||||
expect(appFlowyBold, true);
|
||||
expect(applicationNormal, false);
|
||||
expect(textNode.toRawString(), 'AppFlowy application');
|
||||
});
|
||||
|
||||
testWidgets('**** nothing changes', (tester) async {
|
||||
const text = '***';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
@ -198,6 +237,45 @@ void main() async {
|
||||
expect(textNode.toRawString(), '_AppFlowy');
|
||||
});
|
||||
|
||||
testWidgets('__AppFlowy__ application to bold AppFlowy only',
|
||||
(tester) async {
|
||||
const boldText = '__AppFlowy_';
|
||||
const normalText = ' application';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
|
||||
for (var i = 0; i < boldText.length; i++) {
|
||||
await editor.insertText(textNode, boldText[i], i);
|
||||
}
|
||||
await insertUnderscore(editor);
|
||||
for (var i = 0; i < normalText.length; i++) {
|
||||
await editor.insertText(
|
||||
textNode, normalText[i], i + boldText.length - 3);
|
||||
}
|
||||
final boldTextLength = boldText.replaceAll('_', '').length;
|
||||
final appFlowyBold = textNode.allSatisfyBoldInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: boldTextLength,
|
||||
),
|
||||
);
|
||||
final applicationNormal = textNode.allSatisfyBoldInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: boldTextLength,
|
||||
endOffset: textNode.toRawString().length,
|
||||
),
|
||||
);
|
||||
expect(appFlowyBold, true);
|
||||
expect(applicationNormal, false);
|
||||
expect(textNode.toRawString(), 'AppFlowy application');
|
||||
});
|
||||
|
||||
testWidgets('____ nothing changes', (tester) async {
|
||||
const text = '___';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
|
Loading…
Reference in New Issue
Block a user