-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to insert a custom embed in autoformat/heuristics #369
Comments
This is the full function, FYI:
|
Hi @cotw-fabier.
Your confusion is totally normal. In fact, I myself have to read lots of code and try different things every time I need to tweak something in the editor and it's mostly due to the complexity of the project and poor documentation. Here's a working sample based on your code which catches YouTube links after pressing space or enter and turns them into an embedded object inside editor: import 'package:fleather/fleather.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:parchment_delta/parchment_delta.dart';
void main() {
runApp(const FleatherApp());
}
class FleatherApp extends StatelessWidget {
const FleatherApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
title: 'Fleather - rich-text editor for Flutter',
home: HomePage(),
);
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final FocusNode _focusNode = FocusNode();
final _controller = FleatherController(
autoFormats: AutoFormats(autoFormats: [AutoFormatYoutubeEmbed()]));
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(elevation: 0, title: Text('Fleather Demo')),
body: Column(
children: [
FleatherToolbar.basic(controller: _controller),
Divider(height: 1, thickness: 1, color: Colors.grey.shade200),
Expanded(
child: FleatherEditor(
controller: _controller,
focusNode: _focusNode,
padding: EdgeInsets.only(
left: 16,
right: 16,
bottom: MediaQuery.of(context).padding.bottom,
),
maxContentWidth: 800,
embedBuilder: _embedBuilder,
spellCheckConfiguration: SpellCheckConfiguration(
spellCheckService: DefaultSpellCheckService(),
misspelledSelectionColor: Colors.red,
misspelledTextStyle: DefaultTextStyle.of(context).style),
),
),
],
),
);
}
Widget _embedBuilder(BuildContext context, EmbedNode node) {
if (node.value.type == 'youtube') {
return Container(
height: 200,
color: Colors.red,
child: Center(
child: Text(
"A placeholder for youtube video: ${node.value.data['url']}")),
);
}
return defaultFleatherEmbedBuilder(context, node);
}
}
class AutoFormatYoutubeEmbed extends AutoFormat {
static final _youtubePattern =
RegExp(r'https:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)');
const AutoFormatYoutubeEmbed();
@override
AutoFormatResult? apply(
ParchmentDocument document, int position, String data) {
if (data != ' ' && data != '\n') return null;
final documentDelta = document.toDelta();
final iter = DeltaIterator(documentDelta);
final previous = iter.skip(position);
if (previous == null || previous.data is! String) return null;
final previousText = previous.data as String;
final candidate = previousText.split('\n').last.split(' ').last;
final match = _youtubePattern.firstMatch(candidate);
if (match == null) return null;
final videoId = match.group(1);
final url = 'https://www.youtube.com/watch?v=$videoId';
final thumbUrl = 'https://img.youtube.com/vi/$videoId/0.jpg';
final youtubeEmbedDelta = {
"_type": "youtube",
"_inline": false,
"url": url,
"subtitles": "English",
"language": "en",
"thumbUrl": thumbUrl
};
final change = Delta()
..retain(position - candidate.length)
..delete(candidate.length + 1)
..insert(youtubeEmbedDelta)
..insert('\n');
final undo = change.invert(documentDelta);
document.compose(change, ChangeSource.local);
return AutoFormatResult(
change: change,
undo: undo,
undoPositionCandidate: position - candidate.length + 1,
selection:
TextSelection.collapsed(offset: position - candidate.length + 2),
undoSelection: TextSelection.collapsed(offset: position),
);
}
}
You're right. It's impossible to extend the default auto formats right now. Will work on it. |
My man! Thank you for the speedy reply. I was thinking about documentation. Would you guys be open to some help with writing documentation? I would also be interested in submitting a PR to add a way to simply spread the default autoformats. I'm not the best dart developer you've ever met, but I think you guys have an excellent package and would love to do my part to help others realize it as well :). |
FYI your solution works perfectly!! Many thanks! |
You're welcome. Glad it worked. I will close the issue but feel free to reopen it.
We will be more than happy to have your help. You can contribute to the documentation at https://github.com/fleather-editor/fleather-editor.github.io. Although we have an old PR (fleather-editor/fleather-editor.github.io#3) waiting for a few months now but we will try to review them soon.
Thanks for the kind words! Don't forget to give it a star! ⭐️ |
Hey Guys,
Please forgive my possibly dumb question but I've been struggling trying to figure out how to do this for a while now. I have a custom embed I've built for displaying Youtube videos inline which feels pretty slick. I created a button to insert a dummy video. Code looks like this to insert:
Then, I had an idea. What if I could make a shortcut to insert a Youtube Video by adding a bang "!" and the youtube link and it would convert it into the proper embed.
At first I did a bunch of stuff with Heuristics trying to get this to work, but then after searching discussions I learned you had introduced Autoformats to accomplish this very use-case.
But I am running into two problems.
1.) How do I insert an embed when I only can access the Document? I am getting errors when I attempt to insert an object with my document, I've using
And also:
And also:
All three of these throw errors for some reason. Either "No attribute key is registered" or "The following _TypeError was thrown during method call TextInputClient.updateEditingStateWithDeltas:
type 'Null' is not a subtype of type 'String' in type cast"
What am I doing wrong here?
Also, my second question. When adding autoformats. How do I not override the current ones? I can't spread the fallback ones afaik. This won't work:
Thanks! I'm sorry for the giant post. I've spent hours on this and am throwing up the white flag. Any help would be greatly appreciated!
The text was updated successfully, but these errors were encountered: