Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/ruler.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/unicode_range.dart
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.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_editing.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/util.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart
Expand Down
3 changes: 2 additions & 1 deletion lib/web_ui/lib/src/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ part 'engine/text/ruler.dart';
part 'engine/text/unicode_range.dart';
part 'engine/text/word_break_properties.dart';
part 'engine/text/word_breaker.dart';
part 'engine/text_editing.dart';
part 'engine/text_editing/input_type.dart';
part 'engine/text_editing/text_editing.dart';
part 'engine/util.dart';
part 'engine/validators.dart';
part 'engine/vector_math.dart';
Expand Down
22 changes: 19 additions & 3 deletions lib/web_ui/lib/src/engine/browser_detection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,35 @@ OperatingSystem _operatingSystem;
///
/// This is used to implement operating system specific behavior such as
/// soft keyboards.
OperatingSystem get operatingSystem =>
_operatingSystem ??= _detectOperatingSystem();
OperatingSystem get operatingSystem {
if (debugOperatingSystemOverride != null) {
return debugOperatingSystemOverride;
}
return _operatingSystem ??= _detectOperatingSystem();
}

/// Override the value of [operatingSystem].
///
/// Setting this to `null` lets [operatingSystem] detect the real OS that the
/// app is running on.
///
/// This is intended to be used for testing and debugging only.
OperatingSystem debugOperatingSystemOverride;

