From 83a65b5d5445f6b913f6990770303020591e7604 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 8 Sep 2021 22:06:57 +0100 Subject: [PATCH 01/17] Load new custom JS file in UBE With this commit, a new JS file is loaded in 'GutenbergWebViewActivity.java'. This new file will have our custom JS, which will load when the UBE is open. --- .../ReactNativeGutenbergBridge/GutenbergWebViewActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index b67cae08e932eb..551fe09e12bf51 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -267,6 +267,9 @@ public void onPageFinished(WebView view, String url) { String injectGutenbergObserver = getFileContentFromAssets("gutenberg-web-single-block/gutenberg-observer.js"); evaluateJavaScript(injectGutenbergObserver); + + String customJS = getFileContentFromAssets("gutenberg-web-single-block/custom-js.js"); + evaluateJavaScript(customJS); } }); } From 4681438d5d418225ffb8af45ea992d06e47dac2f Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 8 Sep 2021 22:16:05 +0100 Subject: [PATCH 02/17] Detect when dropdown menus are active An event listener is added as part of this commit, which will listen for changes in focus in the UBE. In addition, an if statement that checks for the specific elements we're interested in (the toolbars dropdown menus) has been added. This if statement will be fleshed out in future commits. --- .../gutenberg-web-single-block/custom-js.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js b/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js new file mode 100644 index 00000000000000..e7dcb88550850e --- /dev/null +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js @@ -0,0 +1,15 @@ +window.addEventListener( + 'focus', + function () { + if ( + window.activeElement.classList.contains( + 'components-dropdown-menu__menu-item' + ) || + window.activeElement.classList.contains( + 'components-menu-item__button' + ) + ) { + } + }, + true +); From ab5425ef6dfb109de90948e91a312af954be26ea Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 8 Sep 2021 22:21:39 +0100 Subject: [PATCH 03/17] Remove toolbar by resetting text selection The text selection is reset by utilising JavaScript's setBaseAndExtent' method. This has the effect of removing the text selection toolbar when a dropdown menu is pressed, while maintaining the original selection. See here for more details on setBaseAndExtent: https://developer.mozilla.org/en-US/docs/Web/API/Selection/setBaseAndExtent --- .../common/gutenberg-web-single-block/custom-js.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js b/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js index e7dcb88550850e..b12f7a66902aaa 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js @@ -9,6 +9,17 @@ window.addEventListener( 'components-menu-item__button' ) ) { + const selected = document.getSelection(); + const anchorNode = selected.anchorNode; + const anchorOffset = selected.anchorOffset; + const focusNode = selected.focusNode; + const focusOffset = selected.focusOffset; + selected.setBaseAndExtent( + anchorNode, + anchorOffset, + focusNode, + focusOffset + ); } }, true From b8fffc680baf6acb5e097a54bb935033bd795bc6 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Sun, 19 Sep 2021 23:29:08 +0100 Subject: [PATCH 04/17] Rename 'custom-js' file for clarity This PR renames the 'custom-js' file to 'editor-behavior-overrides.js' in an attempt to clarify its purpose. --- .../ReactNativeGutenbergBridge/GutenbergWebViewActivity.java | 4 ++-- .../{custom-js.js => editor-behavior-overrides.js} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename packages/react-native-bridge/common/gutenberg-web-single-block/{custom-js.js => editor-behavior-overrides.js} (99%) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index 551fe09e12bf51..95e0603176495b 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -268,8 +268,8 @@ public void onPageFinished(WebView view, String url) { String injectGutenbergObserver = getFileContentFromAssets("gutenberg-web-single-block/gutenberg-observer.js"); evaluateJavaScript(injectGutenbergObserver); - String customJS = getFileContentFromAssets("gutenberg-web-single-block/custom-js.js"); - evaluateJavaScript(customJS); + String behaviorOverrides = getFileContentFromAssets("gutenberg-web-single-block/editor-behavior-overrides.js"); + evaluateJavaScript(behaviorOverrides); } }); } diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js similarity index 99% rename from packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js rename to packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index b12f7a66902aaa..bc1bfc99cf9e7d 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/custom-js.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -23,4 +23,4 @@ window.addEventListener( } }, true -); +); \ No newline at end of file From b4debe563d87aa49fb979df0b21ebe9a85c678a3 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 20 Sep 2021 10:50:33 +0100 Subject: [PATCH 05/17] Add clarifying comment to new JS file As this is a somewhat hacky and unintuitive fix, this commit adds a clarifying comment along with a link back to the PR for more details. --- .../editor-behavior-overrides.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index bc1bfc99cf9e7d..3b08d6b9673cd2 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -1,3 +1,11 @@ +/* +This is a hacky fix for a text selection quirk in the UBE. +It uses the 'setBaseAndExtent' method to reset the text +selection when certain menu items are tapped. This then +dismisses the text selection toolbar, preventing it from +blocking access to buttons. See PR for further details: +https://github.com/WordPress/gutenberg/pull/34668 +*/ window.addEventListener( 'focus', function () { @@ -23,4 +31,4 @@ window.addEventListener( } }, true -); \ No newline at end of file +); From 7e52ac450e2f7b5b9e1566c58423c57241760249 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 20 Sep 2021 11:18:03 +0100 Subject: [PATCH 06/17] Improve if/else logic by adding 'selected' check The if/else statement was only checking whether specific buttons were active before resetting the text selection. With this commit, an extra check for whether text is actually selected has been added. The code for resetting the selection will therefore only be run when necessary (i.e. it's not necessary if there's no selection). --- .../editor-behavior-overrides.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 3b08d6b9673cd2..d2e71bad026e37 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -9,15 +9,16 @@ https://github.com/WordPress/gutenberg/pull/34668 window.addEventListener( 'focus', function () { + const selected = document.getSelection(); if ( - window.activeElement.classList.contains( + selected && + ( window.activeElement.classList.contains( 'components-dropdown-menu__menu-item' ) || - window.activeElement.classList.contains( - 'components-menu-item__button' - ) + window.activeElement.classList.contains( + 'components-menu-item__button' + ) ) ) { - const selected = document.getSelection(); const anchorNode = selected.anchorNode; const anchorOffset = selected.anchorOffset; const focusNode = selected.focusNode; From 3cd73f2e824f7bb8eeb52020941ec810c2d87a71 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 20 Sep 2021 11:39:29 +0100 Subject: [PATCH 07/17] Access 'activeElement' via 'document' With this commit, changes are made to access the 'activeElement' via 'document', rather than 'window'. Accessing directly via 'window' was not working as expected. It was necessary to still reference 'window' to bypass lint errors. --- .../gutenberg-web-single-block/editor-behavior-overrides.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index d2e71bad026e37..d64a1273412dc1 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -12,10 +12,10 @@ window.addEventListener( const selected = document.getSelection(); if ( selected && - ( window.activeElement.classList.contains( + ( window.document.classList.contains( 'components-dropdown-menu__menu-item' ) || - window.activeElement.classList.contains( + window.document.classList.contains( 'components-menu-item__button' ) ) ) { From 3c4eb820281678f48416e7559d3eb88c1ad135c6 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 20 Sep 2021 11:51:33 +0100 Subject: [PATCH 08/17] Add back 'activeElement' selector This was accidentally removed with the last commit. --- .../gutenberg-web-single-block/editor-behavior-overrides.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index d64a1273412dc1..21899eec852e9b 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -12,10 +12,10 @@ window.addEventListener( const selected = document.getSelection(); if ( selected && - ( window.document.classList.contains( + ( window.document.activeElement.classList.contains( 'components-dropdown-menu__menu-item' ) || - window.document.classList.contains( + window.document.activeElement.classList.contains( 'components-menu-item__button' ) ) ) { From 8c24a8def8b92c9f121d12d4680160c69f311f5e Mon Sep 17 00:00:00 2001 From: Siobhan Date: Mon, 20 Sep 2021 11:59:52 +0100 Subject: [PATCH 09/17] Update CHANGELOG --- packages/react-native-editor/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 9286962065b72e..bd4007ae360e8a 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i --> ## Unreleased +- [*] [Unsupported Block Editor] Fix text selection bug for Android [#34668] - [**] [Embed block] Implement WP embed preview component [#34004] - [*] [Embed block] Fix content disappearing on Android when switching light/dark mode [#34207] - [*] Embed block: Add device's locale to preview content [#33858] From ca63ef9348ce6ef6c217b10c5f284a9b3f565c49 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 29 Sep 2021 00:12:05 +0100 Subject: [PATCH 10/17] Notify Android code when certain menus are tapped Previously the selected text was reset on the JavaScript side of the codebase (using the 'setBaseAndExtent' method). This commit refactors the code so that the Android side of the codebase is notified instead, via the newly created 'hideTextSelectionContextMenu' method. The aim here is to make use of Android's built-in functions around ActionMode, in order to make the code and functionality more stable. --- .../editor-behavior-overrides.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 21899eec852e9b..84081ded61a4e9 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -19,16 +19,7 @@ window.addEventListener( 'components-menu-item__button' ) ) ) { - const anchorNode = selected.anchorNode; - const anchorOffset = selected.anchorOffset; - const focusNode = selected.focusNode; - const focusOffset = selected.focusOffset; - selected.setBaseAndExtent( - anchorNode, - anchorOffset, - focusNode, - focusOffset - ); + window.wpwebkit.hideTextSelectionContextMenu(); } }, true From 3fadc5e058cee5f601f78abf4c4b97281f83bdba Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 29 Sep 2021 00:15:51 +0100 Subject: [PATCH 11/17] Update comment to clarify new code changes --- .../editor-behavior-overrides.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 84081ded61a4e9..773159ee2c50e6 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -1,9 +1,10 @@ /* -This is a hacky fix for a text selection quirk in the UBE. -It uses the 'setBaseAndExtent' method to reset the text -selection when certain menu items are tapped. This then -dismisses the text selection toolbar, preventing it from -blocking access to buttons. See PR for further details: +This is a fix for a text selection quirk in the UBE. +It notifies the Android app to dismiss the text selection +context menu when certain menu items are tapped. This is +done via the 'hideTextSelectionContextMenu' method, which +is sent back to the Android app, where the dismissal is +then handle. See PR for further details: https://github.com/WordPress/gutenberg/pull/34668 */ window.addEventListener( From 35c6414dca503b61a2d4128b1592614089b6295e Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 29 Sep 2021 00:21:11 +0100 Subject: [PATCH 12/17] Hide text selection toolbar when selecting certain items This commit taps into Android's ActionMode to hide the text selection toolbar whenever the 'hideTextSelectionContextMenu' function is called. More specficially, it uses the 'finish' method: https://developer.android.com/reference/android/view/ActionMode#finish() --- .../GutenbergWebViewActivity.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index 95e0603176495b..7150adb33c0fc8 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -4,6 +4,7 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; +import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -85,6 +86,20 @@ private void showTroubleshootingInstructions() { mForegroundViewImage.setVisibility(ImageView.VISIBLE); } + @Override + public void onActionModeStarted(ActionMode mode) { + if (mActionMode == null) { + mActionMode = mode; + } + super.onActionModeStarted(mode); + } + + @Override + public void onActionModeFinished(ActionMode mode) { + mActionMode = null; + super.onActionModeFinished(mode); + } + @SuppressLint("SetJavaScriptEnabled") protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -403,5 +418,12 @@ public void postMessage(String content) { public void gutenbergReady() { GutenbergWebViewActivity.this.runOnUiThread(() -> onGutenbergReady()); } + + @JavascriptInterface + public void hideTextSelectionContextMenu() { + if (mActionMode != null) { + GutenbergWebViewActivity.this.runOnUiThread(() -> GutenbergWebViewActivity.this.mActionMode.finish()); + } + } } } From afbed6928bed78fe125fd5dac81802ac523d2af9 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Wed, 29 Sep 2021 08:48:44 +0100 Subject: [PATCH 13/17] Add missing variable I accidentally ommitted the 'mActionMode' variable from previous commits. --- .../ReactNativeGutenbergBridge/GutenbergWebViewActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index 7150adb33c0fc8..daee68f6d2f8f4 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -50,6 +50,7 @@ public class GutenbergWebViewActivity extends AppCompatActivity { protected TextView mForegroundViewTitle; protected TextView mForegroundViewSubtitle; protected boolean mIsRedirected; + protected ActionMode mActionMode = null; private ProgressBar mProgressBar; private boolean mIsGutenbergReady; From 4f1ca312d1e5a96165d620cbf8c7f1f404bb3b41 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Mon, 4 Oct 2021 16:30:37 +0200 Subject: [PATCH 14/17] Add listener for hide text selection context menu event --- .../GutenbergWebViewActivity.java | 8 +++++++- .../editor-behavior-overrides.js | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index daee68f6d2f8f4..f8cd745fa47686 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -42,6 +42,7 @@ public class GutenbergWebViewActivity extends AppCompatActivity { private static final String INJECT_LOCAL_STORAGE_SCRIPT_TEMPLATE = "localStorage.setItem('WP_DATA_USER_%d','%s')"; private static final String INJECT_CSS_SCRIPT_TEMPLATE = "window.injectCss('%s')"; private static final String INJECT_GET_HTML_POST_CONTENT_SCRIPT = "window.getHTMLPostContent();"; + private static final String INJECT_ON_HIDE_TEXT_SELECTION_CONTEXT_MENU_SCRIPT = "window.onHideTextSelectionContextMenu();"; private static final String JAVA_SCRIPT_INTERFACE_NAME = "wpwebkit"; protected WebView mWebView; @@ -423,7 +424,12 @@ public void gutenbergReady() { @JavascriptInterface public void hideTextSelectionContextMenu() { if (mActionMode != null) { - GutenbergWebViewActivity.this.runOnUiThread(() -> GutenbergWebViewActivity.this.mActionMode.finish()); + GutenbergWebViewActivity.this.runOnUiThread(() -> { + GutenbergWebViewActivity.this.mActionMode.finish(); + + mWebView.evaluateJavascript(INJECT_ON_HIDE_TEXT_SELECTION_CONTEXT_MENU_SCRIPT, + value -> AppLog.e(AppLog.T.EDITOR, value)); + }); } } } diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 773159ee2c50e6..c68cb56cbb533c 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -9,10 +9,11 @@ https://github.com/WordPress/gutenberg/pull/34668 */ window.addEventListener( 'focus', - function () { + function ( event ) { const selected = document.getSelection(); if ( selected && + event.relatedTarget && ( window.document.activeElement.classList.contains( 'components-dropdown-menu__menu-item' ) || @@ -20,8 +21,20 @@ window.addEventListener( 'components-menu-item__button' ) ) ) { + hideTextSelectionContextMenuListener = () => { + event.relatedTarget.click(); + }; window.wpwebkit.hideTextSelectionContextMenu(); } }, true ); + +let hideTextSelectionContextMenuListener; + +window.onHideTextSelectionContextMenu = () => { + if ( hideTextSelectionContextMenuListener ) { + setTimeout( hideTextSelectionContextMenuListener, 0 ); + hideTextSelectionContextMenuListener = null; + } +}; From 3ac0c7a7da16ffa00df93a1677c22c77f52cccd0 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 6 Oct 2021 16:06:26 +0200 Subject: [PATCH 15/17] Listen to click events instead of focus --- .../editor-behavior-overrides.js | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index c68cb56cbb533c..892adadff04bbf 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -8,23 +8,39 @@ then handle. See PR for further details: https://github.com/WordPress/gutenberg/pull/34668 */ window.addEventListener( - 'focus', - function ( event ) { + 'click', + ( event ) => { const selected = document.getSelection(); - if ( - selected && - event.relatedTarget && - ( window.document.activeElement.classList.contains( - 'components-dropdown-menu__menu-item' - ) || - window.document.activeElement.classList.contains( - 'components-menu-item__button' - ) ) - ) { + if ( ! selected || ! selected.toString() ) { + return; + } + + // Check if the event is triggered by a dropdown + // toggle button. + const dropdownToggles = document.querySelectorAll( + '.components-dropdown-menu > button' + ); + let currentToggle; + for ( const node of dropdownToggles.values() ) { + if ( node.contains( event.target ) ) { + currentToggle = node; + break; + } + } + + // Hide text selection context menu when the click + // is triggered by a dropdown toggle. + // + // NOTE: The default behavior of the event is prevented + // because it will be dispatched after the context menu + // is hidden. + if ( currentToggle ) { hideTextSelectionContextMenuListener = () => { - event.relatedTarget.click(); + currentToggle.click(); }; + window.wpwebkit.hideTextSelectionContextMenu(); + event.preventDefault(); } }, true From 2074054c207a6c689e6b29765815221e7ddf09bb Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 6 Oct 2021 16:58:25 +0200 Subject: [PATCH 16/17] Add click listeners for context menu visibility --- .../GutenbergWebViewActivity.java | 12 +++--- .../editor-behavior-overrides.js | 40 +++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java index f8cd745fa47686..ccc3682a2c661e 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergWebViewActivity.java @@ -25,7 +25,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import org.wordpress.android.util.AppLog;; +import org.wordpress.android.util.AppLog; import org.wordpress.mobile.FileUtils; import java.util.ArrayList; @@ -42,7 +42,8 @@ public class GutenbergWebViewActivity extends AppCompatActivity { private static final String INJECT_LOCAL_STORAGE_SCRIPT_TEMPLATE = "localStorage.setItem('WP_DATA_USER_%d','%s')"; private static final String INJECT_CSS_SCRIPT_TEMPLATE = "window.injectCss('%s')"; private static final String INJECT_GET_HTML_POST_CONTENT_SCRIPT = "window.getHTMLPostContent();"; - private static final String INJECT_ON_HIDE_TEXT_SELECTION_CONTEXT_MENU_SCRIPT = "window.onHideTextSelectionContextMenu();"; + private static final String INJECT_ON_SHOW_CONTEXT_MENU_SCRIPT = "window.onShowContextMenu();"; + private static final String INJECT_ON_HIDE_CONTEXT_MENU_SCRIPT = "window.onHideContextMenu();"; private static final String JAVA_SCRIPT_INTERFACE_NAME = "wpwebkit"; protected WebView mWebView; @@ -93,12 +94,16 @@ public void onActionModeStarted(ActionMode mode) { if (mActionMode == null) { mActionMode = mode; } + mWebView.evaluateJavascript(INJECT_ON_SHOW_CONTEXT_MENU_SCRIPT, + value -> AppLog.e(AppLog.T.EDITOR, value)); super.onActionModeStarted(mode); } @Override public void onActionModeFinished(ActionMode mode) { mActionMode = null; + mWebView.evaluateJavascript(INJECT_ON_HIDE_CONTEXT_MENU_SCRIPT, + value -> AppLog.e(AppLog.T.EDITOR, value)); super.onActionModeFinished(mode); } @@ -426,9 +431,6 @@ public void hideTextSelectionContextMenu() { if (mActionMode != null) { GutenbergWebViewActivity.this.runOnUiThread(() -> { GutenbergWebViewActivity.this.mActionMode.finish(); - - mWebView.evaluateJavascript(INJECT_ON_HIDE_TEXT_SELECTION_CONTEXT_MENU_SCRIPT, - value -> AppLog.e(AppLog.T.EDITOR, value)); }); } } diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 892adadff04bbf..8ab5f15f742019 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -1,3 +1,18 @@ +// Listeners for native context menu visibility changes +let isContextMenuVisible = false; +const hideContextMenuListeners = []; + +window.onShowContextMenu = () => { + isContextMenuVisible = true; +}; +window.onHideContextMenu = () => { + isContextMenuVisible = false; + while ( hideContextMenuListeners.length > 0 ) { + const listener = hideContextMenuListeners.pop(); + listener(); + } +}; + /* This is a fix for a text selection quirk in the UBE. It notifies the Android app to dismiss the text selection @@ -11,7 +26,7 @@ window.addEventListener( 'click', ( event ) => { const selected = document.getSelection(); - if ( ! selected || ! selected.toString() ) { + if ( ! isContextMenuVisible || ! selected || ! selected.toString() ) { return; } @@ -31,26 +46,17 @@ window.addEventListener( // Hide text selection context menu when the click // is triggered by a dropdown toggle. // - // NOTE: The default behavior of the event is prevented - // because it will be dispatched after the context menu + // NOTE: The event propagation is prevented because + // it will be dispatched after the context menu // is hidden. if ( currentToggle ) { - hideTextSelectionContextMenuListener = () => { - currentToggle.click(); - }; - + event.stopPropagation(); + hideContextMenuListeners.push( () => + // setTimeout( () => currentToggle.click(), 500 ) + currentToggle.click() + ); window.wpwebkit.hideTextSelectionContextMenu(); - event.preventDefault(); } }, true ); - -let hideTextSelectionContextMenuListener; - -window.onHideTextSelectionContextMenu = () => { - if ( hideTextSelectionContextMenuListener ) { - setTimeout( hideTextSelectionContextMenuListener, 0 ); - hideTextSelectionContextMenuListener = null; - } -}; From 1456ae9313da0d869f3b51c9a3fbb777ee301ba3 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 8 Oct 2021 16:48:47 +0200 Subject: [PATCH 17/17] Remove commented line --- .../gutenberg-web-single-block/editor-behavior-overrides.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js index 8ab5f15f742019..a456549b9501ab 100644 --- a/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js +++ b/packages/react-native-bridge/common/gutenberg-web-single-block/editor-behavior-overrides.js @@ -51,10 +51,7 @@ window.addEventListener( // is hidden. if ( currentToggle ) { event.stopPropagation(); - hideContextMenuListeners.push( () => - // setTimeout( () => currentToggle.click(), 500 ) - currentToggle.click() - ); + hideContextMenuListeners.push( () => currentToggle.click() ); window.wpwebkit.hideTextSelectionContextMenu(); } },