Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Submenus in Context Menu #1947

Open
oprobst88 opened this issue Apr 29, 2020 · 20 comments
Open

Allow Submenus in Context Menu #1947

oprobst88 opened this issue Apr 29, 2020 · 20 comments
Labels
contextmenu feature-request Request for new features or functionality

Comments

@oprobst88
Copy link

Hi

I really like working with the Monaco Editor. I use it in a react app. I've started to use the context menu and using the addAction(descriptor: IActionDescriptor): IDisposable method to add customized entries. It would be really great to be able to add submenus. Otherwise, the context menu gets a bit messy...

Thanks
Oliver

@umesh-timalsina
Copy link

This would really help. Is there a possibility to add a submenu?

@alexdima alexdima added the feature-request Request for new features or functionality label Sep 18, 2020
@y912765390
Copy link

Did you finally achieve it? I also wanted this feature, I tried to modify the source code to achieve the effect but it was difficult for me to introduce that many dependencies outside to achieve the effect of this feature. And if you did, can you tell me what you did in the end

@oprobst88
Copy link
Author

No. In the meantime I've switched to another editor.

@smiles2424
Copy link

Is there a reason you closed this? I still think this is very much an issue I'd like to see resolved.

Its weird because VSCode has nested context menus.

@sukh1495
Copy link

sukh1495 commented Aug 2, 2022

is there any update or any code snippet which can help to add sub actions for a action here like Peek in VS editor or monaco editor playground?

@minzhenyu
Copy link

minzhenyu commented Aug 12, 2022

@alexdima Is there a development plan for this feature?

@dh666
Copy link

dh666 commented Nov 8, 2022

I like the default contextmenu of monaco-editor,I want to customize it.But I can't define the submenu by the method addAction. I'm not sure whether I can use the precondition, Do you have any solutions?

@Ellen0604
Copy link

@hediet Is this issues achievable?

@dh666
Copy link

dh666 commented Apr 24, 2023 via email

@NO-MAP
Copy link

NO-MAP commented May 9, 2023

any update?

@dh666
Copy link

dh666 commented May 9, 2023 via email

@IDovgalyuk
Copy link

React sample that worked for me

import { editor } from 'monaco-editor';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { LinkedList } from 'monaco-editor/esm/vs/base/common/linkedList';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { MenuId, MenuRegistry } from 'monaco-editor/esm/vs/platform/actions/common/actions';

export const setupContextMenuFeature = (editor: editor.IStandaloneCodeEditor) => {
  removeAllMenus();

  addActionWithSubmenus(editor, {
    title: 'Change color',
    context: 'EditorChangeColorContext',
    group: 'edit',
    order: 0,
    actions: [
      {
        id: 'red',
        label: 'Red',
        run: () => console.log('red'),
      },
      {
        id: 'green',
        label: 'Green',
        run: () => console.log('green'),
      },
    ],
  });

  addActionWithSubmenus(editor, {
    title: 'Change coordinates',
    context: 'EditorChangeCoordinatesContext',
    group: 'edit',
    order: 1,
    actions: [
      {
        id: 'wgs',
        label: 'WGS',
        run: () => console.log('wgs'),
      },
      {
        id: 'utc',
        label: 'UTC',
        run: () => console.log('utc'),
      },
      {
        id: 'mgrs',
        label: 'MGRS',
        run: () => console.log('mgrs'),
      },
    ],
  });
};

const addActionWithSubmenus = (
  editor: editor.IStandaloneCodeEditor,
  descriptor: {
    title: string;
    context: string;
    group: string;
    order: number;
    actions: { run: (editor: editor.IStandaloneCodeEditor) => void; label: string; id: string }[];
  }
) => {
  const submenu = new MenuId(descriptor.context);
  const list = new LinkedList();
  MenuRegistry._menuItems.set(submenu, list);

  for (let i = 0; i < descriptor.actions.length; i++) {
    const action = descriptor.actions[i];
    editor.addAction({
      id: action.id,
      label: action.label,
      run: action.run,
      contextMenuOrder: i,
      contextMenuGroupId: descriptor.context,
    });
    const actionId = editor
      .getSupportedActions()
      .find(a => a.label === action.label && a.id.endsWith(action.id))!.id;

    const items = MenuRegistry._menuItems.get(MenuId.EditorContext) as LinkedList;
    const item = popItem(items, actionId);
    if (item) {
      list.push(item);
    }
  }

  MenuRegistry._menuItems.get(MenuId.EditorContext).push({
    group: descriptor.group,
    order: descriptor.order,
    submenu: submenu,
    title: descriptor.title,
  });
};

const popItem = (items: LinkedList, id: string): any => {
  let node = items._first;
  do {
    if (node.element?.command?.id === id) {
      items._remove(node);
      return node.element;
    }
    node = node.next;
  } while (node !== undefined);
};