OperatingSystem _detectOperatingSystem() {
final String platform = html.window.navigator.platform;
final String userAgent = html.window.navigator.userAgent;

if (platform.startsWith('Mac')) {
return OperatingSystem.macOs;
} else if (platform.toLowerCase().contains('iphone') ||
platform.toLowerCase().contains('ipad') ||
platform.toLowerCase().contains('ipod')) {
return OperatingSystem.iOs;
} else if (platform.toLowerCase().contains('android')) {
} else if (userAgent.contains('Android')) {
// The Android OS reports itself as "Linux armv8l" in
// [html.window.navigator.platform]. So we have to check the user-agent to
// determine if the OS is Android or not.
return OperatingSystem.android;
} else if (platform.startsWith('Linux')) {
return OperatingSystem.linux;
Expand Down
129 changes: 129 additions & 0 deletions lib/web_ui/lib/src/engine/text_editing/input_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// 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.

part of engine;

/// Various types of inputs used in text fields.
///
/// These types are coming from Flutter's [TextInputType]. Currently, we don't
/// support all the types. We fallback to [EngineInputType.text] when Flutter
/// sends a type that isn't supported.
// TODO(flutter_web): Support more types.
abstract class EngineInputType {
const EngineInputType();

static EngineInputType fromName(String name) {
switch (name) {
case 'TextInputType.number':
return number;
case 'TextInputType.phone':
return phone;
case 'TextInputType.emailAddress':
return emailAddress;
case 'TextInputType.url':
return url;
case 'TextInputType.multiline':
return multiline;

case 'TextInputType.text':
default:
return text;
}
}

/// Single-line text input type.
static const TextInputType text = TextInputType();

/// Numeric input type.
static const NumberInputType number = NumberInputType();

/// Phone number input type.
static const PhoneInputType phone = PhoneInputType();

/// Email address input type.
static const EmailInputType emailAddress = EmailInputType();

/// URL input type.
static const UrlInputType url = UrlInputType();

/// Multi-line text input type.
static const MultilineInputType multiline = MultilineInputType();

/// The HTML `inputmode` attribute to be set on the DOM element.
///
/// This HTML attribute helps the browser decide what kind of keyboard works
/// best for this text field.
///
/// For various `inputmode` values supported by browsers, see:
/// <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode>.
String get inputmodeAttribute;

/// Create the appropriate DOM element for this input type.
html.HtmlElement createDomElement() => html.InputElement();

/// Given a [domElement], set attributes that are specific to this input type.
void configureDomElement(html.HtmlElement domElement) {
if (inputmodeAttribute == null) {
return;
}

// Only apply `inputmode` in mobile browsers so that the right virtual
// keyboard shows up.
if (operatingSystem == OperatingSystem.iOs ||
operatingSystem == OperatingSystem.android) {
domElement.setAttribute('inputmode', inputmodeAttribute);
}
}
}

/// Single-line text input type.
class TextInputType extends EngineInputType {
const TextInputType();

@override
final String inputmodeAttribute = 'text';
}

/// Numeric input type.
class NumberInputType extends EngineInputType {
const NumberInputType();

@override
final String inputmodeAttribute = 'numeric';
}

/// Phone number input type.
class PhoneInputType extends EngineInputType {
const PhoneInputType();

@override
final String inputmodeAttribute = 'tel';
}

/// Email address input type.
class EmailInputType extends EngineInputType {
const EmailInputType();

@override
final String inputmodeAttribute = 'email';
}

/// URL input type.
class UrlInputType extends EngineInputType {
const UrlInputType();

@override
final String inputmodeAttribute = 'url';
}

/// Multi-line text input type.
class MultilineInputType extends EngineInputType {
const MultilineInputType();

@override
final String inputmodeAttribute = null;

@override
html.HtmlElement createDomElement() => html.TextAreaElement();
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,31 +163,6 @@ class EditingState {
}
}

/// Various types of inputs used in text fields.
///
/// These types are coming from Flutter's [TextInputType]. Currently, we don't
/// support all the types. We fallback to [InputType.text] when Flutter sends
/// a type that isn't supported.
// TODO(flutter_web): Support more types.
enum InputType {
/// Single-line plain text.
text,

/// Multi-line text.
multiline,
}

InputType _getInputTypeFromString(String inputType) {
switch (inputType) {
case 'TextInputType.multiline':
return InputType.multiline;

case 'TextInputType.text':
default:
return InputType.text;
}
}

/// Controls the appearance of the input control being edited.
///
/// For example, [inputType] determines whether we should use `<input>` or
Expand All @@ -201,12 +176,12 @@ class InputConfiguration {
});

InputConfiguration.fromFlutter(Map<String, dynamic> flutterInputConfiguration)
: inputType = _getInputTypeFromString(
: inputType = EngineInputType.fromName(
flutterInputConfiguration['inputType']['name']),
obscureText = flutterInputConfiguration['obscureText'];

/// The type of information being edited in the input control.
final InputType inputType;
final EngineInputType inputType;

/// Whether to hide the text being edited.
final bool obscureText;
Expand Down Expand Up @@ -341,6 +316,7 @@ class TextEditingElement {
_subscriptions.add(domElement.onKeyUp.listen((event) {
_handleChange(event);
}));

/// In Firefox the context menu item "Select All" does not work without
/// listening to onSelect. On the other browsers onSelectionChange is
/// enough for covering "Select All" functionality.
Expand Down Expand Up @@ -370,19 +346,10 @@ class TextEditingElement {
}

void _initDomElement(InputConfiguration inputConfig) {
switch (inputConfig.inputType) {
case InputType.text:
domElement = owner.createInputElement();
break;

case InputType.multiline:
domElement = owner.createTextAreaElement();
break;

default:
throw UnsupportedError(
'Unsupported input type: ${inputConfig.inputType}');
}
domElement = inputConfig.inputType.createDomElement();
inputConfig.inputType.configureDomElement(domElement);
_setStaticStyleAttributes(domElement);
owner._setDynamicStyleAttributes(domElement);
domRenderer.glassPaneElement.append(domElement);
}

Expand Down Expand Up @@ -757,20 +724,6 @@ class HybridTextEditing {
void setStyleOutsideOfScreen(html.HtmlElement domElement) {
domElement.style.transform = 'translate(-9999px, -9999px)';
}

html.InputElement createInputElement() {
final html.InputElement input = html.InputElement();
_setStaticStyleAttributes(input);
_setDynamicStyleAttributes(input);
return input;
}

html.TextAreaElement createTextAreaElement() {
final html.TextAreaElement textarea = html.TextAreaElement();
_setStaticStyleAttributes(textarea);
_setDynamicStyleAttributes(textarea);
return textarea;
}
}

/// Information on the font and alignment of a text editing element.
Expand Down
Loading