menu-item.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import * as roles from '@electron/internal/browser/api/menu-item-roles';
  2. import { Menu, BaseWindow, WebContents, KeyboardEvent } from 'electron/main';
  3. let nextCommandId = 0;
  4. const MenuItem = function (this: any, options: any) {
  5. // Preserve extra fields specified by user
  6. for (const key in options) {
  7. if (!(key in this)) this[key] = options[key];
  8. }
  9. if (typeof this.role === 'string' || this.role instanceof String) {
  10. this.role = this.role.toLowerCase();
  11. }
  12. this.submenu = this.submenu || roles.getDefaultSubmenu(this.role);
  13. if (this.submenu != null && this.submenu.constructor !== Menu) {
  14. this.submenu = Menu.buildFromTemplate(this.submenu);
  15. }
  16. if (this.type == null && this.submenu != null) {
  17. this.type = 'submenu';
  18. }
  19. if (this.type === 'submenu' && (this.submenu == null || this.submenu.constructor !== Menu)) {
  20. throw new Error('Invalid submenu');
  21. }
  22. this.overrideReadOnlyProperty('type', roles.getDefaultType(this.role));
  23. this.overrideReadOnlyProperty('role');
  24. this.overrideReadOnlyProperty('accelerator');
  25. this.overrideReadOnlyProperty('icon');
  26. this.overrideReadOnlyProperty('submenu');
  27. this.overrideProperty('label', roles.getDefaultLabel(this.role));
  28. this.overrideProperty('sublabel', '');
  29. this.overrideProperty('toolTip', '');
  30. this.overrideProperty('enabled', true);
  31. this.overrideProperty('visible', true);
  32. this.overrideProperty('checked', false);
  33. this.overrideProperty('acceleratorWorksWhenHidden', true);
  34. this.overrideProperty('registerAccelerator', roles.shouldRegisterAccelerator(this.role));
  35. if (!MenuItem.types.includes(this.type)) {
  36. throw new Error(`Unknown menu item type: ${this.type}`);
  37. }
  38. this.overrideReadOnlyProperty('commandId', ++nextCommandId);
  39. Object.defineProperty(this, 'userAccelerator', {
  40. get: () => {
  41. if (process.platform !== 'darwin') return null;
  42. if (!this.menu) return null;
  43. return this.menu._getUserAcceleratorAt(this.commandId);
  44. },
  45. enumerable: true
  46. });
  47. const click = options.click;
  48. this.click = (event: KeyboardEvent, focusedWindow: BaseWindow, focusedWebContents: WebContents) => {
  49. // Manually flip the checked flags when clicked.
  50. if (!roles.shouldOverrideCheckStatus(this.role) &&
  51. (this.type === 'checkbox' || this.type === 'radio')) {
  52. this.checked = !this.checked;
  53. }
  54. if (!roles.execute(this.role, focusedWindow, focusedWebContents)) {
  55. if (typeof click === 'function') {
  56. click(this, focusedWindow, event);
  57. } else if (typeof this.selector === 'string' && process.platform === 'darwin') {
  58. Menu.sendActionToFirstResponder(this.selector);
  59. }
  60. }
  61. };
  62. };
  63. MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio'];
  64. MenuItem.prototype.getDefaultRoleAccelerator = function () {
  65. return roles.getDefaultAccelerator(this.role);
  66. };
  67. MenuItem.prototype.getCheckStatus = function () {
  68. if (!roles.shouldOverrideCheckStatus(this.role)) return this.checked;
  69. return roles.getCheckStatus(this.role);
  70. };
  71. MenuItem.prototype.overrideProperty = function (name: string, defaultValue: any = null) {
  72. if (this[name] == null) {
  73. this[name] = defaultValue;
  74. }
  75. };
  76. MenuItem.prototype.overrideReadOnlyProperty = function (name: string, defaultValue: any) {
  77. this.overrideProperty(name, defaultValue);
  78. Object.defineProperty(this, name, {
  79. enumerable: true,
  80. writable: false,
  81. value: this[name]
  82. });
  83. };
  84. module.exports = MenuItem;