// Since we only need to handler the input of `underscore`.
// All inputs except `underscore` will be ignored directly.
if (event.logicalKey != LogicalKeyboardKey.underscore) {
return KeyEventResult.ignored;
}
};
```
Then, we need to determine if the currently selected node is `TextNode` and is a single-select case, because for the multi-select case, underscore input should be considered as replacement.
Now, we start working on underscore logic by looking for the position of the previous underscore and returning if not found. If found, the text wrapped in the two underscores will be converted info italic.
For example, we want to render an image from network.
To start with, we build the simplest example, just a blank document.
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.topCenter,
child: FlowyEditor(
editorState: EditorState.empty(),
keyEventHandlers: const [],
),
),
);
}
```
Next, we choose a unique string for the type of the custom node and use `network_image` in this case. And we add `network_image_src` to the `attributes` to describe the link of the image.
> For the definition of the [Node](), please refer to this [link]().
Then, we create a class that inherits [NodeWidgetBuilder](). As shown in the autoprompt, we need to implement two functions, one that returns a widget and the other that verifies the correctness of the [Node]().
```dart
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/material.dart';
class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
@override
Widget build(NodeWidgetContext<Node> context) {
throw UnimplementedError();
}
@override
NodeValidator<Node> get nodeValidator => throw UnimplementedError();
}
```
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]().**
> For the definition of the [Selectable](), please refer to this [link]().
```dart
class _NetworkImageNodeWidget extends StatefulWidget {
const _NetworkImageNodeWidget({
Key? key,
required this.node,
}) : super(key: key);
final Node node;
@override
State<_NetworkImageNodeWidget> createState() =>
__NetworkImageNodeWidgetState();
}
class __NetworkImageNodeWidgetState extends State<_NetworkImageNodeWidget>
with Selectable {
RenderBox get _renderBox => context.findRenderObject() as RenderBox;
Finally, we return `_NetworkImageNodeWidget` in the `build` function of `NetworkImageNodeWidgetBuilder` and register `NetworkImageNodeWidgetBuilder` into `AppFlowyEditor`.
```dart
class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {