-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix web editable text composing range (#33590)
Flutter web framework now gets valid composing region updates from engine Co-authored-by: Anthony Oleinik <[email protected]>
- Loading branch information
1 parent
1a1c309
commit 1b9fb67
Showing
6 changed files
with
446 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// 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 'dart:html' as html; | ||
|
||
import 'text_editing.dart'; | ||
|
||
/// Provides default functionality for listening to HTML composition events. | ||
/// | ||
/// A class with this mixin generally calls [determineCompositionState] in order to update | ||
/// an [EditingState] with new composition values; namely, [EditingState.composingBaseOffset] | ||
/// and [EditingState.composingExtentOffset]. | ||
/// | ||
/// A class with this mixin should call [addCompositionEventHandlers] on initalization, and | ||
/// [removeCompositionEventHandlers] on deinitalization. | ||
/// | ||
/// See also: | ||
/// | ||
/// * [EditingState], the state of a text field that [CompositionAwareMixin] updates. | ||
/// * [DefaultTextEditingStrategy], the primary implementer of [CompositionAwareMixin]. | ||
mixin CompositionAwareMixin { | ||
/// The name of the HTML composition event type that triggers on starting a composition. | ||
static const String _kCompositionStart = 'compositionstart'; | ||
|
||
/// The name of the browser composition event type that triggers on updating a composition. | ||
static const String _kCompositionUpdate = 'compositionupdate'; | ||
|
||
/// The name of the browser composition event type that triggers on ending a composition. | ||
static const String _kCompositionEnd = 'compositionend'; | ||
|
||
late final html.EventListener _compositionStartListener = _handleCompositionStart; | ||
late final html.EventListener _compositionUpdateListener = _handleCompositionUpdate; | ||
late final html.EventListener _compositionEndListener = _handleCompositionEnd; | ||
|
||
/// The currently composing text in the `domElement`. | ||
/// | ||
/// Will be null if composing just started, ended, or no composing is being done. | ||
/// This member is kept up to date provided compositionEventHandlers are in place, | ||
/// so it is safe to reference it to get the current composingText. | ||
String? composingText; | ||
|
||
void addCompositionEventHandlers(html.HtmlElement domElement) { | ||
domElement.addEventListener(_kCompositionStart, _compositionStartListener); | ||
domElement.addEventListener(_kCompositionUpdate, _compositionUpdateListener); | ||
domElement.addEventListener(_kCompositionEnd, _compositionEndListener); | ||
} | ||
|
||
void removeCompositionEventHandlers(html.HtmlElement domElement) { | ||
domElement.removeEventListener(_kCompositionStart, _compositionStartListener); | ||
domElement.removeEventListener(_kCompositionUpdate, _compositionUpdateListener); | ||
domElement.removeEventListener(_kCompositionEnd, _compositionEndListener); | ||
} | ||
|
||
void _handleCompositionStart(html.Event event) { | ||
composingText = null; | ||
} | ||
|
||
void _handleCompositionUpdate(html.Event event) { | ||
if (event is html.CompositionEvent) { | ||
composingText = event.data; | ||
} | ||
} | ||
|
||
void _handleCompositionEnd(html.Event event) { | ||
composingText = null; | ||
} | ||
|
||
EditingState determineCompositionState(EditingState editingState) { | ||
if (editingState.baseOffset == null || composingText == null || editingState.text == null) { | ||
return editingState; | ||
} | ||
|
||
final int composingBase = editingState.baseOffset! - composingText!.length; | ||
|
||
if (composingBase < 0) { | ||
return editingState; | ||
} | ||
|
||
return editingState.copyWith( | ||
composingBaseOffset: composingBase, | ||
composingExtentOffset: composingBase + composingText!.length, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.