Browse Source

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.
Saul Shanabrook 5 years ago
parent
commit
c096a8065d
2 changed files with 37 additions and 1 deletions
  1. 16 0
      docs/source/developer/extension_points.rst
  2. 21 1
      packages/application/src/frontend.ts

+ 16 - 0
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 (
+        <div data-native-context-menu>
+          <p>Hi</p>
+          <p onContextMenu={() => {console.log("right clicked")}}>There</p>
+        </div>
+      )
+    }
 
 .. _copy_shareable_link:
 

+ 21 - 1
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;
+  }
 }