From c096a8065d0935b774dbc7e76d41aa657dfb399e Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 12 Feb 2020 16:34:11 -0500 Subject: [PATCH 01/14] Add support for disabling JupyterLab's context menu Fixes #7670 by disabling JuptyrLab's context menu on all elements which are children of elements with the `data-native-context-menu` property. --- docs/source/developer/extension_points.rst | 16 ++++++++++++++++ packages/application/src/frontend.ts | 22 +++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index f7ab6d9aa345..03268a6291bd 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -125,6 +125,22 @@ right-clicks on a DOM element matching ``.jp-Notebook`` (that is to say, a noteb The selector can be any valid CSS selector, and may target your own UI elements, or existing ones. A list of CSS selectors currently used by context menu commands is given in :ref:`css-selectors`. +If you don't want JupyterLab's custom context menu to appear for your element, because you have +your own right click behavior that you want to trigger, you can add the `native-context-menu` data attribute +to any node to have it and it's children not trigger it. + +For example, if you are building a custom React element, it would like this: + +.. code:: typescript + + function MyElement(props: {}) { + return ( +
+

Hi

+

{console.log("right clicked")}}>There

+
+ ) + } .. _copy_shareable_link: diff --git a/packages/application/src/frontend.ts b/packages/application/src/frontend.ts index b615b0459a6c..cc9eb18a144e 100644 --- a/packages/application/src/frontend.ts +++ b/packages/application/src/frontend.ts @@ -150,7 +150,10 @@ export abstract class JupyterFrontEnd< */ protected evtContextMenu(event: MouseEvent): void { this._contextMenuEvent = event; - if (event.shiftKey) { + if ( + event.shiftKey || + Private.elementChildOfNativeContextMenu(event.target as HTMLElement) + ) { return; } const opened = this.contextMenu.open(event); @@ -349,4 +352,21 @@ namespace Private { * ersatz command. */ export const CONTEXT_MENU_INFO = '__internal:context-menu-info'; + + /** + * Returns whether the element is itself, or a child of, an element with the `native-context-menu` data attribute. + */ + export function elementChildOfNativeContextMenu({ + dataset, + parentElement + }: HTMLElement): boolean { + // Any value of `native-context-menu` data property means its active. + if (typeof dataset.nativeContextMenu === 'string') { + return true; + } + if (parentElement) { + return elementChildOfNativeContextMenu(parentElement); + } + return false; + } } From 6744b0c03451d116ce770772b83ee59ce5a46c2a Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 12 Feb 2020 17:03:18 -0500 Subject: [PATCH 02/14] Rename to `data-jp-suppress-context-menu` This now matches lumino keyboard shortcuts disable data attribute --- docs/source/developer/extension_points.rst | 4 ++-- packages/application/src/frontend.ts | 12 ++++++------ packages/json-extension/src/component.tsx | 9 ++++++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index 03268a6291bd..f55728ec7889 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -126,7 +126,7 @@ The selector can be any valid CSS selector, and may target your own UI elements, A list of CSS selectors currently used by context menu commands is given in :ref:`css-selectors`. If you don't want JupyterLab's custom context menu to appear for your element, because you have -your own right click behavior that you want to trigger, you can add the `native-context-menu` data attribute +your own right click behavior that you want to trigger, you can add the `jp-suppress-context-menu` data attribute to any node to have it and it's children not trigger it. For example, if you are building a custom React element, it would like this: @@ -135,7 +135,7 @@ For example, if you are building a custom React element, it would like this: function MyElement(props: {}) { return ( -
+

Hi

{console.log("right clicked")}}>There

diff --git a/packages/application/src/frontend.ts b/packages/application/src/frontend.ts index cc9eb18a144e..2e48c6080967 100644 --- a/packages/application/src/frontend.ts +++ b/packages/application/src/frontend.ts @@ -152,7 +152,7 @@ export abstract class JupyterFrontEnd< this._contextMenuEvent = event; if ( event.shiftKey || - Private.elementChildOfNativeContextMenu(event.target as HTMLElement) + Private.suppressContextMenu(event.target as HTMLElement) ) { return; } @@ -354,18 +354,18 @@ namespace Private { export const CONTEXT_MENU_INFO = '__internal:context-menu-info'; /** - * Returns whether the element is itself, or a child of, an element with the `native-context-menu` data attribute. + * Returns whether the element is itself, or a child of, an element with the `jp-suppress-context-menu` data attribute. */ - export function elementChildOfNativeContextMenu({ + export function suppressContextMenu({ dataset, parentElement }: HTMLElement): boolean { - // Any value of `native-context-menu` data property means its active. - if (typeof dataset.nativeContextMenu === 'string') { + // Any value of data property means its active. + if (typeof dataset.jpSuppressContextMenu === 'string') { return true; } if (parentElement) { - return elementChildOfNativeContextMenu(parentElement); + return suppressContextMenu(parentElement); } return false; } diff --git a/packages/json-extension/src/component.tsx b/packages/json-extension/src/component.tsx index 46cee3b70edc..12bc476f5091 100644 --- a/packages/json-extension/src/component.tsx +++ b/packages/json-extension/src/component.tsx @@ -51,7 +51,14 @@ export class Component extends React.Component { ? filterPaths(data, this.state.filter, [root]) : [root]; return ( -
+
+
{ + console.log('right clicked'); + }} + > +

HI!!!

+
Date: Wed, 12 Feb 2020 17:05:24 -0500 Subject: [PATCH 03/14] Forgot data in docs --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index f55728ec7889..da8acf979eee 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -126,7 +126,7 @@ The selector can be any valid CSS selector, and may target your own UI elements, A list of CSS selectors currently used by context menu commands is given in :ref:`css-selectors`. If you don't want JupyterLab's custom context menu to appear for your element, because you have -your own right click behavior that you want to trigger, you can add the `jp-suppress-context-menu` data attribute +your own right click behavior that you want to trigger, you can add the `data-jp-suppress-context-menu` data attribute to any node to have it and it's children not trigger it. For example, if you are building a custom React element, it would like this: From d8dd2dea420a6e132d6596ecf17c87d163de097f Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 12 Feb 2020 17:07:31 -0500 Subject: [PATCH 04/14] Revert accidental commit of JSON example --- packages/json-extension/src/component.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/json-extension/src/component.tsx b/packages/json-extension/src/component.tsx index 12bc476f5091..46cee3b70edc 100644 --- a/packages/json-extension/src/component.tsx +++ b/packages/json-extension/src/component.tsx @@ -51,14 +51,7 @@ export class Component extends React.Component { ? filterPaths(data, this.state.filter, [root]) : [root]; return ( -
-
{ - console.log('right clicked'); - }} - > -

HI!!!

-
+
Date: Wed, 12 Feb 2020 17:17:49 -0500 Subject: [PATCH 05/14] Update docs/source/developer/extension_points.rst Co-Authored-By: Jason Grout --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index da8acf979eee..2c1323ff6adf 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -127,7 +127,7 @@ A list of CSS selectors currently used by context menu commands is given in :ref If you don't want JupyterLab's custom context menu to appear for your element, because you have your own right click behavior that you want to trigger, you can add the `data-jp-suppress-context-menu` data attribute -to any node to have it and it's children not trigger it. +to any node to have it and its children not trigger it. For example, if you are building a custom React element, it would like this: From a319e33b5250a487b6b6eb140b7c93e0bd5f8617 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 12 Feb 2020 17:18:23 -0500 Subject: [PATCH 06/14] Update docs/source/developer/extension_points.rst Co-Authored-By: Jason Grout --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index 2c1323ff6adf..474e5a7d2d0e 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -129,7 +129,7 @@ If you don't want JupyterLab's custom context menu to appear for your element, b your own right click behavior that you want to trigger, you can add the `data-jp-suppress-context-menu` data attribute to any node to have it and its children not trigger it. -For example, if you are building a custom React element, it would like this: +For example, if you are building a custom React element, it would look like this: .. code:: typescript From bfe2739613833c01a95c17d6adf065c89b9f58a3 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 12 Feb 2020 18:11:01 -0500 Subject: [PATCH 07/14] Switch to loop instead of recursion --- packages/application/src/frontend.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/application/src/frontend.ts b/packages/application/src/frontend.ts index 2e48c6080967..87bb1512426c 100644 --- a/packages/application/src/frontend.ts +++ b/packages/application/src/frontend.ts @@ -356,16 +356,12 @@ namespace Private { /** * Returns whether the element is itself, or a child of, an element with the `jp-suppress-context-menu` data attribute. */ - export function suppressContextMenu({ - dataset, - parentElement - }: HTMLElement): boolean { - // Any value of data property means its active. - if (typeof dataset.jpSuppressContextMenu === 'string') { - return true; - } - if (parentElement) { - return suppressContextMenu(parentElement); + export function suppressContextMenu(element: HTMLElement | null): boolean { + while (element) { + if (typeof element.dataset.jpSuppressContextMenu === 'string') { + return true; + } + element = element.parentElement; } return false; } From be0a811ee49ee7fd80f6c95cd30b27155c6d650c Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Sat, 15 Feb 2020 10:39:44 -0500 Subject: [PATCH 08/14] Update extension_points.rst --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index 474e5a7d2d0e..f500e24f7beb 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -131,7 +131,7 @@ to any node to have it and its children not trigger it. For example, if you are building a custom React element, it would look like this: -.. code:: typescript +.. code:: jsx function MyElement(props: {}) { return ( From f0c90662f27229019bd5750304ae207d7dbff434 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Sat, 15 Feb 2020 12:02:19 -0500 Subject: [PATCH 09/14] Add JSX lexer --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0ce51b9a5d28..f16504df5693 100644 --- a/setup.py +++ b/setup.py @@ -153,7 +153,8 @@ def run(self): 'sphinx', 'recommonmark', 'sphinx_rtd_theme', - 'sphinx-copybutton' + 'sphinx-copybutton', + 'jsx-lexer' ], } From f19b142a8c0ac9608e9b7a89b7a07e0bf136e60f Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Mon, 17 Feb 2020 16:44:54 -0500 Subject: [PATCH 10/14] Update setup.py --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index f16504df5693..0ce51b9a5d28 100644 --- a/setup.py +++ b/setup.py @@ -153,8 +153,7 @@ def run(self): 'sphinx', 'recommonmark', 'sphinx_rtd_theme', - 'sphinx-copybutton', - 'jsx-lexer' + 'sphinx-copybutton' ], } From 5addc5e1b89c4d440ef27f0d1f3e6c6b562ba540 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Mon, 17 Feb 2020 16:46:47 -0500 Subject: [PATCH 11/14] Remove jsx code block --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index f500e24f7beb..dd1114e5f993 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -131,7 +131,7 @@ to any node to have it and its children not trigger it. For example, if you are building a custom React element, it would look like this: -.. code:: jsx +.. code:: function MyElement(props: {}) { return ( From 3c04478c56a106c3eca9e91dd1d5b092845384de Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Tue, 25 Feb 2020 12:24:07 -0500 Subject: [PATCH 12/14] Fix typo in data attribute in docs --- docs/source/developer/extension_points.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/developer/extension_points.rst b/docs/source/developer/extension_points.rst index dd1114e5f993..93838f03086a 100644 --- a/docs/source/developer/extension_points.rst +++ b/docs/source/developer/extension_points.rst @@ -135,7 +135,7 @@ For example, if you are building a custom React element, it would look like this function MyElement(props: {}) { return ( -
+

Hi

{console.log("right clicked")}}>There

From 183d538eb9673723cc70d6a92f2cfab04c5ec71b Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Tue, 25 Feb 2020 12:24:23 -0500 Subject: [PATCH 13/14] Use `closest` method instead of looping --- packages/application/src/frontend.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/application/src/frontend.ts b/packages/application/src/frontend.ts index 87bb1512426c..4ea9838f9be0 100644 --- a/packages/application/src/frontend.ts +++ b/packages/application/src/frontend.ts @@ -356,13 +356,7 @@ namespace Private { /** * Returns whether the element is itself, or a child of, an element with the `jp-suppress-context-menu` data attribute. */ - export function suppressContextMenu(element: HTMLElement | null): boolean { - while (element) { - if (typeof element.dataset.jpSuppressContextMenu === 'string') { - return true; - } - element = element.parentElement; - } - return false; + export function suppressContextMenu(element: HTMLElement): boolean { + return element.closest('[data-jp-suppress-context-menu]') !== null; } } From b99a10eeb2e0ee0aff44cef9df783b2a25bf79bd Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Tue, 17 Mar 2020 11:26:41 -0400 Subject: [PATCH 14/14] ci bump