Feat/link regexp (#1329)

* Allow for custom regular expression validation of links. (#1048)

* Fix the default RegExp for link validation to support port and match the beginning.
pull/1331/head
widealpha 2 years ago committed by GitHub
parent 1c91430882
commit b6ec9ff5d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      flutter_quill_extensions/lib/embeds/toolbar/image_button.dart
  2. 13
      flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart
  3. 4
      flutter_quill_extensions/lib/embeds/toolbar/video_button.dart
  4. 6
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  5. 2
      lib/src/models/rules/insert.dart
  6. 5
      lib/src/widgets/toolbar.dart
  7. 23
      lib/src/widgets/toolbar/link_style_button.dart

@ -18,6 +18,7 @@ class ImageButton extends StatelessWidget {
this.iconTheme,
this.dialogTheme,
this.tooltip,
this.linkRegExp,
Key? key,
}) : super(key: key);
@ -40,6 +41,7 @@ class ImageButton extends StatelessWidget {
final QuillDialogTheme? dialogTheme;
final String? tooltip;
final RegExp? linkRegExp;
@override
Widget build(BuildContext context) {
@ -90,7 +92,10 @@ class ImageButton extends StatelessWidget {
void _typeLink(BuildContext context) {
showDialog<String>(
context: context,
builder: (_) => LinkDialog(dialogTheme: dialogTheme),
builder: (_) => LinkDialog(
dialogTheme: dialogTheme,
linkRegExp: linkRegExp,
),
).then(_linkSubmitted);
}

@ -10,10 +10,16 @@ import 'package:image_picker/image_picker.dart';
import '../embed_types.dart';
class LinkDialog extends StatefulWidget {
const LinkDialog({this.dialogTheme, this.link, Key? key}) : super(key: key);
const LinkDialog({
this.dialogTheme,
this.link,
this.linkRegExp,
Key? key,
}) : super(key: key);
final QuillDialogTheme? dialogTheme;
final String? link;
final RegExp? linkRegExp;
@override
LinkDialogState createState() => LinkDialogState();
@ -22,12 +28,14 @@ class LinkDialog extends StatefulWidget {
class LinkDialogState extends State<LinkDialog> {
late String _link;
late TextEditingController _controller;
late RegExp _linkRegExp;
@override
void initState() {
super.initState();
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
_linkRegExp = widget.linkRegExp ?? AutoFormatMultipleLinksRule.linkRegExp;
}
@override
@ -48,8 +56,7 @@ class LinkDialogState extends State<LinkDialog> {
),
actions: [
TextButton(
onPressed: _link.isNotEmpty &&
AutoFormatMultipleLinksRule.linkRegExp.hasMatch(_link)
onPressed: _link.isNotEmpty && _linkRegExp.hasMatch(_link)
? _applyLink
: null,
child: Text(

@ -18,6 +18,7 @@ class VideoButton extends StatelessWidget {
this.iconTheme,
this.dialogTheme,
this.tooltip,
this.linkRegExp,
Key? key,
}) : super(key: key);
@ -39,8 +40,11 @@ class VideoButton extends StatelessWidget {
final QuillIconTheme? iconTheme;
final QuillDialogTheme? dialogTheme;
final String? tooltip;
final RegExp? linkRegExp;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);

@ -49,6 +49,8 @@ class FlutterQuillEmbeds {
FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl,
WebVideoPickImpl? webVideoPickImpl,
RegExp? imageLinkRegExp,
RegExp? videoLinkRegExp,
}) =>
[
if (showImageButton)
@ -63,6 +65,7 @@ class FlutterQuillEmbeds {
mediaPickSettingSelector: mediaPickSettingSelector,
iconTheme: iconTheme,
dialogTheme: dialogTheme,
linkRegExp: imageLinkRegExp,
),
if (showVideoButton)
(controller, toolbarIconSize, iconTheme, dialogTheme) => VideoButton(
@ -76,7 +79,8 @@ class FlutterQuillEmbeds {
mediaPickSettingSelector: mediaPickSettingSelector,
iconTheme: iconTheme,
dialogTheme: dialogTheme,
),
linkRegExp: videoLinkRegExp,
),
if ((onImagePickCallback != null || onVideoPickCallback != null) &&
showCameraButton)
(controller, toolbarIconSize, iconTheme, dialogTheme) => CameraButton(

@ -330,7 +330,7 @@ class AutoFormatMultipleLinksRule extends InsertRule {
// https://example.net/
// URL generator tool (https://www.randomlists.com/urls) is used.
static const _linkPattern =
r'(https?:\/\/|www\.)[\w-\.]+\.[\w-\.]+(\/([\S]+)?)?';
r'^https?:\/\/[\w\-]+(\.[\w\-]+)*(:\d+)?(\/.*)?$';
static final linkRegExp = RegExp(_linkPattern, caseSensitive: false);
@override

@ -154,6 +154,10 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// The space occupied by toolbar divider
double? sectionDividerSpace,
/// Validate the legitimacy of hyperlinks
RegExp? linkRegExp,
Key? key,
}) {
final isButtonGroupShown = [
@ -551,6 +555,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
iconTheme: iconTheme,
dialogTheme: dialogTheme,
afterButtonPressed: afterButtonPressed,
linkRegExp: linkRegExp,
),
if (showSearchButton)
SearchButton(

@ -18,6 +18,7 @@ class LinkStyleButton extends StatefulWidget {
this.dialogTheme,
this.afterButtonPressed,
this.tooltip,
this.linkRegExp,
Key? key,
}) : super(key: key);
@ -28,6 +29,7 @@ class LinkStyleButton extends StatefulWidget {
final QuillDialogTheme? dialogTheme;
final VoidCallback? afterButtonPressed;
final String? tooltip;
final RegExp? linkRegExp;
@override
_LinkStyleButtonState createState() => _LinkStyleButtonState();
@ -108,7 +110,11 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
text ??=
len == 0 ? '' : widget.controller.document.getPlainText(index, len);
return _LinkDialog(
dialogTheme: widget.dialogTheme, link: link, text: text);
dialogTheme: widget.dialogTheme,
link: link,
text: text,
linkRegExp: widget.linkRegExp,
);
},
).then(
(value) {
@ -143,12 +149,18 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
}
class _LinkDialog extends StatefulWidget {
const _LinkDialog({this.dialogTheme, this.link, this.text, Key? key})
: super(key: key);
const _LinkDialog({
this.dialogTheme,
this.link,
this.text,
this.linkRegExp,
Key? key,
}) : super(key: key);
final QuillDialogTheme? dialogTheme;
final String? link;
final String? text;
final RegExp? linkRegExp;
@override
_LinkDialogState createState() => _LinkDialogState();
@ -157,6 +169,7 @@ class _LinkDialog extends StatefulWidget {
class _LinkDialogState extends State<_LinkDialog> {
late String _link;
late String _text;
late RegExp linkRegExp;
late TextEditingController _linkController;
late TextEditingController _textController;
@ -165,6 +178,7 @@ class _LinkDialogState extends State<_LinkDialog> {
super.initState();
_link = widget.link ?? '';
_text = widget.text ?? '';
linkRegExp = widget.linkRegExp ?? AutoFormatMultipleLinksRule.linkRegExp;
_linkController = TextEditingController(text: _link);
_textController = TextEditingController(text: _text);
}
@ -218,8 +232,7 @@ class _LinkDialogState extends State<_LinkDialog> {
if (_text.isEmpty || _link.isEmpty) {
return false;
}
if (!AutoFormatMultipleLinksRule.linkRegExp.hasMatch(_link)) {
if (!linkRegExp.hasMatch(_link)) {
return false;
}

Loading…
Cancel
Save