mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: link text is only displayed if all selected text satisfy linked style
This commit is contained in:
parent
44b4ef4ad7
commit
60a7557520
frontend/app_flowy/packages/appflowy_editor
lib/src
extensions
infra
render/toolbar
service
test/service/internal_key_event_handlers
@ -29,24 +29,34 @@ extension TextNodeExtension on TextNode {
|
||||
}
|
||||
|
||||
bool allSatisfyLinkInSelection(Selection selection) =>
|
||||
allSatisfyInSelection(StyleKey.href, null, selection);
|
||||
allSatisfyInSelection(StyleKey.href, selection, (value) {
|
||||
return value != null;
|
||||
});
|
||||
|
||||
bool allSatisfyBoldInSelection(Selection selection) =>
|
||||
allSatisfyInSelection(StyleKey.bold, true, selection);
|
||||
allSatisfyInSelection(StyleKey.bold, selection, (value) {
|
||||
return value == true;
|
||||
});
|
||||
|
||||
bool allSatisfyItalicInSelection(Selection selection) =>
|
||||
allSatisfyInSelection(StyleKey.italic, true, selection);
|
||||
allSatisfyInSelection(StyleKey.italic, selection, (value) {
|
||||
return value == true;
|
||||
});
|
||||
|
||||
bool allSatisfyUnderlineInSelection(Selection selection) =>
|
||||
allSatisfyInSelection(StyleKey.underline, true, selection);
|
||||
allSatisfyInSelection(StyleKey.underline, selection, (value) {
|
||||
return value == true;
|
||||
});
|
||||
|
||||
bool allSatisfyStrikethroughInSelection(Selection selection) =>
|
||||
allSatisfyInSelection(StyleKey.strikethrough, true, selection);
|
||||
allSatisfyInSelection(StyleKey.strikethrough, selection, (value) {
|
||||
return value == true;
|
||||
});
|
||||
|
||||
bool allSatisfyInSelection(
|
||||
String styleKey,
|
||||
dynamic value,
|
||||
Selection selection,
|
||||
bool Function(dynamic value) compare,
|
||||
) {
|
||||
final ops = delta.whereType<TextInsert>();
|
||||
final startOffset =
|
||||
@ -62,7 +72,7 @@ extension TextNodeExtension on TextNode {
|
||||
if (start < endOffset && start + length > startOffset) {
|
||||
if (op.attributes == null ||
|
||||
!op.attributes!.containsKey(styleKey) ||
|
||||
op.attributes![styleKey] != value) {
|
||||
!compare(op.attributes![styleKey])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -116,13 +126,15 @@ extension TextNodesExtension on List<TextNode> {
|
||||
bool allSatisfyInSelection(
|
||||
String styleKey,
|
||||
Selection selection,
|
||||
dynamic value,
|
||||
dynamic matchValue,
|
||||
) {
|
||||
if (isEmpty) {
|
||||
return false;
|
||||
}
|
||||
if (length == 1) {
|
||||
return first.allSatisfyInSelection(styleKey, value, selection);
|
||||
return first.allSatisfyInSelection(styleKey, selection, (value) {
|
||||
return value == matchValue;
|
||||
});
|
||||
} else {
|
||||
for (var i = 0; i < length; i++) {
|
||||
final node = this[i];
|
||||
@ -142,7 +154,9 @@ extension TextNodesExtension on List<TextNode> {
|
||||
end: Position(path: node.path, offset: node.toRawString().length),
|
||||
);
|
||||
}
|
||||
if (!node.allSatisfyInSelection(styleKey, value, newSelection)) {
|
||||
if (!node.allSatisfyInSelection(styleKey, newSelection, (value) {
|
||||
return value == matchValue;
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ class Log {
|
||||
/// For example, uses the logger when processing scroll events.
|
||||
static Log scroll = Log._(name: 'scroll');
|
||||
|
||||
/// For logging message related to [AppFlowyToolbarService].
|
||||
///
|
||||
/// For example, uses the logger when processing toolbar events.
|
||||
static Log toolbar = Log._(name: 'toolbar');
|
||||
|
||||
/// For logging message related to UI.
|
||||
///
|
||||
/// For example, uses the logger when building the widget.
|
||||
|
@ -181,7 +181,12 @@ void _showLinkMenu(EditorState editorState, BuildContext context) {
|
||||
final length = (selection.start.offset - selection.end.offset).abs();
|
||||
final node = editorState.service.selectionService.currentSelectedNodes.first
|
||||
as TextNode;
|
||||
final linkText = node.getAttributeInSelection(selection, StyleKey.href);
|
||||
final String linkText;
|
||||
if (node.allSatisfyLinkInSelection(selection)) {
|
||||
linkText = node.getAttributeInSelection(selection, StyleKey.href);
|
||||
} else {
|
||||
linkText = '';
|
||||
}
|
||||
_linkMenuOverlay = OverlayEntry(builder: (context) {
|
||||
return Positioned(
|
||||
top: matchRect.bottom + 5.0,
|
||||
|
@ -36,10 +36,10 @@ class FlowyService {
|
||||
|
||||
// toolbar service
|
||||
final toolbarServiceKey = GlobalKey(debugLabel: 'flowy_toolbar_service');
|
||||
FlowyToolbarService? get toolbarService {
|
||||
AppFlowyToolbarService? get toolbarService {
|
||||
if (toolbarServiceKey.currentState != null &&
|
||||
toolbarServiceKey.currentState is FlowyToolbarService) {
|
||||
return toolbarServiceKey.currentState! as FlowyToolbarService;
|
||||
toolbarServiceKey.currentState is AppFlowyToolbarService) {
|
||||
return toolbarServiceKey.currentState! as AppFlowyToolbarService;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
|
||||
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
||||
|
||||
abstract class FlowyToolbarService {
|
||||
abstract class AppFlowyToolbarService {
|
||||
/// Show the toolbar widget beside the offset.
|
||||
void showInOffset(Offset offset, LayerLink layerLink);
|
||||
|
||||
@ -31,7 +31,7 @@ class FlowyToolbar extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _FlowyToolbarState extends State<FlowyToolbar>
|
||||
implements FlowyToolbarService {
|
||||
implements AppFlowyToolbarService {
|
||||
OverlayEntry? _toolbarOverlay;
|
||||
final _toolbarWidgetKey = GlobalKey(debugLabel: '_toolbar_widget');
|
||||
|
||||
|
@ -82,7 +82,14 @@ Future<void> _testUpdateTextStyleByCommandX(
|
||||
);
|
||||
var textNode = editor.nodeAtPath([1]) as TextNode;
|
||||
expect(
|
||||
textNode.allSatisfyInSelection(matchStyle, matchValue, selection), true);
|
||||
textNode.allSatisfyInSelection(
|
||||
matchStyle,
|
||||
selection,
|
||||
(value) {
|
||||
return value == matchValue;
|
||||
},
|
||||
),
|
||||
true);
|
||||
|
||||
selection =
|
||||
Selection.single(path: [1], startOffset: 0, endOffset: text.length);
|
||||
@ -94,7 +101,14 @@ Future<void> _testUpdateTextStyleByCommandX(
|
||||
);
|
||||
textNode = editor.nodeAtPath([1]) as TextNode;
|
||||
expect(
|
||||
textNode.allSatisfyInSelection(matchStyle, matchValue, selection), true);
|
||||
textNode.allSatisfyInSelection(
|
||||
matchStyle,
|
||||
selection,
|
||||
(value) {
|
||||
return value == matchValue;
|
||||
},
|
||||
),
|
||||
true);
|
||||
|
||||
await editor.updateSelection(selection);
|
||||
await editor.pressLogicKey(
|
||||
@ -123,9 +137,14 @@ Future<void> _testUpdateTextStyleByCommandX(
|
||||
expect(
|
||||
node.allSatisfyInSelection(
|
||||
matchStyle,
|
||||
matchValue,
|
||||
Selection.single(
|
||||
path: node.path, startOffset: 0, endOffset: text.length),
|
||||
path: node.path,
|
||||
startOffset: 0,
|
||||
endOffset: text.length,
|
||||
),
|
||||
(value) {
|
||||
return value == matchValue;
|
||||
},
|
||||
),
|
||||
true,
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user