add enterkeyhint property to web textfields (flutter/engine#35411)

This commit is contained in:
Tim Whiting 2022-08-31 11:13:50 -06:00 committed by GitHub
parent 026b8abd3a
commit 6ef93045af
5 changed files with 182 additions and 0 deletions

View File

@ -1288,6 +1288,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/word_break_properties.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/word_breaker.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart

View File

@ -161,6 +161,7 @@ export 'engine/text/word_break_properties.dart';
export 'engine/text/word_breaker.dart';
export 'engine/text_editing/autofill_hint.dart';
export 'engine/text_editing/composition_aware_mixin.dart';
export 'engine/text_editing/input_action.dart';
export 'engine/text_editing/input_type.dart';
export 'engine/text_editing/text_capitalization.dart';
export 'engine/text_editing/text_editing.dart';

View File

@ -0,0 +1,155 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../browser_detection.dart';
import '../dom.dart';
/// Various input action types used in text fields.
///
/// These types are coming from Flutter's [TextInputAction]. Currently, the web doesn't
/// support all the types. We fallback to [EngineInputAction.none] when Flutter
/// sends a type that isn't supported.
abstract class EngineInputAction {
const EngineInputAction();
static EngineInputAction fromName(String name) {
switch (name) {
case 'TextInputAction.continueAction':
case 'TextInputAction.next':
return next;
case 'TextInputAction.previous':
return previous;
case 'TextInputAction.done':
return done;
case 'TextInputAction.go':
return go;
case 'TextInputAction.newline':
return enter;
case 'TextInputAction.search':
return search;
case 'TextInputAction.send':
return send;
case 'TextInputAction.emergencyCall':
case 'TextInputAction.join':
case 'TextInputAction.none':
case 'TextInputAction.route':
case 'TextInputAction.unspecified':
default:
return none;
}
}
/// No input action
static const NoInputAction none = NoInputAction();
/// Action to go to next
static const NextInputAction next = NextInputAction();
/// Action to go to previous
static const PreviousInputAction previous = PreviousInputAction();
/// Action to be finished
static const DoneInputAction done = DoneInputAction();
/// Action to Go
static const GoInputAction go = GoInputAction();
/// Action to insert newline
static const EnterInputAction enter = EnterInputAction();
/// Action to search
static const SearchInputAction search = SearchInputAction();
/// Action to send
static const SendInputAction send = SendInputAction();
/// The HTML `enterkeyhint` attribute to be set on the DOM element.
///
/// This HTML attribute helps the browser decide what kind of keyboard action
/// to use for this text field
///
/// For various `enterkeyhint` values supported by browsers, see:
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint>.
String? get enterkeyhintAttribute;
/// Given a [domElement], set attributes that are specific to this input action.
void configureInputAction(DomHTMLElement domElement) {
if (enterkeyhintAttribute == null) {
return;
}
// Only apply `enterkeyhint` in mobile browsers so that the right virtual
// keyboard shows up.
if (operatingSystem == OperatingSystem.iOs ||
operatingSystem == OperatingSystem.android ||
enterkeyhintAttribute == EngineInputAction.none.enterkeyhintAttribute) {
domElement.setAttribute('enterkeyhint', enterkeyhintAttribute!);
}
}
}
/// No action specified
class NoInputAction extends EngineInputAction {
const NoInputAction();
@override
String? get enterkeyhintAttribute => null;
}
/// Typically inserting a new line.
class EnterInputAction extends EngineInputAction {
const EnterInputAction();
@override
String? get enterkeyhintAttribute => 'enter';
}
/// Typically meaning there is nothing more to input and the input method editor (IME) will be closed.
class DoneInputAction extends EngineInputAction {
const DoneInputAction();
@override
String? get enterkeyhintAttribute => 'done';
}
/// Typically meaning to take the user to the target of the text they typed.
class GoInputAction extends EngineInputAction {
const GoInputAction();
@override
String? get enterkeyhintAttribute => 'go';
}
/// Typically taking the user to the next field that will accept text.
class NextInputAction extends EngineInputAction {
const NextInputAction();
@override
String? get enterkeyhintAttribute => 'next';
}
/// Typically taking the user to the previous field that will accept text.
class PreviousInputAction extends EngineInputAction {
const PreviousInputAction();
@override
String? get enterkeyhintAttribute => 'previous';
}
/// Typically taking the user to the results of searching for the text they have typed.
class SearchInputAction extends EngineInputAction {
const SearchInputAction();
@override
String? get enterkeyhintAttribute => 'search';
}
/// Typically delivering the text to its target.
class SendInputAction extends EngineInputAction {
const SendInputAction();
@override
String? get enterkeyhintAttribute => 'send';
}

View File

@ -21,6 +21,7 @@ import '../text/paragraph.dart';
import '../util.dart';
import 'autofill_hint.dart';
import 'composition_aware_mixin.dart';
import 'input_action.dart';
import 'input_type.dart';
import 'text_capitalization.dart';
@ -1180,6 +1181,9 @@ abstract class DefaultTextEditingStrategy with CompositionAwareMixin implements
activeDomElement.setAttribute('inputmode', 'none');
}
final EngineInputAction action = EngineInputAction.fromName(config.inputAction);
action.configureInputAction(activeDomElement);
final AutofillInfo? autofill = config.autofill;
if (autofill != null) {
autofill.applyToDomElement(activeDomElement, focusedElement: true);

View File

@ -159,6 +159,27 @@ Future<void> testMain() async {
editingStrategy!.disable();
});
test('Knows how to create non-default text actions', () {
final InputConfiguration config = InputConfiguration(
inputAction: 'TextInputAction.send'
);
editingStrategy!.enable(
config,
onChange: trackEditingState,
onAction: trackInputAction,
);
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
final DomElement input = defaultTextEditingRoot.querySelector('input')!;
expect(editingStrategy!.domElement, input);
if (operatingSystem == OperatingSystem.iOs || operatingSystem == OperatingSystem.android){
expect(input.getAttribute('enterkeyhint'), 'send');
} else {
expect(input.getAttribute('enterkeyhint'), null);
}
editingStrategy!.disable();
});
test('Knows to turn autocorrect off', () {
final InputConfiguration config = InputConfiguration(
autocorrect: false,