Skip to content

Commit

Permalink
Fix exception thrown when inserting new line with toggled inline styl…
Browse files Browse the repository at this point in the history
…es (#161)
  • Loading branch information
Amir-P authored Sep 23, 2023
1 parent 187ac7a commit 74447c4
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 15 deletions.
50 changes: 35 additions & 15 deletions packages/fleather/lib/src/widgets/controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:math' as math;

import 'package:collection/collection.dart';
import 'package:fleather/src/widgets/history.dart';
import 'package:fleather/util.dart';
import 'package:flutter/cupertino.dart';
Expand Down Expand Up @@ -69,14 +70,39 @@ class FleatherController extends ChangeNotifier {
.mergeAll(toggledStyles);
}

bool _shouldApplyToggledStyles(Delta delta) =>
toggledStyles.isNotEmpty &&
delta.isNotEmpty &&
((delta.length <= 2 && // covers single insert and a retain+insert
delta.last.isInsert) ||
(delta.length <= 3 &&
delta.last.isRetain // special case for AutoTextDirectionRule
));
bool _shouldApplyToggledStyles(Delta delta) {
if (toggledStyles.isNotEmpty && delta.isNotEmpty) {
// covers single insert and a retain+insert
if (delta.length <= 2 && delta.last.isInsert) {
return true;
}
// special case for AutoTextDirectionRule
if (delta.length <= 3 && delta.last.isRetain) {
return delta.last.attributes != null &&
delta.last.attributes!
.containsKey(ParchmentAttribute.direction.key) &&
delta.last.attributes!
.containsKey(ParchmentAttribute.alignment.key);
}
}
return false;
}

void _applyToggledStyles(int index, Object data) {
if (data is String && !isDataOnlyNewLines(data)) {
var retainDelta = Delta()..retain(index);
final segments = data.split('\n');
segments.forEachIndexed((index, segment) {
if (segment.isNotEmpty) {
retainDelta.retain(segment.length, toggledStyles.toJson());
}
if (index != segments.length - 1) {
retainDelta.retain(1);
}
});
document.compose(retainDelta, ChangeSource.local);
}
}

/// Replaces [length] characters in the document starting at [index] with
/// provided [text].
Expand All @@ -96,14 +122,8 @@ class FleatherController extends ChangeNotifier {
final isDataNotEmpty = data is String ? data.isNotEmpty : true;
if (length > 0 || isDataNotEmpty) {
delta = document.replace(index, length, data);
// If the delta is an insert operation and we have toggled
// some styles, then apply those styles to the inserted text.
if (_shouldApplyToggledStyles(delta)) {
final dataLength = data is String ? data.length : 1;
final retainDelta = Delta()
..retain(index)
..retain(dataLength, toggledStyles.toJson());
document.compose(retainDelta, ChangeSource.local);
_applyToggledStyles(index, data);
}
}

Expand Down
5 changes: 5 additions & 0 deletions packages/fleather/lib/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ TextDirection getDirectionOfNode(StyledNode node) {
}
return TextDirection.ltr;
}

bool isDataOnlyNewLines(Object data) {
if (data is! String || data.isEmpty) return false;
return RegExp('^(\n)+\$').hasMatch(data);
}
10 changes: 10 additions & 0 deletions packages/fleather/test/util_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,14 @@ void main() {
expect(result, 1);
});
});

test('isDataOnlyNewLines', () {
expect(isDataOnlyNewLines(123), false);
expect(isDataOnlyNewLines(Object()), false);
expect(isDataOnlyNewLines(''), false);
expect(isDataOnlyNewLines('\nTest\nTest\n'), false);
expect(isDataOnlyNewLines('\n \n\n'), false);
expect(isDataOnlyNewLines('\n\t\n\n'), false);
expect(isDataOnlyNewLines('\n\n\n'), true);
});
}
16 changes: 16 additions & 0 deletions packages/fleather/test/widgets/controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ void main() {
// expect(controller.lastChangeSource, ChangeSource.local);
});

test('replaceText only applies toggled styles to non new line parts', () {
controller.replaceText(0, 0, 'Words');
controller.formatText(2, 0, ParchmentAttribute.bold);
controller.replaceText(2, 0, '\nTest\n');

expect(
controller.document.toDelta(),
Delta()
..insert('Wo\n')
..insert('Test', ParchmentAttribute.bold.toJson())
..insert('\n')
..insert('rds')
..insert('\n'),
);
});

test('insert text with toggled style unset', () {
var notified = false;
controller.addListener(() {
Expand Down

0 comments on commit 74447c4

Please sign in to comment.