mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
doc: Editorial updates to the ReadMe for AppFlowyEditor (#900)
docs: Editorial updates to the ReadMe for AppFlowyEditor
This commit is contained in:
parent
1b9f096e5a
commit
9a01f90aee
@ -26,21 +26,27 @@ and the Flutter guide for
|
|||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
* Allow you to build rich, intuitive editors
|
* Build rich, intuitive editors
|
||||||
* Design and modify it your way by customizing components, shortcut events, and many more coming soon including menu options and themes
|
* Design and modify an ever expanding list of customizable features including
|
||||||
* [Test-covered](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/testing.md) and maintained by AppFlowy's core team along with a community of more than 1,000 builders
|
* components (such as form input controls, numbered lists, and rich text widgets)
|
||||||
|
* shortcut events
|
||||||
|
* menu options (**coming soon!**)
|
||||||
|
* themes (**coming soon!**)
|
||||||
|
* [Test-coverage](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/testing.md) and on-going maintenance by AppFlowy's core team and community of more than 1,000 builders
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
## Getting started
|
Add the AppFlowy editor [Flutter package](https://docs.flutter.dev/development/packages-and-plugins/using-packages) to your environment.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
flutter pub add appflowy_editor
|
flutter pub add appflowy_editor
|
||||||
flutter pub get
|
flutter pub get
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to use
|
## Creating Your First Editor
|
||||||
|
|
||||||
|
Start by creating a new empty AppFlowyEditor object.
|
||||||
|
|
||||||
Let's create a new AppFlowyEditor object
|
|
||||||
```dart
|
```dart
|
||||||
final editorState = EditorState.empty(); // an empty state
|
final editorState = EditorState.empty(); // an empty state
|
||||||
final editor = AppFlowyEditor(
|
final editor = AppFlowyEditor(
|
||||||
@ -50,7 +56,8 @@ final editor = AppFlowyEditor(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also create an editor from a JSON file
|
You can also create an editor from a JSON object in order to configure your initial state.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final json = ...;
|
final json = ...;
|
||||||
final editorState = EditorState(StateTree.fromJson(data));
|
final editorState = EditorState(StateTree.fromJson(data));
|
||||||
@ -61,37 +68,43 @@ final editor = AppFlowyEditor(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
To get a sense for how you might use it, run this example:
|
To get a sense for how the AppFlowy Editor works, run our example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/AppFlowy-IO/AppFlowy.git
|
git clone https://github.com/AppFlowy-IO/AppFlowy.git
|
||||||
cd frontend/app_flowy/packages/appflowy_editor/example
|
cd frontend/app_flowy/packages/appflowy_editor/example
|
||||||
flutter run
|
flutter run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Customizing Your Editor
|
||||||
|
|
||||||
## How to customize
|
### Customizing Components
|
||||||
### Customize a component
|
|
||||||
Please refer to [customizing a component](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-component) for more details.
|
|
||||||
|
|
||||||
|
Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing components](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-component).
|
||||||
|
|
||||||
### Customize a shortcut event
|
Below are some examples of component customizations:
|
||||||
Please refer to [customizing a shortcut event](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-shortcut-event) for more details.
|
|
||||||
|
|
||||||
## More Examples
|
* [Checkbox Text](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/checkbox_text.dart) demonstrates how to extend new styles based on existing rich text components
|
||||||
* Customize a component
|
* [Image](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) demonstrates how to extend a new node and render it
|
||||||
* [Checkbox Text](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/checkbox_text.dart) shows you how to extend new styles based on existing rich text components
|
* See further examples of [rich-text plugins](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text)
|
||||||
* [Image](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) teaches you how to extend a new node and render it
|
|
||||||
* And more examples on [rich-text plugins](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text)
|
### Customizing Shortcut Events
|
||||||
* Customize a shortcut event
|
|
||||||
* [BIUS](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart) shows you how to make text bold/italic/underline/strikethrough through shortcut keys
|
Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing shortcut events](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-shortcut-event).
|
||||||
* [Paste HTML](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart) gives you an idea on how to handle pasted styles through shortcut keys
|
|
||||||
* Need more examples? Check out [Internal key event handlers](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers)
|
Below are some examples of shortcut event customizations:
|
||||||
|
|
||||||
|
* [BIUS](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart) demonstrates how to make text bold/italic/underline/strikethrough through shortcut keys
|
||||||
|
* [Paste HTML](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart) gives you an idea on how to handle pasted styles through shortcut keys
|
||||||
|
* Need more examples? Check out [Internal key event handlers](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers)
|
||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
Please refer to the API documentation.
|
Please refer to the API documentation.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated. Please look at [CONTRIBUTING.md](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy) for details.
|
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
|
||||||
|
|
||||||
|
Please look at [CONTRIBUTING.md](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy) for details.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Distributed under the AGPLv3 License. See LICENSE for more information.
|
Distributed under the AGPLv3 License. See [LICENSE](https://github.com/AppFlowy-IO/AppFlowy-Docs/blob/main/LICENSE) for more information.
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# How to customize ...
|
# Customizing Editor Features
|
||||||
|
|
||||||
## Customize a shortcut event
|
## Customizing a Shortcut Event
|
||||||
|
|
||||||
We will use a simple example to illustrate how to quickly add a shortcut event.
|
We will use a simple example to illustrate how to quickly add a shortcut event.
|
||||||
|
|
||||||
For example, typing `_xxx_` will be converted into _xxx_.
|
In this example, text that starts and ends with an underscore ( \_ ) character will be rendered in italics for emphasis. So typing `_xxx_` will automatically be converted into _xxx_.
|
||||||
|
|
||||||
Let's start with a blank document.
|
Let's start with a blank document:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
@ -27,7 +27,7 @@ At this point, nothing magic will happen after typing `_xxx_`.
|
|||||||
|
|
||||||
![Before](./images/customizing_a_shortcut_event_before.gif)
|
![Before](./images/customizing_a_shortcut_event_before.gif)
|
||||||
|
|
||||||
Next, we will create a function to handle an underscore input.
|
To implement our shortcut event we will create a function to handle an underscore input.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
@ -35,23 +35,25 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
||||||
// Since we only need to handler the input of `underscore`.
|
// Since we only need to handle the input of an 'underscore' character,
|
||||||
// All inputs except `underscore` will be ignored directly.
|
// all inputs except `underscore` will be ignored immediately.
|
||||||
if (event.logicalKey != LogicalKeyboardKey.underscore) {
|
if (event.logicalKey != LogicalKeyboardKey.underscore) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, we need to determine if the currently selected node is `TextNode` and the selection is collapsed.
|
Then, we need to determine if the currently selected node is a `TextNode` and if the selection is collapsed.
|
||||||
|
|
||||||
|
If so, we will continue.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// ...
|
// ...
|
||||||
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
// Obtaining the selection and selected nodes of the current document through `selectionService`.
|
// Obtain the selection and selected nodes of the current document through the 'selectionService'
|
||||||
// And determine whether the selection is collapsed and whether the selected node is a text node.
|
// to determine whether the selection is collapsed and whether the selected node is a text node.
|
||||||
final selectionService = editorState.service.selectionService;
|
final selectionService = editorState.service.selectionService;
|
||||||
final selection = selectionService.currentSelection.value;
|
final selection = selectionService.currentSelection.value;
|
||||||
final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
|
final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
|
||||||
@ -60,11 +62,11 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, we start dealing with underscore.
|
Now, we deal with handling the underscore.
|
||||||
|
|
||||||
Look for the position of the previous underscore and
|
Look for the position of the previous underscore and
|
||||||
1. return, if not found.
|
1. if one is _not_ found, return without doing anything.
|
||||||
2. if found, the text wrapped in between two underscores will be displayed in italic.
|
2. if one is found, the text enclosed within the two underscores will be formatted to display in italics.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// ...
|
// ...
|
||||||
@ -73,14 +75,14 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
|||||||
|
|
||||||
final textNode = textNodes.first;
|
final textNode = textNodes.first;
|
||||||
final text = textNode.toRawString();
|
final text = textNode.toRawString();
|
||||||
// Determine if `underscore` already exists in the text node
|
// Determine if an 'underscore' already exists in the text node
|
||||||
final previousUnderscore = text.indexOf('_');
|
final previousUnderscore = text.indexOf('_');
|
||||||
if (previousUnderscore == -1) {
|
if (previousUnderscore == -1) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the previous `underscore`,
|
// Delete the previous 'underscore',
|
||||||
// update the style of the text surrounded by two underscores to `italic`,
|
// update the style of the text surrounded by the two underscores to 'italic',
|
||||||
// and update the cursor position.
|
// and update the cursor position.
|
||||||
TransactionBuilder(editorState)
|
TransactionBuilder(editorState)
|
||||||
..deleteText(textNode, previousUnderscore, 1)
|
..deleteText(textNode, previousUnderscore, 1)
|
||||||
@ -99,7 +101,7 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
So far, the 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.
|
Now our 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
@ -120,14 +122,15 @@ Widget build(BuildContext context) {
|
|||||||
|
|
||||||
![After](./images/customizing_a_shortcut_event_after.gif)
|
![After](./images/customizing_a_shortcut_event_after.gif)
|
||||||
|
|
||||||
[Complete code example]()
|
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart) file of this example.
|
||||||
|
|
||||||
## Customize a component
|
|
||||||
We will use a simple example to showcase how to quickly add a custom component.
|
|
||||||
|
|
||||||
For example, we want to render an image from the network.
|
## Customizing a Component
|
||||||
|
We will use a simple example to show how to quickly add a custom component.
|
||||||
|
|
||||||
To start with, let's create an empty document by running commands as follows:
|
In this example we will render an image from the network.
|
||||||
|
|
||||||
|
Let's start with a blank document:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
@ -144,9 +147,9 @@ Widget build(BuildContext context) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, we choose a unique string for your custom node's type. We use `network_image` in this case. And we add `network_image_src` to the `attributes` to describe the link of the image.
|
Next, we will choose a unique string for your custom node's type.
|
||||||
|
|
||||||
> For the definition of the [Node](), please refer to this [link]().
|
We'll use `network_image` in this case. And we add `network_image_src` to the `attributes` to describe the link of the image.
|
||||||
|
|
||||||
```JSON
|
```JSON
|
||||||
{
|
{
|
||||||
@ -157,9 +160,9 @@ Next, we choose a unique string for your custom node's type. We use `network_ima
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, we create a class that inherits [NodeWidgetBuilder](). As shown in the autoprompt, we need to implement two functions:
|
Then, we create a class that inherits [NodeWidgetBuilder](../lib/src/service/render_plugin_service.dart). As shown in the autoprompt, we need to implement two functions:
|
||||||
1. one returns a widget
|
1. one returns a widget
|
||||||
2. the other verifies the correctness of the [Node]().
|
2. the other verifies the correctness of the [Node](../lib/src/document/node.dart).
|
||||||
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@ -179,9 +182,7 @@ class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
|
|||||||
|
|
||||||
Now, let's implement a simple image widget based on `Image`.
|
Now, let's implement a simple image widget based on `Image`.
|
||||||
|
|
||||||
**It is important to note that the `State` of the returned `Widget` must be with [Selectable]().**
|
Note that the `State` object that is returned by the `Widget` must implement [Selectable](../lib/src/render/selection/selectable.dart) using the `with` keyword.
|
||||||
|
|
||||||
> For the definition of the [Selectable](), please refer to this [link]().
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
class _NetworkImageNodeWidget extends StatefulWidget {
|
class _NetworkImageNodeWidget extends StatefulWidget {
|
||||||
@ -236,7 +237,7 @@ class __NetworkImageNodeWidgetState extends State<_NetworkImageNodeWidget>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, we return `_NetworkImageNodeWidget` in the `build` function of `NetworkImageNodeWidgetBuilder` and register `NetworkImageNodeWidgetBuilder` into `AppFlowyEditor`.
|
Finally, we return `_NetworkImageNodeWidget` in the `build` function of `NetworkImageNodeWidgetBuilder`...
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
|
class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
|
||||||
@ -256,6 +257,8 @@ class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
... and register `NetworkImageNodeWidgetBuilder` in the `AppFlowyEditor`.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final editorState = EditorState(
|
final editorState = EditorState(
|
||||||
document: StateTree.empty()
|
document: StateTree.empty()
|
||||||
@ -281,6 +284,6 @@ return AppFlowyEditor(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
![](./images/customizing_a_component.gif)
|
![Whew!](./images/customizing_a_component.gif)
|
||||||
|
|
||||||
[Here you can check out the complete code file of this example]()
|
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) file of this example.
|
||||||
|
@ -1,24 +1,33 @@
|
|||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
> The directory structure of test files is consistent with the code files, making it easy for us to map a file with the corresponding test and check if the test is updated
|
The directory structure of test files mirrors that of the code files, making it easy for us to map a file with the corresponding test and check if the test is updated.
|
||||||
|
|
||||||
## Testing Functions
|
For an overview of testing best practices in Flutter applications, please refer to Flutter's [introduction to widget testing](https://docs.flutter.dev/cookbook/testing/widget/introduction) as well as their [introduction to unit testing](https://docs.flutter.dev/cookbook/testing/unit/introduction).
|
||||||
|
There you will learn how to do such things as such as simulate a click as well as leverage the `test` and `expect` functions.
|
||||||
|
|
||||||
|
## Testing Basic Editor Functions
|
||||||
|
|
||||||
|
The example code below shows how to construct a document that will be used in our testing.
|
||||||
|
|
||||||
**Construct a document for testing**
|
|
||||||
```dart
|
```dart
|
||||||
const text = 'Welcome to Appflowy 😁';
|
const text = 'Welcome to Appflowy 😁';
|
||||||
// Get the instance of editor.
|
// Get the instance of the editor.
|
||||||
final editor = tester.editor;
|
final editor = tester.editor;
|
||||||
// Insert empty text node.
|
|
||||||
|
// Insert an empty text node.
|
||||||
editor.insertEmptyTextNode();
|
editor.insertEmptyTextNode();
|
||||||
// Insert text node with string.
|
|
||||||
|
// Insert a text node with the text string we defined earlier.
|
||||||
editor.insertTextNode(text);
|
editor.insertTextNode(text);
|
||||||
// Insert text node with heading style.
|
|
||||||
|
// Insert the same text, but with the heading style.
|
||||||
editor.insertTextNode(text, attributes: {
|
editor.insertTextNode(text, attributes: {
|
||||||
StyleKey.subtype: StyleKey.heading,
|
StyleKey.subtype: StyleKey.heading,
|
||||||
StyleKey.heading: StyleKey.h1,
|
StyleKey.heading: StyleKey.h1,
|
||||||
});
|
});
|
||||||
// Insert text node with bulleted list style and bold style.
|
|
||||||
|
// Insert our text with the bulleted list style and the bold style.
|
||||||
|
// If you want to modify the style of the inserted text, you need to use the Delta parameter.
|
||||||
editor.insertTextNode(
|
editor.insertTextNode(
|
||||||
'',
|
'',
|
||||||
attributes: {
|
attributes: {
|
||||||
@ -30,40 +39,46 @@ editor.insertTextNode(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
**The `startTesting` function must be called before testing**.
|
The `startTesting` function of the editor must be called before you begin your test.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
await editor.startTesting();
|
await editor.startTesting();
|
||||||
```
|
```
|
||||||
|
|
||||||
**Get the number of nodes in the document**
|
Get the number of nodes in the document.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final length = editor.documentLength;
|
final length = editor.documentLength;
|
||||||
print(length);
|
print(length);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Get the node of a defined path**
|
Get the node of a defined path. In this case we are getting the first node of the document which is the text "Welcome to Appflowy 😁".
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final firstTextNode = editor.nodeAtPath([0]) as TextNode;
|
final firstTextNode = editor.nodeAtPath([0]) as TextNode;
|
||||||
```
|
```
|
||||||
|
|
||||||
**Update selection**
|
Update the [Selection](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/document/selection.dart) so that our text "Welcome to Appflowy 😁" is selected. We will start our selection from the beginning of the string.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
await editor.updateSelection(
|
await editor.updateSelection(
|
||||||
Selection.single(path: firstTextNode.path, startOffset: 0),
|
Selection.single(path: firstTextNode.path, startOffset: 0),
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Get the selection**
|
Get the current selection.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final selection = editor.documentSelection;
|
final selection = editor.documentSelection;
|
||||||
print(selection);
|
print(selection);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Simulate shortcut event inputs**
|
Next we will simulate the input of a shortcut key being pressed that will select all the text.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// Command + A.
|
// Meta + A.
|
||||||
await editor.pressLogicKey(LogicalKeyboardKey.keyA, isMetaPressed: true);
|
await editor.pressLogicKey(LogicalKeyboardKey.keyA, isMetaPressed: true);
|
||||||
// Command + shift + S.
|
// Meta + shift + S.
|
||||||
await editor.pressLogicKey(
|
await editor.pressLogicKey(
|
||||||
LogicalKeyboardKey.keyS,
|
LogicalKeyboardKey.keyS,
|
||||||
isMetaPressed: true,
|
isMetaPressed: true,
|
||||||
@ -71,25 +86,29 @@ await editor.pressLogicKey(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Simulate a text input**
|
We will then simulate text input.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// Insert 'Hello World' at the beginning of the first node.
|
// Insert 'Hello World' at the beginning of the first node.
|
||||||
editor.insertText(firstTextNode, 'Hello World', 0);
|
editor.insertText(firstTextNode, 'Hello World', 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Get information about the text node**
|
Once the text has been added, we can get information about the text node.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// Get plain text.
|
// Get the text of the first text node as plain text
|
||||||
final textAfterInserted = firstTextNode.toRawString();
|
final textAfterInserted = firstTextNode.toRawString();
|
||||||
print(textAfterInserted);
|
print(textAfterInserted);
|
||||||
// Get attributes.
|
// Get the attributes of the text node
|
||||||
final attributes = firstTextNode.attributes;
|
final attributes = firstTextNode.attributes;
|
||||||
print(attributes);
|
print(attributes);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## A Complete Code Example
|
||||||
For example, we are going to test `select_all_handler.dart`
|
|
||||||
|
|
||||||
|
In the example code below we are going to test `select_all_handler.dart` by inserting 100 lines of text that read "Welcome to Appflowy 😁" and then simulating the "selectAll" shortcut key being pressed.
|
||||||
|
|
||||||
|
Afterwards, we will `expect` that the current selection of the editor is equal to the selection of all the lines that were generated.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
@ -124,5 +143,3 @@ void main() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information about testing, such as simulating a click, please refer to [An introduction to widget testing](https://docs.flutter.dev/cookbook/testing/widget/introduction)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user