Skip to content
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

Cherry Pick: Changed LinkAttribution to allow invalid (unchecked) URLs (Resolves #1927) #1989

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ MutableDocument _createInitialDocument() {
AttributedSpans(
attributions: [
SpanMarker(
attribution: LinkAttribution(url: Uri.https('example.org', '')),
attribution: LinkAttribution.fromUri(Uri.https('example.org', '')),
offset: 30,
markerType: SpanMarkerType.start),
SpanMarker(
attribution: LinkAttribution(url: Uri.https('example.org', '')),
attribution: LinkAttribution.fromUri(Uri.https('example.org', '')),
offset: 35,
markerType: SpanMarkerType.end),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ class _EditorToolbarState extends State<EditorToolbar> {

final trimmedRange = _trimTextRangeWhitespace(text, selectionRange);

final linkAttribution = LinkAttribution(url: Uri.parse(url));
final linkAttribution = LinkAttribution.fromUri(Uri.parse(url));

widget.editor!.execute([
AddTextAttributionsRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ Document createInitialDocument() {
"Built by the Flutter Bounty Hunters",
AttributedSpans(attributions: [
SpanMarker(
attribution: LinkAttribution(url: Uri.parse("https://flutterbountyhunters.com")),
attribution: LinkAttribution.fromUri(Uri.parse("https://flutterbountyhunters.com")),
offset: 13,
markerType: SpanMarkerType.start),
SpanMarker(
attribution: LinkAttribution(url: Uri.parse("https://flutterbountyhunters.com")),
attribution: LinkAttribution.fromUri(Uri.parse("https://flutterbountyhunters.com")),
offset: 34,
markerType: SpanMarkerType.end),
]),
Expand Down
2 changes: 1 addition & 1 deletion super_editor/example_docs/lib/toolbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ class _DocsEditorToolbarState extends State<DocsEditorToolbar> {

final trimmedRange = _trimTextRangeWhitespace(text, selectionRange);

final linkAttribution = LinkAttribution(url: Uri.parse(url));
final linkAttribution = LinkAttribution.fromUri(Uri.parse(url));

widget.editor.execute([
AddTextAttributionsRequest(
Expand Down
23 changes: 19 additions & 4 deletions super_editor/lib/src/default_editor/attributions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,29 @@ class FontSizeAttribution implements Attribution {
/// within [AttributedText]. This class doesn't have a special
/// relationship with [AttributedText].
class LinkAttribution implements Attribution {
LinkAttribution({
required this.url,
});
factory LinkAttribution.fromUri(Uri uri) {
return LinkAttribution(uri.toString());
}

const LinkAttribution(this.url);

@override
String get id => 'link';

final Uri url;
/// The URL associated with the attributed text, as a `String`.
final String url;

/// Attempts to parse the [url] as a [Uri], and returns `true` if the [url]
/// is successfully parsed, or `false` if parsing fails, such as due to the [url]
/// including an invalid scheme, separator syntax, extra segments, etc.
bool get hasValidUri => Uri.tryParse(url) != null;

/// The URL associated with the attributed text, as a `Uri`.
///
/// Accessing the [uri] throws an exception if the [url] isn't valid.
/// To access a URL that might not be valid, consider accessing the [url],
/// instead.
Uri get uri => Uri.parse(url);

@override
bool canMergeWith(Attribution other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2380,7 +2380,7 @@ class PasteEditorCommand implements EditCommand {

if (link != null && link.hasScheme && link.hasAuthority) {
// Valid url. Apply [LinkAttribution] to the url
final linkAttribution = LinkAttribution(url: link);
final linkAttribution = LinkAttribution.fromUri(link);

final startOffset = wordBoundary.start;
// -1 because TextPosition's offset indexes the character after the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ class LinkifyReaction implements EditReaction {
final uri = _parseLink(word);

text.addAttribution(
LinkAttribution(url: uri),
LinkAttribution.fromUri(uri),
SpanRange(wordStartOffset, endOffset - 1),
);
}
Expand Down Expand Up @@ -798,8 +798,8 @@ class LinkifyReaction implements EditReaction {
// link attribution that reflects the edited URL text. We do that below.
if (updatePolicy == LinkUpdatePolicy.update) {
changedNodeText.addAttribution(
LinkAttribution(
url: _parseLink(changedNodeText.text.substring(rangeToUpdate.start, rangeToUpdate.end + 1)),
LinkAttribution.fromUri(
_parseLink(changedNodeText.text.substring(rangeToUpdate.start, rangeToUpdate.end + 1)),
),
rangeToUpdate,
);
Expand Down
2 changes: 1 addition & 1 deletion super_editor/lib/src/default_editor/super_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,7 @@ class SuperEditorLaunchLinkTapHandler extends ContentTapDelegate {
final tappedAttributions = textNode.text.getAllAttributionsAt(nodePosition.offset);
for (final tappedAttribution in tappedAttributions) {
if (tappedAttribution is LinkAttribution) {
return tappedAttribution.url;
return tappedAttribution.uri;
}
}

Expand Down
2 changes: 1 addition & 1 deletion super_editor/lib/src/super_reader/super_reader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ class SuperReaderLaunchLinkTapHandler extends ContentTapDelegate {
final tappedAttributions = textNode.text.getAllAttributionsAt(nodePosition.offset);
for (final tappedAttribution in tappedAttributions) {
if (tappedAttribution is LinkAttribution) {
return tappedAttribution.url;
return tappedAttribution.uri;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,12 @@ MutableDocument _singleParagraphWithLinkDoc() {
AttributedSpans(
attributions: [
SpanMarker(
attribution: LinkAttribution(url: Uri.parse('https://google.com')),
attribution: LinkAttribution.fromUri(Uri.parse('https://google.com')),
offset: 0,
markerType: SpanMarkerType.start,
),
SpanMarker(
attribution: LinkAttribution(url: Uri.parse('https://google.com')),
attribution: LinkAttribution.fromUri(Uri.parse('https://google.com')),
offset: 17,
markerType: SpanMarkerType.end,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1488,12 +1488,12 @@ MutableDocument _singleParagraphWithLinkDoc() {
AttributedSpans(
attributions: [
SpanMarker(
attribution: LinkAttribution(url: Uri.parse('https://google.com')),
attribution: LinkAttribution.fromUri(Uri.parse('https://google.com')),
offset: 0,
markerType: SpanMarkerType.start,
),
SpanMarker(
attribution: LinkAttribution(url: Uri.parse('https://google.com')),
attribution: LinkAttribution.fromUri(Uri.parse('https://google.com')),
offset: 17,
markerType: SpanMarkerType.end,
),
Expand Down
18 changes: 10 additions & 8 deletions super_editor/test/super_editor/test_documents.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ MutableDocument singleParagraphWithLinkDoc() => MutableDocument(
"This paragraph includes a link that the user can tap",
AttributedSpans(
attributions: [
SpanMarker(
attribution: LinkAttribution(url: Uri.parse("https://fake.url")),
offset: 26,
markerType: SpanMarkerType.start),
SpanMarker(
attribution: LinkAttribution(url: Uri.parse("https://fake.url")),
offset: 30,
markerType: SpanMarkerType.end),
const SpanMarker(
attribution: LinkAttribution("https://fake.url"),
offset: 26,
markerType: SpanMarkerType.start,
),
const SpanMarker(
attribution: LinkAttribution("https://fake.url"),
offset: 30,
markerType: SpanMarkerType.end,
),
],
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ void main() {

// Add link across "one two"
text.addAttribution(
LinkAttribution(url: Uri.parse('https://flutter.dev')),
const LinkAttribution('https://flutter.dev'),
const SpanRange(0, 6),
);

// Try to add a different link across "two three" and expect
// an exception
expect(() {
text.addAttribution(
LinkAttribution(url: Uri.parse('https://pub.dev')),
const LinkAttribution('https://pub.dev'),
const SpanRange(4, 12),
);
}, throwsA(isA<IncompatibleOverlappingAttributionsException>()));
Expand All @@ -27,7 +27,7 @@ void main() {
test('identical link attributions can overlap', () {
final text = AttributedText('one two three');

final linkAttribution = LinkAttribution(url: Uri.parse('https://flutter.dev'));
const linkAttribution = LinkAttribution('https://flutter.dev');

// Add link across "one two"
text.addAttribution(
Expand All @@ -36,7 +36,7 @@ void main() {
);

text.addAttribution(
LinkAttribution(url: Uri.parse('https://flutter.dev')),
const LinkAttribution('https://flutter.dev'),
const SpanRange(4, 12),
);

Expand Down
Loading
Loading