From b976577d84b9a1d53647101ee352a2a3f0c25274 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Thu, 7 Sep 2023 12:29:01 -0400 Subject: [PATCH 1/2] [web] Move context menu handling to its own class --- ci/licenses_golden/licenses_flutter | 4 + lib/web_ui/lib/src/engine.dart | 2 + lib/web_ui/lib/src/engine/embedder.dart | 14 --- .../lib/src/engine/mouse/context_menu.dart | 42 +++++++ .../lib/src/engine/mouse/prevent_default.dart | 10 ++ .../lib/src/engine/platform_dispatcher.dart | 4 +- .../src/engine/text_editing/text_editing.dart | 5 +- .../custom_element_embedding_strategy.dart | 6 - .../embedding_strategy.dart | 70 +----------- .../full_page_embedding_strategy.dart | 6 - lib/web_ui/lib/src/engine/window.dart | 8 +- .../test/engine/mouse/context_menu_test.dart | 104 ++++++++++++++++++ ...ustom_element_embedding_strategy_test.dart | 56 ---------- .../full_page_embedding_strategy_test.dart | 52 --------- 14 files changed, 174 insertions(+), 209 deletions(-) create mode 100644 lib/web_ui/lib/src/engine/mouse/context_menu.dart create mode 100644 lib/web_ui/lib/src/engine/mouse/prevent_default.dart create mode 100644 lib/web_ui/test/engine/mouse/context_menu_test.dart diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 24db8a78eeb23..108872308d53c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2038,7 +2038,9 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/key_map.g.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/keyboard_binding.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/layers.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/mouse/context_menu.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/mouse/cursor.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/mouse/prevent_default.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/navigation/history.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/noto_font.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/noto_font_encoding.dart + ../../../flutter/LICENSE @@ -4787,7 +4789,9 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/key_map.g.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/keyboard_binding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/layers.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/mouse/context_menu.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/mouse/cursor.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/mouse/prevent_default.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/navigation/history.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/noto_font.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/noto_font_encoding.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 1c166b90649a9..1fda83ecc08fa 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -111,7 +111,9 @@ export 'engine/js_interop/js_typed_data.dart'; export 'engine/key_map.g.dart'; export 'engine/keyboard_binding.dart'; export 'engine/layers.dart'; +export 'engine/mouse/context_menu.dart'; export 'engine/mouse/cursor.dart'; +export 'engine/mouse/prevent_default.dart'; export 'engine/navigation/history.dart'; export 'engine/noto_font.dart'; export 'engine/noto_font_encoding.dart'; diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index aced6b1ba0c84..7f362eee1f455 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -318,20 +318,6 @@ class FlutterViewEmbedder { assert(element.parentNode == _resourcesHost); element.remove(); } - - /// Disables the browser's context menu for this part of the DOM. - /// - /// By default, when a Flutter web app starts, the context menu is enabled. - /// - /// Can be re-enabled by calling [enableContextMenu]. - void disableContextMenu() => _embeddingStrategy.disableContextMenu(); - - /// Enables the browser's context menu for this part of the DOM. - /// - /// By default, when a Flutter web app starts, the context menu is already - /// enabled. Typically, this method would be used after calling - /// [disableContextMenu] to first disable it. - void enableContextMenu() => _embeddingStrategy.enableContextMenu(); } /// The embedder singleton. diff --git a/lib/web_ui/lib/src/engine/mouse/context_menu.dart b/lib/web_ui/lib/src/engine/mouse/context_menu.dart new file mode 100644 index 0000000000000..b34e3d64abe72 --- /dev/null +++ b/lib/web_ui/lib/src/engine/mouse/context_menu.dart @@ -0,0 +1,42 @@ +// 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 '../dom.dart'; +import 'prevent_default.dart'; + +/// Controls the browser's context menu in the given [element]. +class ContextMenu { + ContextMenu(this.element); + + final DomElement element; + + /// False when the context menu has been disabled, otherwise true. + bool _enabled = true; + + /// Disables the browser's context menu for this [element]. + /// + /// By default, when a Flutter web app starts, the context menu is enabled. + /// + /// Can be re-enabled by calling [enable]. + void disable() { + if (!_enabled) { + return; + } + _enabled = false; + element.addEventListener('contextmenu', preventDefaultListener); + } + + /// Enables the browser's context menu for this [element]. + /// + /// By default, when a Flutter web app starts, the context menu is already + /// enabled. Typically, this method would be used after calling + /// [disable] to first disable it. + void enable() { + if (_enabled) { + return; + } + _enabled = true; + element.removeEventListener('contextmenu', preventDefaultListener); + } +} diff --git a/lib/web_ui/lib/src/engine/mouse/prevent_default.dart b/lib/web_ui/lib/src/engine/mouse/prevent_default.dart new file mode 100644 index 0000000000000..2371deae14001 --- /dev/null +++ b/lib/web_ui/lib/src/engine/mouse/prevent_default.dart @@ -0,0 +1,10 @@ +// 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 '../dom.dart'; + +/// Listener for DOM events that prevents the default browser behavior. +final DomEventListener preventDefaultListener = createDomEventListener((DomEvent event) { + event.preventDefault(); +}); diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index e2ddae4ff0e0a..b8ec0fb537bd2 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -566,11 +566,11 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { final MethodCall decoded = codec.decodeMethodCall(data); switch (decoded.method) { case 'enableContextMenu': - flutterViewEmbedder.enableContextMenu(); + implicitView!.contextMenu.enable(); replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true)); return; case 'disableContextMenu': - flutterViewEmbedder.disableContextMenu(); + implicitView!.contextMenu.disable(); replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true)); return; } diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index bc094ea1cb215..3be53ed83cedc 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -12,6 +12,7 @@ import 'package:ui/ui.dart' as ui; import '../browser_detection.dart'; import '../dom.dart'; import '../embedder.dart'; +import '../mouse/prevent_default.dart'; import '../platform_dispatcher.dart'; import '../safe_browser_api.dart'; import '../semantics.dart'; @@ -210,9 +211,7 @@ class EngineAutofillForm { formElement.noValidate = true; formElement.method = 'post'; formElement.action = '#'; - formElement.addEventListener('submit', createDomEventListener((DomEvent e) { - e.preventDefault(); - })); + formElement.addEventListener('submit', preventDefaultListener); // We need to explicitly disable pointer events on the form in Safari Desktop, // so that we don't have pointer event collisions if users hover over or click diff --git a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart index 572bdb8ce33b2..ecf92bb3d8956 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart @@ -51,12 +51,6 @@ class CustomElementEmbeddingStrategy extends EmbeddingStrategy { registerElementForCleanup(resourceHost); } - @override - void disableContextMenu() => disableContextMenuOn(_hostElement); - - @override - void enableContextMenu() => enableContextMenuOn(_hostElement); - void _setHostAttribute(String name, String value) { _hostElement.setAttribute(name, value); } diff --git a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart index 8a3e401816bf9..bb1c9361ae2a8 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart @@ -20,7 +20,7 @@ import 'full_page_embedding_strategy.dart'; /// * [CustomElementEmbeddingStrategy] - Flutter is rendered inside a custom host /// element, provided by the web app programmer through the engine /// initialization. -abstract class EmbeddingStrategy with _ContextMenu { +abstract class EmbeddingStrategy { EmbeddingStrategy() { // Initialize code to handle hot-restart (debug only). assert(() { @@ -56,71 +56,3 @@ abstract class EmbeddingStrategy with _ContextMenu { _hotRestartCache?.registerElement(element); } } - -/// Provides functionality to disable and enable the browser's context menu. -mixin _ContextMenu { - /// False when the context menu has been disabled, otherwise true. - bool _contextMenuEnabled = true; - - /// Listener for contextmenu events that prevents the browser's context menu - /// from being shown. - final DomEventListener _disablingContextMenuListener = createDomEventListener((DomEvent event) { - event.preventDefault(); - }); - - /// Disables the browser's context menu for this part of the DOM. - /// - /// By default, when a Flutter web app starts, the context menu is enabled. - /// - /// Can be re-enabled by calling [enableContextMenu]. - /// - /// See also: - /// - /// * [disableContextMenuOn], which is like this but takes the relevant - /// [DomElement] as a parameter. - void disableContextMenu(); - - /// Disables the browser's context menu for the given [DomElement]. - /// - /// See also: - /// - /// * [disableContextMenu], which is like this but is not passed a - /// [DomElement]. - @protected - void disableContextMenuOn(DomEventTarget element) { - if (!_contextMenuEnabled) { - return; - } - - element.addEventListener('contextmenu', _disablingContextMenuListener); - _contextMenuEnabled = false; - } - - /// Enables the browser's context menu for this part of the DOM. - /// - /// By default, when a Flutter web app starts, the context menu is already - /// enabled. Typically, this method would be used after calling - /// [disableContextMenu] to first disable it. - /// - /// See also: - /// - /// * [enableContextMenuOn], which is like this but takes the relevant - /// [DomElement] as a parameter. - void enableContextMenu(); - - /// Enables the browser's context menu for the given [DomElement]. - /// - /// See also: - /// - /// * [enableContextMenu], which is like this but is not passed a - /// [DomElement]. - @protected - void enableContextMenuOn(DomEventTarget element) { - if (_contextMenuEnabled) { - return; - } - - element.removeEventListener('contextmenu', _disablingContextMenuListener); - _contextMenuEnabled = true; - } -} diff --git a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart index d8db4f82f2ac1..b8abc6e2427b7 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart @@ -48,12 +48,6 @@ class FullPageEmbeddingStrategy extends EmbeddingStrategy { registerElementForCleanup(resourceHost); } - @override - void disableContextMenu() => disableContextMenuOn(domWindow); - - @override - void enableContextMenu() => enableContextMenuOn(domWindow); - void _setHostAttribute(String name, String value) { domDocument.body!.setAttribute(name, value); } diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 0dd502def1627..9f65ae6ee07ff 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -17,6 +17,7 @@ import '../engine.dart' show DimensionsProvider, registerHotRestartListener, ren import 'display.dart'; import 'dom.dart'; import 'embedder.dart'; +import 'mouse/context_menu.dart'; import 'mouse/cursor.dart'; import 'navigation/history.dart'; import 'platform_dispatcher.dart'; @@ -36,8 +37,10 @@ const int kImplicitViewId = 0; /// In addition to everything defined in [ui.FlutterView], this class adds /// a few web-specific properties. abstract interface class EngineFlutterView extends ui.FlutterView { - MouseCursor get mouseCursor; DomElement get rootElement; + + MouseCursor get mouseCursor; + ContextMenu get contextMenu; } /// The Web implementation of [ui.SingletonFlutterWindow]. @@ -67,6 +70,9 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow implements EngineFlu @override late final MouseCursor mouseCursor = MouseCursor(rootElement); + @override + late final ContextMenu contextMenu = ContextMenu(rootElement); + @override DomElement get rootElement => flutterViewEmbedder.flutterViewElement; diff --git a/lib/web_ui/test/engine/mouse/context_menu_test.dart b/lib/web_ui/test/engine/mouse/context_menu_test.dart new file mode 100644 index 0000000000000..a432678657927 --- /dev/null +++ b/lib/web_ui/test/engine/mouse/context_menu_test.dart @@ -0,0 +1,104 @@ +// 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 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('$ContextMenu', () { + test('can disable context menu', () { + final DomElement rootViewElement = createDomElement('div'); + final ContextMenu contextMenu = ContextMenu(rootViewElement); + + // When the app starts, contextmenu events are not prevented. + DomEvent event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + + // Disabling the context menu causes contextmenu events to be prevented. + contextMenu.disable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isTrue); + + // Disabling again has no effect. + contextMenu.disable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isTrue); + }); + + test('does not disable context menu outside root view element', () { + final DomElement rootViewElement = createDomElement('div'); + final ContextMenu contextMenu = ContextMenu(rootViewElement); + + contextMenu.disable(); + + // Dispatching on a DOM element outside of target's subtree has no effect. + final DomEvent event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + domDocument.body!.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + }); + + test('can enable context menu after disabling', () { + final DomElement rootViewElement = createDomElement('div'); + final ContextMenu contextMenu = ContextMenu(rootViewElement); + + // When the app starts, contextmenu events are not prevented. + DomEvent event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + + // Disabling the context menu causes contextmenu events to be prevented. + contextMenu.disable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isTrue); + + // Enabling the context menu means that contextmenu events are back to not + // being prevented. + contextMenu.enable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + + // Enabling again has no effect. + contextMenu.enable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + }); + + test('enabling before disabling has no effect', () { + final DomElement rootViewElement = createDomElement('div'); + final ContextMenu contextMenu = ContextMenu(rootViewElement); + + // When the app starts, contextmenu events are not prevented. + DomEvent event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + + // Enabling has no effect. + contextMenu.enable(); + event = createDomEvent('Event', 'contextmenu'); + expect(event.defaultPrevented, isFalse); + rootViewElement.dispatchEvent(event); + expect(event.defaultPrevented, isFalse); + }); + }); +} diff --git a/lib/web_ui/test/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy_test.dart b/lib/web_ui/test/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy_test.dart index 850a2a66a2376..b28fbc3d7fe1c 100644 --- a/lib/web_ui/test/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy_test.dart +++ b/lib/web_ui/test/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy_test.dart @@ -122,60 +122,4 @@ void doTests() { reason: 'Should be injected `nextTo` the passed element.'); }); }); - - group('context menu', () { - setUp(() { - target = createDomElement('this-is-the-target'); - domDocument.body!.append(target); - strategy = CustomElementEmbeddingStrategy(target); - strategy.initialize(); - }); - - tearDown(() { - target.remove(); - }); - - test('disableContextMenu and enableContextMenu can toggle the context menu', () { - // When the app starts, contextmenu events are not prevented. - DomEvent event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - - // Disabling the context menu causes contextmenu events to be prevented. - strategy.disableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isTrue); - - // Disabling again has no effect. - strategy.disableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isTrue); - - // Dispatching on a DOM element outside of target's subtree has no effect. - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - domDocument.body!.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - - // Enabling the context menu means that contextmenu events are back to not - // being prevented. - strategy.enableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - - // Enabling again has no effect. - strategy.enableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - }); - }); } diff --git a/lib/web_ui/test/engine/view_embedder/embedding_strategy/full_page_embedding_strategy_test.dart b/lib/web_ui/test/engine/view_embedder/embedding_strategy/full_page_embedding_strategy_test.dart index 70f2fbd1e92bd..5bf979105e142 100644 --- a/lib/web_ui/test/engine/view_embedder/embedding_strategy/full_page_embedding_strategy_test.dart +++ b/lib/web_ui/test/engine/view_embedder/embedding_strategy/full_page_embedding_strategy_test.dart @@ -130,56 +130,4 @@ void doTests() { reason: 'Should be injected `nextTo` the passed element.'); }); }); - - group('context menu', () { - setUp(() { - strategy = FullPageEmbeddingStrategy(); - strategy.initialize(); - }); - - test('disableContextMenu and enableContextMenu can toggle the context menu', () { - final FullPageEmbeddingStrategy strategy = FullPageEmbeddingStrategy(); - - // When the app starts, contextmenu events are not prevented. - DomEvent event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - - // Disabling the context menu causes contextmenu events to be prevented. - strategy.disableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isTrue); - - // Disabling again has no effect. - strategy.disableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isTrue); - - // Dispatching on the document body is still disabled. - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - domDocument.body!.dispatchEvent(event); - expect(event.defaultPrevented, isTrue); - - // Enabling the context menu means that contextmenu events are back to not - // being prevented. - strategy.enableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - - // Enabling again has no effect. - strategy.enableContextMenu(); - event = createDomEvent('Event', 'contextmenu'); - expect(event.defaultPrevented, isFalse); - target.dispatchEvent(event); - expect(event.defaultPrevented, isFalse); - }); - }); } From c481ab09e06a105042dc5742c2017b1e50a56984 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 20 Sep 2023 13:55:21 -0400 Subject: [PATCH 2/2] sort --- lib/web_ui/lib/src/engine/window.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 9f65ae6ee07ff..9f498654bdd9e 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -37,10 +37,9 @@ const int kImplicitViewId = 0; /// In addition to everything defined in [ui.FlutterView], this class adds /// a few web-specific properties. abstract interface class EngineFlutterView extends ui.FlutterView { - DomElement get rootElement; - - MouseCursor get mouseCursor; ContextMenu get contextMenu; + MouseCursor get mouseCursor; + DomElement get rootElement; } /// The Web implementation of [ui.SingletonFlutterWindow].