Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 7f4f4a8

Browse files
author
nturgut
committed
update editing state
1 parent 990803e commit 7f4f4a8

File tree

2 files changed

+82
-7
lines changed

2 files changed

+82
-7
lines changed

lib/web_ui/lib/src/engine/text_editing/text_editing.dart

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,17 +305,19 @@ class EditingState {
305305
///
306306
/// [domElement] can be a [InputElement] or a [TextAreaElement] depending on
307307
/// the [InputType] of the text field.
308-
factory EditingState.fromDomElement(html.HtmlElement? domElement) {
308+
factory EditingState.fromDomElement(html.HtmlElement? domElement,
309+
{TextCapitalizationUtil textCapitalization =
310+
const TextCapitalizationUtil.defaultCapitalization()}) {
309311
if (domElement is html.InputElement) {
310312
html.InputElement element = domElement;
311313
return EditingState(
312-
text: element.value,
314+
text: textCapitalization.capitializeTextValue(element.value),
313315
baseOffset: element.selectionStart,
314316
extentOffset: element.selectionEnd);
315317
} else if (domElement is html.TextAreaElement) {
316318
html.TextAreaElement element = domElement;
317319
return EditingState(
318-
text: element.value,
320+
text: textCapitalization.capitializeTextValue(element.value),
319321
baseOffset: element.selectionStart,
320322
extentOffset: element.selectionEnd);
321323
} else {
@@ -706,7 +708,8 @@ abstract class DefaultTextEditingStrategy implements TextEditingStrategy {
706708
void _handleChange(html.Event event) {
707709
assert(isEnabled);
708710

709-
EditingState newEditingState = EditingState.fromDomElement(domElement);
711+
EditingState newEditingState = EditingState.fromDomElement(domElement,
712+
textCapitalization: _inputConfiguration.textCapitalization);
710713

711714
if (newEditingState != _lastEditingState) {
712715
_lastEditingState = newEditingState;
@@ -1487,6 +1490,12 @@ enum TextCapitalization {
14871490
class TextCapitalizationUtil {
14881491
final TextCapitalization textCapitalization;
14891492

1493+
static final RegExp wordExp = new RegExp(r"(\w+)");
1494+
static final RegExp whiteSpaceExp = new RegExp(r"(\s+)");
1495+
1496+
const TextCapitalizationUtil.defaultCapitalization()
1497+
: textCapitalization = TextCapitalization.none;
1498+
14901499
// TODO: support sentence level text capitalization.
14911500
TextCapitalizationUtil.fromInputConfiguration(String inputConfiguration)
14921501
: this.textCapitalization =
@@ -1513,4 +1522,50 @@ class TextCapitalizationUtil {
15131522
break;
15141523
}
15151524
}
1525+
1526+
/// Change the capitalization of the focused text field's value depending on
1527+
/// the [TextCapitalization].
1528+
///
1529+
/// For [TextCapitalization.words], this method makes all first letter of each
1530+
/// word uppercase.
1531+
///
1532+
/// For [TextCapitalization.characters], this method makes all letters of each
1533+
/// word uppercase.
1534+
///
1535+
/// For [TextCapitalization.sentence] is not supported for now.
1536+
String capitializeTextValue(String value) {
1537+
if (value.isEmpty) {
1538+
return value;
1539+
}
1540+
switch (textCapitalization) {
1541+
case TextCapitalization.words:
1542+
final Iterable<RegExpMatch> wordMatches = wordExp.allMatches(value);
1543+
final List<String> words = wordMatches.map((RegExpMatch match) {
1544+
final String? word = match.group(0);
1545+
return (word == null) ? '' : word;
1546+
}).toList();
1547+
final Iterable<RegExpMatch> whiteSpaceMatches =
1548+
whiteSpaceExp.allMatches(value);
1549+
final List<String> whiteSpaces =
1550+
whiteSpaceMatches.map((RegExpMatch match) {
1551+
final String? word = match.group(0);
1552+
return (word == null) ? '' : word;
1553+
}).toList();
1554+
final StringBuffer textValueBuffer = new StringBuffer();
1555+
for (int i = 0; i < words.length && !words[i].isEmpty; i++) {
1556+
final String word = words[i];
1557+
textValueBuffer.write('${word[0].toUpperCase()}${word.substring(1)}');
1558+
if (whiteSpaces.length > i) {
1559+
textValueBuffer.write(whiteSpaces[i]);
1560+
}
1561+
}
1562+
return textValueBuffer.toString();
1563+
case TextCapitalization.characters:
1564+
return value.toUpperCase();
1565+
case TextCapitalization.sentences:
1566+
case TextCapitalization.none:
1567+
default:
1568+
return value;
1569+
}
1570+
}
15161571
}

lib/web_ui/test/text_editing_test.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ void main() {
875875

876876
test(
877877
'Word capitilization: setClient, setEditingState, show, '
878-
'setEditingState, clearClient', () {
878+
'updateEditingState', () {
879879
// Create a configuration with an AutofillGroup of four text fields.
880880
final Map<String, dynamic> capitilizeWordsConfig =
881881
createFlutterConfig('text',
@@ -895,12 +895,32 @@ void main() {
895895

896896
const MethodCall show = MethodCall('TextInput.show');
897897
sendFrameworkMessage(codec.encodeMethodCall(show));
898+
spy.messages.clear();
898899

899900
expect(textEditing.editingElement.domElement.style.textTransform,
900901
'capitalize');
901902

902-
const MethodCall clearClient = MethodCall('TextInput.clearClient');
903-
sendFrameworkMessage(codec.encodeMethodCall(clearClient));
903+
final InputElement element = textEditing.editingElement.domElement;
904+
element.value = 'something some test';
905+
element.dispatchEvent(Event.eventType('Event', 'input'));
906+
907+
expect(spy.messages, hasLength(1));
908+
expect(spy.messages[0].channel, 'flutter/textinput');
909+
expect(spy.messages[0].methodName, 'TextInputClient.updateEditingState');
910+
expect(
911+
spy.messages[0].methodArguments,
912+
<dynamic>[
913+
123, // Client ID
914+
<String, dynamic>{
915+
'text': 'Something Some Test',
916+
'selectionBase': 19,
917+
'selectionExtent': 19,
918+
},
919+
],
920+
);
921+
922+
spy.messages.clear();
923+
hideKeyboard();
904924
});
905925

906926
test(

0 commit comments

Comments
 (0)