5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 19:50:15 +08:00

[v2] Add smart default context-menu functionality (backported from v3) (#2748)

* [v2] Add smart default context-menu functionality (backported from v3)

* Update changelog
This commit is contained in:
Mohamed Gharib 2023-06-27 23:35:02 +03:00 committed by GitHub
parent cdbe77a0fc
commit 8acbdc246c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 9 deletions

View File

@ -230,7 +230,7 @@ typedef void (^schemeTaskCaller)(id<WKURLSchemeTask>);
} else if (!self.defaultContextMenu) { } else if (!self.defaultContextMenu) {
// Disable default context menus // Disable default context menus
WKUserScript *initScript = [WKUserScript new]; WKUserScript *initScript = [WKUserScript new];
[initScript initWithSource:@"window.wails.flags.disableWailsDefaultContextMenu = true;" [initScript initWithSource:@"window.wails.flags.disableDefaultContextMenu = true;"
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:false]; forMainFrameOnly:false];
[userContentController addUserScript:initScript]; [userContentController addUserScript:initScript];

View File

@ -0,0 +1,50 @@
/*
--default-contextmenu: auto; (default) will show the default context menu if contentEditable is true OR text has been selected OR element is input or textarea
--default-contextmenu: show; will always show the default context menu
--default-contextmenu: hide; will always hide the default context menu
This rule is inherited like normal CSS rules, so nesting works as expected
*/
export function processDefaultContextMenu(event) {
// Process default context menu
const element = event.target;
const computedStyle = window.getComputedStyle(element);
const defaultContextMenuAction = computedStyle.getPropertyValue("--default-contextmenu").trim();
switch (defaultContextMenuAction) {
case "show":
return;
case "hide":
event.preventDefault();
return;
default:
// Check if contentEditable is true
if (element.isContentEditable) {
return;
}
// Check if text has been selected and action is on the selected elements
const selection = window.getSelection();
const hasSelection = (selection.toString().length > 0)
if (hasSelection) {
for (let i = 0; i < selection.rangeCount; i++) {
const range = selection.getRangeAt(i);
const rects = range.getClientRects();
for (let j = 0; j < rects.length; j++) {
const rect = rects[j];
if (document.elementFromPoint(rect.left, rect.top) === element) {
return;
}
}
}
}
// Check if tagname is input or textarea
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA") {
if (hasSelection || (!element.readOnly && !element.disabled)) {
return;
}
}
// hide default context menu
event.preventDefault();
}
}

View File

@ -16,6 +16,7 @@ import * as Window from "./window";
import * as Screen from "./screen"; import * as Screen from "./screen";
import * as Browser from "./browser"; import * as Browser from "./browser";
import * as Clipboard from "./clipboard"; import * as Clipboard from "./clipboard";
import * as ContextMenu from "./contextmenu";
export function Quit() { export function Quit() {
@ -61,7 +62,7 @@ window.wails = {
callbacks, callbacks,
flags: { flags: {
disableScrollbarDrag: false, disableScrollbarDrag: false,
disableWailsDefaultContextMenu: false, disableDefaultContextMenu: false,
enableResize: false, enableResize: false,
defaultCursor: null, defaultCursor: null,
borderThickness: 6, borderThickness: 6,
@ -187,8 +188,13 @@ window.addEventListener('mousemove', function (e) {
// Setup context menu hook // Setup context menu hook
window.addEventListener('contextmenu', function (e) { window.addEventListener('contextmenu', function (e) {
if (window.wails.flags.disableWailsDefaultContextMenu) { // always show the contextmenu in debug & dev
if (DEBUG) return;
if (window.wails.flags.disableDefaultContextMenu) {
e.preventDefault(); e.preventDefault();
} else {
ContextMenu.processDefaultContextMenu(e);
} }
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -420,8 +420,28 @@ Type: `string`
### EnableDefaultContextMenu ### EnableDefaultContextMenu
EnableDefaultContextMenu enables the browser's default context-menu in production (Without the devtools inspector). EnableDefaultContextMenu enables the browser's default context-menu in production.
This menu is already enabled in development, as well as in debug builds and production builds with the `-devtools` flag.
By default, the browser's default context-menu is only available in development and in a `-debug` or `-devtools` [build](../reference/cli.mdx#build) along with the devtools inspector, Using this option you can enable the default context-menu in `production` while the devtools inspector won't be available unless the `-devtools` build flag is used.
When this option is enabled, by default the context-menu will only be shown for text contexts (where Cut/Copy/Paste is needed), to override this behavior, you can use the CSS property `--default-contextmenu` on any HTML element (including the `body`) with the following values :
| CSS Style | Behavior |
|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| `--default-contextmenu: auto;` | (**default**) will show the default context menu only if :<br/> contentEditable is true OR text has been selected OR element is input or textarea |
| `--default-contextmenu: show;` | will always show the default context menu |
| `--default-contextmenu: hide;` | will always hide the default context menu |
This rule is inherited like any normal CSS rule, so nesting works as expected.
:::note
This filtering functionality is only enabled in production, so in development and in debug build, the full context-menu is always available everywhere.
:::
:::warning
This filtering functionality is NOT a security measure, the developer should expect that the full context-menu could be leaked anytime which could contain commands like (Download image, Reload, Save webpage), if this is a concern, the developer SHOULD NOT enable the default context-menu.
:::
Name: EnableDefaultContextMenu<br/> Name: EnableDefaultContextMenu<br/>
Type: `bool` Type: `bool`

View File

@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `-devtools` production build flag. Added by @mmghv in [PR](https://github.com/wailsapp/wails/pull/2725) - Added `-devtools` production build flag. Added by @mmghv in [PR](https://github.com/wailsapp/wails/pull/2725)
- Added `EnableDefaultContextMenu` option to allow enabling the browser's default context-menu in production . Added by @mmghv in [PR](https://github.com/wailsapp/wails/pull/2733) - Added `EnableDefaultContextMenu` option to allow enabling the browser's default context-menu in production . Added by @mmghv in [PR](https://github.com/wailsapp/wails/pull/2733)
- Added smart functionality for the default context-menu in production with CSS styles to control it. Added by @mmghv in [PR](https://github.com/wailsapp/wails/pull/2748)
### Changed ### Changed