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

Commit 1caaf43

Browse files
committed
[web] Migrate Flutter Web DOM usage to JS static interop - 22.
1 parent ba606b5 commit 1caaf43

File tree

8 files changed

+117
-70
lines changed

8 files changed

+117
-70
lines changed

lib/web_ui/lib/src/engine/clipboard.dart

+12-13
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
75
import 'package:ui/ui.dart' as ui;
86

97
import 'browser_detection.dart';
8+
import 'dom.dart';
109
import 'services.dart';
1110
import 'util.dart';
1211

@@ -90,7 +89,7 @@ class ClipboardMessageHandler {
9089
/// APIs and the browser.
9190
abstract class CopyToClipboardStrategy {
9291
factory CopyToClipboardStrategy() {
93-
return !unsafeIsNull(html.window.navigator.clipboard)
92+
return !unsafeIsNull(domWindow.navigator.clipboard)
9493
? ClipboardAPICopyStrategy()
9594
: ExecCommandCopyStrategy();
9695
}
@@ -110,7 +109,7 @@ abstract class CopyToClipboardStrategy {
110109
abstract class PasteFromClipboardStrategy {
111110
factory PasteFromClipboardStrategy() {
112111
return (browserEngine == BrowserEngine.firefox ||
113-
unsafeIsNull(html.window.navigator.clipboard))
112+
unsafeIsNull(domWindow.navigator.clipboard))
114113
? ExecCommandPasteStrategy()
115114
: ClipboardAPIPasteStrategy();
116115
}
@@ -127,7 +126,7 @@ class ClipboardAPICopyStrategy implements CopyToClipboardStrategy {
127126
@override
128127
Future<bool> setData(String? text) async {
129128
try {
130-
await html.window.navigator.clipboard!.writeText(text!);
129+
await domWindow.navigator.clipboard!.writeText(text!);
131130
} catch (error) {
132131
print('copy is not successful $error');
133132
return Future<bool>.value(false);
@@ -145,7 +144,7 @@ class ClipboardAPICopyStrategy implements CopyToClipboardStrategy {
145144
class ClipboardAPIPasteStrategy implements PasteFromClipboardStrategy {
146145
@override
147146
Future<String> getData() async {
148-
return html.window.navigator.clipboard!.readText();
147+
return domWindow.navigator.clipboard!.readText();
149148
}
150149
}
151150

@@ -159,13 +158,13 @@ class ExecCommandCopyStrategy implements CopyToClipboardStrategy {
159158
bool _setDataSync(String? text) {
160159
// Copy content to clipboard with execCommand.
161160
// See: https://developers.google.com/web/updates/2015/04/cut-and-copy-commands
162-
final html.TextAreaElement tempTextArea = _appendTemporaryTextArea();
161+
final DomHTMLTextAreaElement tempTextArea = _appendTemporaryTextArea();
163162
tempTextArea.value = text;
164163
tempTextArea.focus();
165164
tempTextArea.select();
166165
bool result = false;
167166
try {
168-
result = html.document.execCommand('copy');
167+
result = domDocument.execCommand('copy');
169168
if (!result) {
170169
print('copy is not successful');
171170
}
@@ -177,9 +176,9 @@ class ExecCommandCopyStrategy implements CopyToClipboardStrategy {
177176
return result;
178177
}
179178

180-
html.TextAreaElement _appendTemporaryTextArea() {
181-
final html.TextAreaElement tempElement = html.TextAreaElement();
182-
final html.CssStyleDeclaration elementStyle = tempElement.style;
179+
DomHTMLTextAreaElement _appendTemporaryTextArea() {
180+
final DomHTMLTextAreaElement tempElement = createDomHTMLTextAreaElement();
181+
final DomCSSStyleDeclaration elementStyle = tempElement.style;
183182
elementStyle
184183
..position = 'absolute'
185184
..top = '-99999px'
@@ -189,12 +188,12 @@ class ExecCommandCopyStrategy implements CopyToClipboardStrategy {
189188
..backgroundColor = 'transparent'
190189
..background = 'transparent';
191190

192-
html.document.body!.append(tempElement);
191+
domDocument.body!.append(tempElement);
193192

194193
return tempElement;
195194
}
196195

197-
void _removeTemporaryTextArea(html.HtmlElement element) {
196+
void _removeTemporaryTextArea(DomHTMLElement element) {
198197
element.remove();
199198
}
200199
}

lib/web_ui/lib/src/engine/dom.dart

+49
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extension DomWindowExtension on DomWindow {
2929
external int? get innerHeight;
3030
external int? get innerWidth;
3131
external DomNavigator get navigator;
32+
external DomVisualViewport? get visualViewport;
3233
external DomPerformance get performance;
3334
Future<Object?> fetch(String url) =>
3435
js_util.promiseToFuture(js_util.callMethod(this, 'fetch', <String>[url]));
@@ -50,6 +51,7 @@ external DomWindow get domWindow;
5051
class DomNavigator {}
5152

5253
extension DomNavigatorExtension on DomNavigator {
54+
external DomClipboard? get clipboard;
5355
external int? get maxTouchPoints;
5456
external String get vendor;
5557
external String get language;
@@ -62,13 +64,15 @@ extension DomNavigatorExtension on DomNavigator {
6264
class DomDocument {}
6365

6466
extension DomDocumentExtension on DomDocument {
67+
external DomElement? get documentElement;
6568
external DomElement? querySelector(String selectors);
6669
List<DomElement> querySelectorAll(String selectors) =>
6770
js_util.callMethod<List<Object?>>(
6871
this, 'querySelectorAll', <Object>[selectors]).cast<DomElement>();
6972
DomElement createElement(String name, [Object? options]) =>
7073
js_util.callMethod(this, 'createElement',
7174
<Object>[name, if (options != null) options]) as DomElement;
75+
external bool execCommand(String commandId);
7276
external DomHTMLScriptElement? get currentScript;
7377
external DomElement createElementNS(
7478
String namespaceURI, String qualifiedName);
@@ -167,6 +171,8 @@ DomElement createDomElement(String tag) => domDocument.createElement(tag);
167171
extension DomElementExtension on DomElement {
168172
List<DomElement> get children =>
169173
js_util.getProperty<List<Object?>>(this, 'children').cast<DomElement>();
174+
external int get clientHeight;
175+
external int get clientWidth;
170176
external String get id;
171177
external set id(String id);
172178
external set innerHtml(String? html);
@@ -254,6 +260,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
254260
set flexDirection(String value) => setProperty('flex-direction', value, '');
255261
set alignItems(String value) => setProperty('align-items', value, '');
256262
set margin(String value) => setProperty('margin', value, '');
263+
set background(String value) => setProperty('background', value, '');
257264
String get width => getPropertyValue('width');
258265
String get height => getPropertyValue('height');
259266
String get position => getPropertyValue('position');
@@ -308,6 +315,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
308315
String get flexDirection => getPropertyValue('flex-direction');
309316
String get alignItems => getPropertyValue('align-items');
310317
String get margin => getPropertyValue('margin');
318+
String get background=> getPropertyValue('background');
311319

312320
external String getPropertyValue(String property);
313321
void setProperty(String propertyName, String value, [String? priority]) {
@@ -325,6 +333,7 @@ class DomHTMLElement extends DomElement {}
325333

326334
extension DomHTMLElementExtension on DomHTMLElement {
327335
int get offsetWidth => js_util.getProperty<num>(this, 'offsetWidth') as int;
336+
external void focus();
328337
}
329338

330339
@JS()
@@ -376,6 +385,13 @@ class DomHTMLDivElement extends DomHTMLElement {}
376385
DomHTMLDivElement createDomHTMLDivElement() =>
377386
domDocument.createElement('div') as DomHTMLDivElement;
378387

388+
@JS()
389+
@staticInterop
390+
class DomHTMLSpanElement extends DomHTMLElement {}
391+
392+
DomHTMLSpanElement createDomHTMLSpanElement() =>
393+
domDocument.createElement('span') as DomHTMLSpanElement;
394+
379395
@JS()
380396
@staticInterop
381397
class DomHTMLButtonElement extends DomHTMLElement {}
@@ -610,6 +626,39 @@ extension DomFontFaceSetExtension on DomFontFaceSet {
610626
external void clear();
611627
}
612628

629+
@JS()
630+
@staticInterop
631+
class DomVisualViewport extends DomEventTarget {}
632+
633+
extension DomVisualViewportExtension on DomVisualViewport {
634+
external num? get height;
635+
external num? get width;
636+
}
637+
638+
@JS()
639+
@staticInterop
640+
class DomHTMLTextAreaElement extends DomHTMLElement {}
641+
642+
DomHTMLTextAreaElement createDomHTMLTextAreaElement() =>
643+
domDocument.createElement('textarea') as DomHTMLTextAreaElement;
644+
645+
extension DomHTMLTextAreaElementExtension on DomHTMLTextAreaElement {
646+
external set value(String? value);
647+
external void select();
648+
}
649+
650+
@JS()
651+
@staticInterop
652+
class DomClipboard extends DomEventTarget {}
653+
654+
extension DomClipboardExtension on DomClipboard {
655+
Future<String> readText() =>
656+
js_util.promiseToFuture<String>(js_util.callMethod(this, 'readText', <Object>[]));
657+
658+
Future<dynamic> writeText(String data) =>
659+
js_util.promiseToFuture(js_util.callMethod(this, 'readText', <Object>[data]));
660+
}
661+
613662
extension DomResponseExtension on DomResponse {
614663
Future<dynamic> arrayBuffer() => js_util
615664
.promiseToFuture(js_util.callMethod(this, 'arrayBuffer', <Object>[]));

lib/web_ui/lib/src/engine/platform_dispatcher.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'canvaskit/initialization.dart';
1515
import 'canvaskit/layer_scene_builder.dart';
1616
import 'canvaskit/rasterizer.dart';
1717
import 'clipboard.dart';
18+
import 'dom.dart';
1819
import 'embedder.dart';
1920
import 'html/scene.dart';
2021
import 'mouse_cursor.dart';
@@ -482,8 +483,8 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
482483
case 'flutter/platform_views':
483484
_platformViewMessageHandler ??= PlatformViewMessageHandler(
484485
contentManager: platformViewManager,
485-
contentHandler: (html.Element content) {
486-
flutterViewEmbedder.glassPaneElement!.append(content);
486+
contentHandler: (DomElement content) {
487+
flutterViewEmbedder.glassPaneElement!.append(content as html.Element);
487488
},
488489
);
489490
_platformViewMessageHandler!.handlePlatformViewCall(data, callback!);

lib/web_ui/lib/src/engine/platform_views/content_manager.dart

+13-12
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@
55
import 'dart:html' as html;
66

77
import '../browser_detection.dart';
8+
import '../dom.dart';
89
import '../embedder.dart';
910
import '../util.dart';
1011
import 'slots.dart';
1112

1213
/// A function which takes a unique `id` and some `params` and creates an HTML element.
1314
///
1415
/// This is made available to end-users through dart:ui in web.
15-
typedef ParameterizedPlatformViewFactory = html.Element Function(
16+
typedef ParameterizedPlatformViewFactory = DomElement Function(
1617
int viewId, {
1718
Object? params,
1819
});
1920

2021
/// A function which takes a unique `id` and creates an HTML element.
2122
///
2223
/// This is made available to end-users through dart:ui in web.
23-
typedef PlatformViewFactory = html.Element Function(int viewId);
24+
typedef PlatformViewFactory = DomElement Function(int viewId);
2425

2526
/// This class handles the lifecycle of Platform Views in the DOM of a Flutter Web App.
2627
///
@@ -29,7 +30,7 @@ typedef PlatformViewFactory = html.Element Function(int viewId);
2930
///
3031
/// * `factories`: The functions used to render the contents of any given Platform
3132
/// View by its `viewType`.
32-
/// * `contents`: The result [html.Element] of calling a `factory` function.
33+
/// * `contents`: The result [DomElement] of calling a `factory` function.
3334
///
3435
/// The third part is `slots`, which are created on demand by the
3536
/// [createPlatformViewSlot] function.
@@ -41,7 +42,7 @@ class PlatformViewManager {
4142
final Map<String, Function> _factories = <String, Function>{};
4243

4344
// The references to content tags, indexed by their framework-given ID.
44-
final Map<int, html.Element> _contents = <int, html.Element>{};
45+
final Map<int, DomElement> _contents = <int, DomElement>{};
4546

4647
final Set<String> _invisibleViews = <String>{};
4748
final Map<int, String> _viewIdToType = <int, String>{};
@@ -103,7 +104,7 @@ class PlatformViewManager {
103104
/// a place where to attach the `slot` property, that will tell the browser
104105
/// what `slot` tag will reveal this `contents`, **without modifying the returned
105106
/// html from the `factory` function**.
106-
html.Element renderContent(
107+
DomElement renderContent(
107108
String viewType,
108109
int viewId,
109110
Object? params,
@@ -115,12 +116,12 @@ class PlatformViewManager {
115116
_viewIdToType[viewId] = viewType;
116117

117118
return _contents.putIfAbsent(viewId, () {
118-
final html.Element wrapper = html.document
119+
final DomElement wrapper = domDocument
119120
.createElement('flt-platform-view')
120121
..setAttribute('slot', slotName);
121122

122123
final Function factoryFunction = _factories[viewType]!;
123-
late html.Element content;
124+
late DomElement content;
124125

125126
if (factoryFunction is ParameterizedPlatformViewFactory) {
126127
content = factoryFunction(viewId, params: params);
@@ -140,7 +141,7 @@ class PlatformViewManager {
140141
/// never been rendered before.
141142
void clearPlatformView(int viewId) {
142143
// Remove from our cache, and then from the DOM...
143-
final html.Element? element = _contents.remove(viewId);
144+
final DomElement? element = _contents.remove(viewId);
144145
_safelyRemoveSlottedElement(element);
145146
}
146147

@@ -149,7 +150,7 @@ class PlatformViewManager {
149150
// than its slot (after the slot is removed).
150151
//
151152
// TODO(web): Cleanup https://github.com/flutter/flutter/issues/85816
152-
void _safelyRemoveSlottedElement(html.Element? element) {
153+
void _safelyRemoveSlottedElement(DomElement? element) {
153154
if (element == null) {
154155
return;
155156
}
@@ -159,10 +160,10 @@ class PlatformViewManager {
159160
}
160161
final String tombstoneName = "tombstone-${element.getAttribute('slot')}";
161162
// Create and inject a new slot in the shadow root
162-
final html.Element slot = html.document.createElement('slot')
163+
final DomElement slot = domDocument.createElement('slot')
163164
..style.display = 'none'
164165
..setAttribute('name', tombstoneName);
165-
flutterViewEmbedder.glassPaneShadow!.append(slot);
166+
flutterViewEmbedder.glassPaneShadow!.append(slot as html.Node);
166167
// Link the element to the new slot
167168
element.setAttribute('slot', tombstoneName);
168169
// Delete both the element, and the new slot
@@ -172,7 +173,7 @@ class PlatformViewManager {
172173

173174
/// Attempt to ensure that the contents of the user-supplied DOM element will
174175
/// fill the space allocated for this platform view by the framework.
175-
void _ensureContentCorrectlySized(html.Element content, String viewType) {
176+
void _ensureContentCorrectlySized(DomElement content, String viewType) {
176177
// Scrutinize closely any other modifications to `content`.
177178
// We shouldn't modify users' returned `content` if at all possible.
178179
// Note there's also no getContent(viewId) function anymore, to prevent

lib/web_ui/lib/src/engine/platform_views/message_handler.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
65
import 'dart:typed_data';
76

7+
import '../dom.dart';
88
import '../services.dart';
99
import '../util.dart';
1010
import 'content_manager.dart';
@@ -13,9 +13,9 @@ import 'content_manager.dart';
1313
/// Copied here so there's no circular dependencies.
1414
typedef _PlatformMessageResponseCallback = void Function(ByteData? data);
1515

16-
/// A function that handle a newly created [html.Element] with the contents of a
16+
/// A function that handle a newly created [DomElement] with the contents of a
1717
/// platform view with a unique [int] id.
18-
typedef PlatformViewContentHandler = void Function(html.Element);
18+
typedef PlatformViewContentHandler = void Function(DomElement);
1919

2020
/// This class handles incoming framework messages to create/dispose Platform Views.
2121
///
@@ -91,7 +91,7 @@ class PlatformViewMessageHandler {
9191
}
9292

9393
// TODO(hterkelsen): How can users add extra `args` from the HtmlElementView widget?
94-
final html.Element content = _contentManager.renderContent(
94+
final DomElement content = _contentManager.renderContent(
9595
viewType,
9696
viewId,
9797
args,

0 commit comments

Comments
 (0)