const removeAllMenus = () => {
  const contextMenuEntry = MenuRegistry._menuItems.get(MenuId.EditorContext);
  let node = contextMenuEntry._first;
  do {
    if (node.element) {
      contextMenuEntry._remove(node);
    }
    node = node.next;
  } while (node !== undefined);
};

image

@thunderstromcd
Copy link

thunderstromcd commented Jun 2, 2023

hi! any update of this issue?

@CharlesHGong
Copy link

Would be great if there are some public API for this

@dh666
Copy link

dh666 commented Sep 6, 2023 via email

@Nyx2022
Copy link

Nyx2022 commented Nov 9, 2023

React sample that worked for me对我有用的反应示例

import { editor } from 'monaco-editor';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { LinkedList } from 'monaco-editor/esm/vs/base/common/linkedList';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { MenuId, MenuRegistry } from 'monaco-editor/esm/vs/platform/actions/common/actions';

export const setupContextMenuFeature = (editor: editor.IStandaloneCodeEditor) => {
  removeAllMenus();

  addActionWithSubmenus(editor, {
    title: 'Change color',
    context: 'EditorChangeColorContext',
    group: 'edit',
    order: 0,
    actions: [
      {
        id: 'red',
        label: 'Red',
        run: () => console.log('red'),
      },
      {
        id: 'green',
        label: 'Green',
        run: () => console.log('green'),
      },
    ],
  });

  addActionWithSubmenus(editor, {
    title: 'Change coordinates',
    context: 'EditorChangeCoordinatesContext',
    group: 'edit',
    order: 1,
    actions: [
      {
        id: 'wgs',
        label: 'WGS',
        run: () => console.log('wgs'),
      },
      {
        id: 'utc',
        label: 'UTC',
        run: () => console.log('utc'),
      },
      {
        id: 'mgrs',
        label: 'MGRS',
        run: () => console.log('mgrs'),
      },
    ],
  });
};

const addActionWithSubmenus = (
  editor: editor.IStandaloneCodeEditor,
  descriptor: {
    title: string;
    context: string;
    group: string;
    order: number;
    actions: { run: (editor: editor.IStandaloneCodeEditor) => void; label: string; id: string }[];
  }
) => {
  const submenu = new MenuId(descriptor.context);
  const list = new LinkedList();
  MenuRegistry._menuItems.set(submenu, list);

  for (let i = 0; i < descriptor.actions.length; i++) {
    const action = descriptor.actions[i];
    editor.addAction({
      id: action.id,
      label: action.label,
      run: action.run,
      contextMenuOrder: i,
      contextMenuGroupId: descriptor.context,
    });
    const actionId = editor
      .getSupportedActions()
      .find(a => a.label === action.label && a.id.endsWith(action.id))!.id;

    const items = MenuRegistry._menuItems.get(MenuId.EditorContext) as LinkedList;
    const item = popItem(items, actionId);
    if (item) {
      list.push(item);
    }
  }

  MenuRegistry._menuItems.get(MenuId.EditorContext).push({
    group: descriptor.group,
    order: descriptor.order,
    submenu: submenu,
    title: descriptor.title,
  });
};

const popItem = (items: LinkedList, id: string): any => {
  let node = items._first;
  do {
    if (node.element?.command?.id === id) {
      items._remove(node);
      return node.element;
    }
    node = node.next;
  } while (node !== undefined);
};

const removeAllMenus = () => {
  const contextMenuEntry = MenuRegistry._menuItems.get(MenuId.EditorContext);
  let node = contextMenuEntry._first;
  do {
    if (node.element) {
      contextMenuEntry._remove(node);
    }
    node = node.next;
  } while (node !== undefined);
};

image

hello,can you tell us how can i call setupContextMenuFeature?or show us a full example to enable subcontextmenu

@dh666
Copy link

dh666 commented Nov 9, 2023 via email

@IDovgalyuk
Copy link

hello,can you tell us how can i call setupContextMenuFeature?or show us a full example to enable subcontextmenu

Sure, here is very basic sample:
https://github.com/IDovgalyuk/monaco-editor-submenu-sample

@Nyx2022
Copy link

Nyx2022 commented Nov 10, 2023

hello,can you tell us how can i call setupContextMenuFeature?or show us a full example to enable subcontextmenu你好,你能告诉我们如何调用 setupContextMenuFeature 吗?或者向我们展示启用子上下文菜单的完整示例

Sure, here is very basic sample:当然,这是非常基本的示例: https://github.com/IDovgalyuk/monaco-editor-submenu-sample

thank you very much

@Nyx2022
Copy link

Nyx2022 commented Nov 12, 2023

hello,can you tell us how can i call setupContextMenuFeature?or show us a full example to enable subcontextmenu

Sure, here is very basic sample

i tried this sample, it's work well, is any body can convert setupContextMenuFeature.ts in src to common js that browser can run ?(without exports) thanh you !because i have no basic for nodejs or typescript development,so any body can help me ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contextmenu feature-request Request for new features or functionality
Projects
None yet
Development

No branches or pull requests