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

Commit 383427d

Browse files
committed
Handle context menu on embedding strategy
1 parent f25fbca commit 383427d

File tree

8 files changed

+97
-93
lines changed

8 files changed

+97
-93
lines changed

lib/web_ui/lib/src/engine.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ export 'engine/canvaskit/vertices.dart';
5858
export 'engine/clipboard.dart';
5959
export 'engine/color_filter.dart';
6060
export 'engine/configuration.dart';
61-
export 'engine/context_menu.dart';
6261
export 'engine/dom.dart';
6362
export 'engine/embedder.dart';
6463
export 'engine/engine_canvas.dart';

lib/web_ui/lib/src/engine/context_menu.dart

Lines changed: 0 additions & 57 deletions
This file was deleted.

lib/web_ui/lib/src/engine/embedder.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,20 @@ class FlutterViewEmbedder {
356356
assert(element.parentNode == _resourcesHost);
357357
element.remove();
358358
}
359+
360+
/// Enables the browser's context menu for this part of the DOM.
361+
///
362+
/// By default, when a Flutter web app starts, the context menu is already
363+
/// enabled. Typically, this method would be used after calling
364+
/// [disableContextMenu] to first disable it.
365+
void enableContextMenu() => _embeddingStrategy.enableContextMenu();
366+
367+
/// Disables the browser's context menu for this part of the DOM.
368+
///
369+
/// By default, when a Flutter web app starts, the context menu is enabled.
370+
///
371+
/// Can be re-enabled by calling [enableContextMenu].
372+
void disableContextMenu() => _embeddingStrategy.disableContextMenu();
359373
}
360374

361375
/// The embedder singleton.

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import 'package:ui/ui.dart' as ui;
1212

1313
import '../engine.dart' show platformViewManager, registerHotRestartListener;
1414
import 'clipboard.dart';
15-
import 'context_menu.dart';
1615
import 'dom.dart';
1716
import 'embedder.dart';
1817
import 'mouse_cursor.dart';
@@ -537,11 +536,11 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
537536
final MethodCall decoded = codec.decodeMethodCall(data);
538537
switch (decoded.method) {
539538
case 'enableContextMenu':
540-
ContextMenu.enableContextMenu();
539+
flutterViewEmbedder.enableContextMenu();
541540
replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
542541
return;
543542
case 'disableContextMenu':
544-
ContextMenu.disableContextMenu();
543+
flutterViewEmbedder.disableContextMenu();
545544
replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
546545
return;
547546
}

lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ class CustomElementEmbeddingStrategy extends EmbeddingStrategy {
5151
registerElementForCleanup(resourceHost);
5252
}
5353

54+
@override
55+
void disableContextMenu() => disableContextMenuOn(_hostElement);
56+
57+
@override
58+
void enableContextMenu() => enableContextMenuOn(_hostElement);
59+
5460
void _setHostAttribute(String name, String value) {
5561
_hostElement.setAttribute(name, value);
5662
}

lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:meta/meta.dart';
66

77
import 'package:ui/src/engine/dom.dart';
8+
import 'package:ui/src/engine/safe_browser_api.dart';
89
import 'package:ui/src/engine/view_embedder/hot_restart_cache_handler.dart';
910

1011
import 'custom_element_embedding_strategy.dart';
@@ -20,7 +21,7 @@ import 'full_page_embedding_strategy.dart';
2021
/// * [CustomElementEmbeddingStrategy] - Flutter is rendered inside a custom host
2122
/// element, provided by the web app programmer through the engine
2223
/// initialization.
23-
abstract class EmbeddingStrategy {
24+
abstract class EmbeddingStrategy with _ContextMenu {
2425
EmbeddingStrategy() {
2526
// Initialize code to handle hot-restart (debug only).
2627
assert(() {
@@ -56,3 +57,70 @@ abstract class EmbeddingStrategy {
5657
_hotRestartCache?.registerElement(element);
5758
}
5859
}
60+
61+
mixin _ContextMenu {
62+
/// False when the context menu has been disabled, otherwise true.
63+
bool _contextMenuEnabled = true;
64+
65+
/// Listener for contextmenu events that prevents the browser's context menu
66+
/// from being shown.
67+
final DomEventListener _disablingContextMenuListener = allowInterop((DomEvent event) {
68+
event.preventDefault();
69+
});
70+
71+
/// Disables the browser's context menu for this part of the DOM.
72+
///
73+
/// By default, when a Flutter web app starts, the context menu is enabled.
74+
///
75+
/// Can be re-enabled by calling [enableContextMenu].
76+
///
77+
/// See also:
78+
///
79+
/// * [disableContextMenuOn], which is like this but takes the relevant
80+
/// [DomElement] as a parameter.
81+
void disableContextMenu();
82+
83+
/// Disables the browser's context menu for the given [DomElement].
84+
///
85+
/// See also:
86+
///
87+
/// * [disableContextMenu], which is like this but is not passed a
88+
/// [DomElement].
89+
@protected
90+
void disableContextMenuOn(DomElement element) {
91+
if (!_contextMenuEnabled) {
92+
return;
93+
}
94+
95+
element.addEventListener('contextmenu', _disablingContextMenuListener);
96+
_contextMenuEnabled = false;
97+
}
98+
99+
/// Enables the browser's context menu for this part of the DOM.
100+
///
101+
/// By default, when a Flutter web app starts, the context menu is already
102+
/// enabled. Typically, this method would be used after calling
103+
/// [disableContextMenu] to first disable it.
104+
///
105+
/// See also:
106+
///
107+
/// * [enableContextMenuOn], which is like this but takes the relevant
108+
/// [DomElement] as a parameter.
109+
void enableContextMenu();
110+
111+
/// Enables the browser's context menu for the given [DomElement].
112+
///
113+
/// See also:
114+
///
115+
/// * [enableContextMenu], which is like this but is not passed a
116+
/// [DomElement].
117+
@protected
118+
void enableContextMenuOn(DomElement element) {
119+
if (_contextMenuEnabled) {
120+
return;
121+
}
122+
123+
element.removeEventListener('contextmenu', _disablingContextMenuListener);
124+
_contextMenuEnabled = true;
125+
}
126+
}

lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class FullPageEmbeddingStrategy extends EmbeddingStrategy {
4848
registerElementForCleanup(resourceHost);
4949
}
5050

51+
@override
52+
void disableContextMenu() => disableContextMenuOn(domDocument.body!);
53+
54+
@override
55+
void enableContextMenu() => enableContextMenuOn(domDocument.body!);
56+
5157
void _setHostAttribute(String name, String value) {
5258
domDocument.body!.setAttribute(name, value);
5359
}

lib/web_ui/test/engine/context_menu_test.dart

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)