|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
import 'package:tuple/tuple.dart'; |
|
|
|
|
|
|
|
|
|
import '../../../models/documents/document.dart'; |
|
|
|
|
import '../documents/attribute.dart'; |
|
|
|
|
import '../documents/style.dart'; |
|
|
|
|
import '../quill_delta.dart'; |
|
|
|
@ -286,6 +287,110 @@ class InsertEmbedsRule extends InsertRule { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Applies link format to text segments within the inserted text that matches |
|
|
|
|
/// the URL pattern. |
|
|
|
|
/// |
|
|
|
|
/// The link attribute is applied as the user types. |
|
|
|
|
class AutoFormatMultipleLinksRule extends InsertRule { |
|
|
|
|
const AutoFormatMultipleLinksRule(); |
|
|
|
|
|
|
|
|
|
/// Link pattern. |
|
|
|
|
/// |
|
|
|
|
/// This pattern is used to match a links within a text segment. |
|
|
|
|
static const _linkPattern = |
|
|
|
|
r'(https?:\/\/|www\.)[\w-\.]+\.[\w-\.]+(\/([\S]+)?)?'; |
|
|
|
|
static final _linkRegExp = RegExp(_linkPattern); |
|
|
|
|
|
|
|
|
|
@override |
|
|
|
|
Delta? applyRule( |
|
|
|
|
Delta document, |
|
|
|
|
int index, { |
|
|
|
|
int? len, |
|
|
|
|
Object? data, |
|
|
|
|
Attribute? attribute, |
|
|
|
|
}) { |
|
|
|
|
// Only format when inserting text. |
|
|
|
|
if (data is! String) return null; |
|
|
|
|
|
|
|
|
|
// Get current text. |
|
|
|
|
final entireText = Document.fromDelta(document).toPlainText(); |
|
|
|
|
|
|
|
|
|
// Get word before insertion. |
|
|
|
|
final leftWordPart = entireText |
|
|
|
|
// Keep all text before insertion. |
|
|
|
|
.substring(0, index) |
|
|
|
|
// Keep last paragraph. |
|
|
|
|
.split('\n') |
|
|
|
|
.last |
|
|
|
|
// Keep last word. |
|
|
|
|
.split(' ') |
|
|
|
|
.last |
|
|
|
|
.trimLeft(); |
|
|
|
|
|
|
|
|
|
// Get word after insertion. |
|
|
|
|
final rightWordPart = entireText |
|
|
|
|
// Keep all text after insertion. |
|
|
|
|
.substring(index) |
|
|
|
|
// Keep first paragraph. |
|
|
|
|
.split('\n') |
|
|
|
|
.first |
|
|
|
|
// Keep first word. |
|
|
|
|
.split(' ') |
|
|
|
|
.first |
|
|
|
|
.trimRight(); |
|
|
|
|
|
|
|
|
|
// Build the segment of affected words. |
|
|
|
|
final affectedWords = '$leftWordPart$data$rightWordPart'; |
|
|
|
|
|
|
|
|
|
// Check for URL pattern. |
|
|
|
|
final matches = _linkRegExp.allMatches(affectedWords); |
|
|
|
|
|
|
|
|
|
// If there are no matches, do not apply any format. |
|
|
|
|
if (matches.isEmpty) return null; |
|
|
|
|
|
|
|
|
|
// Build base delta. |
|
|
|
|
// The base delta is a simple insertion delta. |
|
|
|
|
final baseDelta = Delta() |
|
|
|
|
..retain(index) |
|
|
|
|
..insert(data); |
|
|
|
|
|
|
|
|
|
// Get unchanged text length. |
|
|
|
|
final unmodifiedLength = index - leftWordPart.length; |
|
|
|
|
|
|
|
|
|
// Create formatter delta. |
|
|
|
|
// The formatter delta will only include links formatting when needed. |
|
|
|
|
final formatterDelta = Delta()..retain(unmodifiedLength); |
|
|
|
|
|
|
|
|
|
var previousLinkEndRelativeIndex = 0; |
|
|
|
|
for (final match in matches) { |
|
|
|
|
// Get the size of the leading segment of text that is not part of the |
|
|
|
|
// link. |
|
|
|
|
final separationLength = match.start - previousLinkEndRelativeIndex; |
|
|
|
|
|
|
|
|
|
// Get the identified link. |
|
|
|
|
final link = affectedWords.substring(match.start, match.end); |
|
|
|
|
|
|
|
|
|
// Keep the leading segment of text and add link with its proper |
|
|
|
|
// attribute. |
|
|
|
|
formatterDelta |
|
|
|
|
..retain(separationLength, LinkAttribute(null).toJson()) |
|
|
|
|
..retain(link.length, LinkAttribute(link).toJson()); |
|
|
|
|
|
|
|
|
|
// Update reference index. |
|
|
|
|
previousLinkEndRelativeIndex = match.end; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get remaining text length. |
|
|
|
|
final remainingLength = affectedWords.length - previousLinkEndRelativeIndex; |
|
|
|
|
|
|
|
|
|
// Remove links from remaining non-link text. |
|
|
|
|
formatterDelta.retain(remainingLength, LinkAttribute(null).toJson()); |
|
|
|
|
|
|
|
|
|
// Build and return resulting change delta. |
|
|
|
|
return baseDelta.compose(formatterDelta); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Applies link format to text segment (which looks like a link) when user |
|
|
|
|
/// inserts space character after it. |
|
|
|
|
class AutoFormatLinksRule extends InsertRule { |
|
|
|
|