mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: could not insert link on the Web
This commit is contained in:
parent
ab0131c19c
commit
99cb2430f7
@ -3,29 +3,25 @@ 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/node.dart';
|
||||
import 'package:appflowy_editor/src/document/path.dart';
|
||||
import 'package:appflowy_editor/src/document/selection.dart';
|
||||
import 'package:appflowy_editor/src/editor_state.dart';
|
||||
|
||||
Future<void> formatBuiltInTextAttributes(
|
||||
EditorState editorState,
|
||||
String key,
|
||||
Attributes attributes, {
|
||||
Selection? selection,
|
||||
Path? path,
|
||||
TextNode? textNode,
|
||||
}) async {
|
||||
final result = getTextNodeToBeFormatted(
|
||||
editorState,
|
||||
path: path,
|
||||
textNode: textNode,
|
||||
);
|
||||
if (BuiltInAttributeKey.globalStyleKeys.contains(key)) {
|
||||
assert(!(path != null && textNode != null));
|
||||
assert(!(path == null && textNode == null));
|
||||
|
||||
TextNode formattedTextNode;
|
||||
if (textNode != null) {
|
||||
formattedTextNode = textNode;
|
||||
} else if (path != null) {
|
||||
formattedTextNode = editorState.document.nodeAtPath(path) as TextNode;
|
||||
} else {
|
||||
throw Exception('path and textNode cannot be null at the same time');
|
||||
}
|
||||
// remove all the existing style
|
||||
final newAttributes = formattedTextNode.attributes
|
||||
final newAttributes = result.attributes
|
||||
..removeWhere((key, value) {
|
||||
if (BuiltInAttributeKey.globalStyleKeys.contains(key)) {
|
||||
return true;
|
||||
@ -41,6 +37,13 @@ Future<void> formatBuiltInTextAttributes(
|
||||
newAttributes,
|
||||
textNode: textNode,
|
||||
);
|
||||
} else if (BuiltInAttributeKey.partialStyleKeys.contains(key)) {
|
||||
return updateTextNodeDeltaAttributes(
|
||||
editorState,
|
||||
selection,
|
||||
attributes,
|
||||
textNode: textNode,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,3 +63,20 @@ Future<void> formatTextToCheckbox(
|
||||
textNode: textNode,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> formatLinkInText(
|
||||
EditorState editorState,
|
||||
String? link, {
|
||||
Path? path,
|
||||
TextNode? textNode,
|
||||
}) async {
|
||||
return formatBuiltInTextAttributes(
|
||||
editorState,
|
||||
BuiltInAttributeKey.href,
|
||||
{
|
||||
BuiltInAttributeKey.href: link,
|
||||
},
|
||||
path: path,
|
||||
textNode: textNode,
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy_editor/src/document/attributes.dart';
|
||||
import 'package:appflowy_editor/src/document/node.dart';
|
||||
import 'package:appflowy_editor/src/document/path.dart';
|
||||
import 'package:appflowy_editor/src/document/selection.dart';
|
||||
import 'package:appflowy_editor/src/editor_state.dart';
|
||||
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -11,24 +14,90 @@ Future<void> updateTextNodeAttributes(
|
||||
Path? path,
|
||||
TextNode? textNode,
|
||||
}) async {
|
||||
assert(!(path != null && textNode != null));
|
||||
assert(!(path == null && textNode == null));
|
||||
final result = getTextNodeToBeFormatted(
|
||||
editorState,
|
||||
path: path,
|
||||
textNode: textNode,
|
||||
);
|
||||
|
||||
TextNode formattedTextNode;
|
||||
if (textNode != null) {
|
||||
formattedTextNode = textNode;
|
||||
} else if (path != null) {
|
||||
formattedTextNode = editorState.document.nodeAtPath(path) as TextNode;
|
||||
} else {
|
||||
throw Exception('path and textNode cannot be null at the same time');
|
||||
}
|
||||
final completer = Completer<void>();
|
||||
|
||||
TransactionBuilder(editorState)
|
||||
..updateNode(formattedTextNode, attributes)
|
||||
..updateNode(result, attributes)
|
||||
..commit();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
print('AAAAAAAAAAAAAA');
|
||||
return;
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<void> updateTextNodeDeltaAttributes(
|
||||
EditorState editorState,
|
||||
Selection? selection,
|
||||
Attributes attributes, {
|
||||
Path? path,
|
||||
TextNode? textNode,
|
||||
}) {
|
||||
final result = getTextNodeToBeFormatted(
|
||||
editorState,
|
||||
path: path,
|
||||
textNode: textNode,
|
||||
);
|
||||
final newSelection = _getSelection(editorState, selection: selection);
|
||||
|
||||
final completer = Completer<void>();
|
||||
|
||||
TransactionBuilder(editorState)
|
||||
..formatText(
|
||||
result,
|
||||
newSelection.startIndex,
|
||||
newSelection.length,
|
||||
attributes,
|
||||
)
|
||||
..commit();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
// get formatted [TextNode]
|
||||
TextNode getTextNodeToBeFormatted(
|
||||
EditorState editorState, {
|
||||
Path? path,
|
||||
TextNode? textNode,
|
||||
}) {
|
||||
assert(!(path != null && textNode != null));
|
||||
assert(!(path == null && textNode == null));
|
||||
|
||||
TextNode result;
|
||||
if (textNode != null) {
|
||||
result = textNode;
|
||||
} else if (path != null) {
|
||||
result = editorState.document.nodeAtPath(path) as TextNode;
|
||||
} else {
|
||||
throw Exception('path and textNode cannot be null at the same time');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Selection _getSelection(
|
||||
EditorState editorState, {
|
||||
Selection? selection,
|
||||
}) {
|
||||
final currentSelection =
|
||||
editorState.service.selectionService.currentSelection.value;
|
||||
Selection result;
|
||||
if (selection != null) {
|
||||
result = selection;
|
||||
} else if (currentSelection != null) {
|
||||
result = currentSelection;
|
||||
} else {
|
||||
throw Exception('path and textNode cannot be null at the same time');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -53,6 +53,10 @@ class Selection {
|
||||
|
||||
Selection get reversed => copyWith(start: end, end: start);
|
||||
|
||||
int get startIndex => normalize.start.offset;
|
||||
int get endIndex => normalize.end.offset;
|
||||
int get length => endIndex - startIndex;
|
||||
|
||||
Selection collapse({bool atStart = false}) {
|
||||
if (atStart) {
|
||||
return Selection(start: start, end: start);
|
||||
|
@ -74,8 +74,8 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
|
||||
padding: iconPadding,
|
||||
name: check ? 'check' : 'uncheck',
|
||||
),
|
||||
onTap: () {
|
||||
formatTextToCheckbox(
|
||||
onTap: () async {
|
||||
await formatTextToCheckbox(
|
||||
widget.editorState,
|
||||
!check,
|
||||
textNode: widget.textNode,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/commands/format_built_in_text.dart';
|
||||
import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';
|
||||
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||
import 'package:appflowy_editor/src/render/link_menu/link_menu.dart';
|
||||
@ -345,11 +346,8 @@ void showLinkMenu(
|
||||
onOpenLink: () async {
|
||||
await safeLaunchUrl(linkText);
|
||||
},
|
||||
onSubmitted: (text) {
|
||||
TransactionBuilder(editorState)
|
||||
..formatText(
|
||||
textNode, index, length, {BuiltInAttributeKey.href: text})
|
||||
..commit();
|
||||
onSubmitted: (text) async {
|
||||
await formatLinkInText(editorState, text, textNode: textNode);
|
||||
_dismissLinkMenu();
|
||||
},
|
||||
onCopyLink: () {
|
||||
@ -377,6 +375,7 @@ void showLinkMenu(
|
||||
Overlay.of(context)?.insert(_linkMenuOverlay!);
|
||||
|
||||
editorState.service.scrollService?.disable();
|
||||
editorState.service.keyboardService?.disable();
|
||||
editorState.service.selectionService.currentSelection
|
||||
.addListener(_dismissLinkMenu);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user