[web] Changes to EditableState to be able to handle Framework text selection shortcuts (flutter/engine#37097)

This commit is contained in:
htoor3
2022-11-01 11:32:30 -05:00
committed by GitHub
parent 5371c52ffe
commit aca860012b
3 changed files with 85 additions and 27 deletions

View File

@@ -666,13 +666,13 @@ class EditingState {
this.text,
int? baseOffset,
int? extentOffset,
this.composingBaseOffset,
this.composingExtentOffset
this.composingBaseOffset = -1,
this.composingExtentOffset = -1
}) :
// Don't allow negative numbers. Pick the smallest selection index for base.
baseOffset = math.max(0, math.min(baseOffset ?? 0, extentOffset ?? 0)),
// Don't allow negative numbers. Pick the greatest selection index for extent.
extentOffset = math.max(0, math.max(baseOffset ?? 0, extentOffset ?? 0));
// Don't allow negative numbers.
baseOffset = math.max(0, baseOffset ?? 0),
// Don't allow negative numbers.
extentOffset = math.max(0, extentOffset ?? 0);
/// Creates an [EditingState] instance using values from an editing state Map
/// coming from Flutter.
@@ -707,8 +707,8 @@ class EditingState {
text: text,
baseOffset: selectionBase,
extentOffset: selectionExtent,
composingBaseOffset: composingBase,
composingExtentOffset: composingExtent
composingBaseOffset: composingBase ?? -1,
composingExtentOffset: composingExtent ?? -1
);
}
@@ -736,6 +736,11 @@ class EditingState {
}
}
// Pick the smallest selection index for base.
int get minOffset => math.min(baseOffset ?? 0, extentOffset ?? 0);
// Pick the greatest selection index for extent.
int get maxOffset => math.max(baseOffset ?? 0, extentOffset ?? 0);
EditingState copyWith({
String? text,
int? baseOffset,
@@ -773,10 +778,10 @@ class EditingState {
final int? extentOffset;
/// The offset at which [CompositionAwareMixin.composingText] begins, if any.
final int? composingBaseOffset;
final int composingBaseOffset;
/// The offset at which [CompositionAwareMixin.composingText] terminates, if any.
final int? composingExtentOffset;
final int composingExtentOffset;
/// Whether the current editing state is valid or not.
bool get isValid => baseOffset! >= 0 && extentOffset! >= 0;
@@ -796,8 +801,8 @@ class EditingState {
}
return other is EditingState &&
other.text == text &&
other.baseOffset == baseOffset &&
other.extentOffset == extentOffset &&
other.minOffset == minOffset &&
other.maxOffset == maxOffset &&
other.composingBaseOffset == composingBaseOffset &&
other.composingExtentOffset == composingExtentOffset;
}
@@ -825,12 +830,12 @@ class EditingState {
if (domInstanceOfString(domElement, 'HTMLInputElement')) {
final DomHTMLInputElement element = domElement! as DomHTMLInputElement;
element.value = text;
element.setSelectionRange(baseOffset!, extentOffset!);
element.setSelectionRange(minOffset, maxOffset);
} else if (domInstanceOfString(domElement, 'HTMLTextAreaElement')) {
final DomHTMLTextAreaElement element = domElement! as
DomHTMLTextAreaElement;
element.value = text;
element.setSelectionRange(baseOffset!, extentOffset!);
element.setSelectionRange(minOffset, maxOffset);
} else {
throw UnsupportedError('Unsupported DOM element type: <${domElement?.tagName}> (${domElement.runtimeType})');
}

View File

@@ -184,7 +184,7 @@ Future<void> testMain() async {
expect(
editingStrategy.lastEditingState,
isA<EditingState>()
.having((EditingState editingState) => editingState.composingBaseOffset!,
.having((EditingState editingState) => editingState.composingBaseOffset,
'composingBaseOffset', beforeComposingText.length - composingText.length)
.having((EditingState editingState) => editingState.composingExtentOffset,
'composingExtentOffset', beforeComposingText.length));

View File

@@ -1557,8 +1557,8 @@ Future<void> testMain() async {
'text': 'something',
'selectionBase': 9,
'selectionExtent': 9,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
],
);
@@ -1583,8 +1583,8 @@ Future<void> testMain() async {
'text': 'something',
'selectionBase': 2,
'selectionExtent': 5,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
],
);
@@ -1641,8 +1641,8 @@ Future<void> testMain() async {
'deltaEnd': -1,
'selectionBase': 2,
'selectionExtent': 5,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
],
}
@@ -1724,8 +1724,8 @@ Future<void> testMain() async {
'text': 'something',
'selectionBase': 9,
'selectionExtent': 9,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
},
],
@@ -1796,8 +1796,8 @@ Future<void> testMain() async {
'text': 'something\nelse',
'selectionBase': 14,
'selectionExtent': 14,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
],
);
@@ -1812,8 +1812,8 @@ Future<void> testMain() async {
'text': 'something\nelse',
'selectionBase': 2,
'selectionExtent': 5,
'composingBase': null,
'composingExtent': null
'composingBase': -1,
'composingExtent': -1
}
],
);
@@ -2231,6 +2231,34 @@ Future<void> testMain() async {
);
});
test('Sets default composing offsets if none given', () {
final EditingState editingState =
EditingState(text: 'Test', baseOffset: 2, extentOffset: 4);
final EditingState editingStateFromFrameworkMsg =
EditingState.fromFrameworkMessage(<String, dynamic>{
'selectionBase': 10,
'selectionExtent': 4,
});
expect(editingState.composingBaseOffset, -1);
expect(editingState.composingExtentOffset, -1);
expect(editingStateFromFrameworkMsg.composingBaseOffset, -1);
expect(editingStateFromFrameworkMsg.composingExtentOffset, -1);
});
test('Correctly identifies min and max offsets', () {
final EditingState flippedEditingState =
EditingState(baseOffset: 10, extentOffset: 4);
final EditingState normalEditingState =
EditingState(baseOffset: 2, extentOffset: 6);
expect(flippedEditingState.minOffset, 4);
expect(flippedEditingState.maxOffset, 10);
expect(normalEditingState.minOffset, 2);
expect(normalEditingState.maxOffset, 6);
});
test('Configure input element from the editing state', () {
final DomHTMLInputElement input =
defaultTextEditingRoot.querySelector('input')! as DomHTMLInputElement;
@@ -2264,6 +2292,20 @@ Future<void> testMain() async {
expect(textArea.selectionEnd, 2);
});
test('Configure input element editing state for a flipped base and extent',
() {
final DomHTMLInputElement input =
defaultTextEditingRoot.querySelector('input')! as DomHTMLInputElement;
editingState =
EditingState(text: 'Hello World', baseOffset: 10, extentOffset: 2);
editingState.applyToDomElement(input);
expect(input.value, 'Hello World');
expect(input.selectionStart, 2);
expect(input.selectionEnd, 10);
});
test('Get Editing State from input element', () {
final DomHTMLInputElement input =
defaultTextEditingRoot.querySelector('input')! as DomHTMLInputElement;
@@ -2318,6 +2360,17 @@ Future<void> testMain() async {
expect(editingState1 != editingState3, isTrue);
});
test('Takes flipped base and extent offsets into account', () {
final EditingState flippedEditingState =
EditingState(baseOffset: 10, extentOffset: 4);
final EditingState normalEditingState =
EditingState(baseOffset: 4, extentOffset: 10);
expect(normalEditingState, flippedEditingState);
expect(normalEditingState == flippedEditingState, isTrue);
});
test('takes composition range into account', () {
final EditingState editingState1 = EditingState(composingBaseOffset: 1, composingExtentOffset: 2);
final EditingState editingState2 = EditingState(composingBaseOffset: 1, composingExtentOffset: 2);