menu-item.js 2.8 KB

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