| 
									
										
										
										
											2024-08-22 15:51:20 -05:00
										 |  |  | import { BaseWindow, MenuItem, webContents, Menu as MenuType, MenuItemConstructorOptions } from 'electron/main'; | 
					
						
							| 
									
										
										
										
											2020-07-13 09:58:49 -07:00
										 |  |  | import { sortMenuItems } from '@electron/internal/browser/api/menu-utils'; | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  | import { setApplicationMenuWasSet } from '@electron/internal/browser/default-menu'; | 
					
						
							| 
									
										
										
										
											2016-03-10 11:54:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-22 20:32:45 -07:00
										 |  |  | const bindings = process._linkedBinding('electron_browser_menu'); | 
					
						
							| 
									
										
										
										
											2016-01-11 18:40:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | const { Menu } = bindings as { Menu: typeof MenuType }; | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  | const checked = new WeakMap<MenuItem, boolean>(); | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | let applicationMenu: MenuType | null = null; | 
					
						
							| 
									
										
										
										
											2017-10-23 22:22:39 -04:00
										 |  |  | let groupIdIndex = 0; | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 00:07:39 -04:00
										 |  |  | /* Instance Methods */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | Menu.prototype._init = function () { | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   this.commandsMap = {}; | 
					
						
							|  |  |  |   this.groupsMap = {}; | 
					
						
							|  |  |  |   this.items = []; | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype._isCommandIdChecked = function (id) { | 
					
						
							| 
									
										
										
										
											2020-11-12 00:29:18 +09:00
										 |  |  |   const item = this.commandsMap[id]; | 
					
						
							|  |  |  |   if (!item) return false; | 
					
						
							|  |  |  |   return item.getCheckStatus(); | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype._isCommandIdEnabled = function (id) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |   return this.commandsMap[id] ? this.commandsMap[id].enabled : false; | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | Menu.prototype._shouldCommandIdWorkWhenHidden = function (id) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |   return this.commandsMap[id] ? !!this.commandsMap[id].acceleratorWorksWhenHidden : false; | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | Menu.prototype._isCommandIdVisible = function (id) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |   return this.commandsMap[id] ? this.commandsMap[id].visible : false; | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator) { | 
					
						
							|  |  |  |   const command = this.commandsMap[id]; | 
					
						
							|  |  |  |   if (!command) return; | 
					
						
							|  |  |  |   if (command.accelerator != null) return command.accelerator; | 
					
						
							|  |  |  |   if (useDefaultAccelerator) return command.getDefaultRoleAccelerator(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |   return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false; | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 10:33:06 +09:00
										 |  |  | if (process.platform === 'darwin') { | 
					
						
							|  |  |  |   Menu.prototype._getSharingItemForCommandId = function (id) { | 
					
						
							|  |  |  |     return this.commandsMap[id] ? this.commandsMap[id].sharingItem : null; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | Menu.prototype._executeCommand = function (event, id) { | 
					
						
							|  |  |  |   const command = this.commandsMap[id]; | 
					
						
							|  |  |  |   if (!command) return; | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |   const focusedWindow = BaseWindow.getFocusedWindow(); | 
					
						
							| 
									
										
										
										
											2024-08-22 15:51:20 -05:00
										 |  |  |   command.click(event, focusedWindow, webContents.getFocusedWebContents()); | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype._menuWillShow = function () { | 
					
						
							|  |  |  |   // Ensure radio groups have at least one menu item selected
 | 
					
						
							|  |  |  |   for (const id of Object.keys(this.groupsMap)) { | 
					
						
							|  |  |  |     const found = this.groupsMap[id].find(item => item.checked) || null; | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |     if (!found) checked.set(this.groupsMap[id][0], true); | 
					
						
							| 
									
										
										
										
											2020-04-02 16:07:56 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 15:38:52 -07:00
										 |  |  | Menu.prototype.popup = function (options = {}) { | 
					
						
							| 
									
										
										
										
											2018-03-17 06:31:10 +09:00
										 |  |  |   if (options == null || typeof options !== 'object') { | 
					
						
							|  |  |  |     throw new TypeError('Options must be an object'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-06-29 15:54:06 -07:00
										 |  |  |   let { window, x, y, positioningItem, sourceType, callback } = options; | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-19 20:59:27 -05:00
										 |  |  |   // no callback passed
 | 
					
						
							| 
									
										
										
										
											2018-02-20 11:10:53 -05:00
										 |  |  |   if (!callback || typeof callback !== 'function') callback = () => {}; | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 00:07:39 -04:00
										 |  |  |   // set defaults
 | 
					
						
							| 
									
										
										
										
											2018-02-19 20:59:27 -05:00
										 |  |  |   if (typeof x !== 'number') x = -1; | 
					
						
							|  |  |  |   if (typeof y !== 'number') y = -1; | 
					
						
							| 
									
										
										
										
											2018-02-20 11:28:34 -05:00
										 |  |  |   if (typeof positioningItem !== 'number') positioningItem = -1; | 
					
						
							| 
									
										
										
										
											2023-06-29 15:54:06 -07:00
										 |  |  |   if (typeof sourceType !== 'string' || !sourceType) sourceType = 'mouse'; | 
					
						
							| 
									
										
										
										
											2018-02-19 20:59:27 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-20 18:35:39 -06:00
										 |  |  |   // find which window to use
 | 
					
						
							| 
									
										
										
										
											2020-06-29 16:06:20 +09:00
										 |  |  |   const wins = BaseWindow.getAllWindows(); | 
					
						
							| 
									
										
										
										
											2023-07-24 12:32:54 +02:00
										 |  |  |   if (!wins || !wins.includes(window as any)) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |     window = BaseWindow.getFocusedWindow() as any; | 
					
						
							| 
									
										
										
										
											2018-02-20 18:35:39 -06:00
										 |  |  |     if (!window && wins && wins.length > 0) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |       window = wins[0] as any; | 
					
						
							| 
									
										
										
										
											2018-02-20 18:38:05 -06:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!window) { | 
					
						
							| 
									
										
										
										
											2020-06-29 16:06:20 +09:00
										 |  |  |       throw new Error('Cannot open Menu without a BaseWindow present'); | 
					
						
							| 
									
										
										
										
											2017-12-08 14:36:52 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-29 15:54:06 -07:00
										 |  |  |   this.popupAt(window as unknown as BaseWindow, x, y, positioningItem, sourceType, callback); | 
					
						
							| 
									
										
										
										
											2018-02-20 11:28:34 -05:00
										 |  |  |   return { browserWindow: window, x, y, position: positioningItem }; | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-10-23 12:11:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  | Menu.prototype.closePopup = function (window) { | 
					
						
							| 
									
										
										
										
											2020-06-29 16:06:20 +09:00
										 |  |  |   if (window instanceof BaseWindow) { | 
					
						
							| 
									
										
										
										
											2017-12-21 15:26:32 +09:00
										 |  |  |     this.closePopupAt(window.id); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     // Passing -1 (invalid) would make closePopupAt close the all menu runners
 | 
					
						
							|  |  |  |     // belong to this menu.
 | 
					
						
							|  |  |  |     this.closePopupAt(-1); | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.prototype.getMenuItemById = function (id) { | 
					
						
							|  |  |  |   const items = this.items; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let found = items.find(item => item.id === id) || null; | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |   for (let i = 0; !found && i < items.length; i++) { | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  |     const { submenu } = items[i]; | 
					
						
							|  |  |  |     if (submenu) { | 
					
						
							|  |  |  |       found = submenu.getMenuItemById(id); | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return found; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | Menu.prototype.append = function (item) { | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   return this.insert(this.getItemCount(), item); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-10-23 12:11:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | Menu.prototype.insert = function (pos, item) { | 
					
						
							| 
									
										
										
										
											2020-03-20 08:12:18 -07:00
										 |  |  |   if ((item ? item.constructor : undefined) !== MenuItem) { | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |     throw new TypeError('Invalid item'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-18 07:58:42 -07:00
										 |  |  |   if (pos < 0) { | 
					
						
							|  |  |  |     throw new RangeError(`Position ${pos} cannot be less than 0`); | 
					
						
							|  |  |  |   } else if (pos > this.getItemCount()) { | 
					
						
							|  |  |  |     throw new RangeError(`Position ${pos} cannot be greater than the total MenuItem count`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |   // insert item depending on its type
 | 
					
						
							|  |  |  |   insertItemByType.call(this, item, pos); | 
					
						
							| 
									
										
										
										
											2017-10-23 12:11:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |   // set item properties
 | 
					
						
							| 
									
										
										
										
											2017-10-24 18:52:12 -04:00
										 |  |  |   if (item.sublabel) this.setSublabel(pos, item.sublabel); | 
					
						
							| 
									
										
										
										
											2019-07-11 01:56:22 -07:00
										 |  |  |   if (item.toolTip) this.setToolTip(pos, item.toolTip); | 
					
						
							| 
									
										
										
										
											2017-10-24 18:52:12 -04:00
										 |  |  |   if (item.icon) this.setIcon(pos, item.icon); | 
					
						
							|  |  |  |   if (item.role) this.setRole(pos, item.role); | 
					
						
							| 
									
										
										
										
											2017-10-23 12:11:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-05 08:49:56 -07:00
										 |  |  |   // Make menu accessible to items.
 | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   item.overrideReadOnlyProperty('menu', this); | 
					
						
							| 
									
										
										
										
											2016-01-11 18:40:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  |   // Remember the items.
 | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   this.items.splice(pos, 0, item); | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  |   this.commandsMap[item.commandId] = item; | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | Menu.prototype._callMenuWillShow = function () { | 
					
						
							| 
									
										
										
										
											2018-02-21 01:11:35 +09:00
										 |  |  |   if (this.delegate) this.delegate.menuWillShow(this); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |   for (const item of this.items) { | 
					
						
							| 
									
										
										
										
											2017-10-24 18:52:12 -04:00
										 |  |  |     if (item.submenu) item.submenu._callMenuWillShow(); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 00:07:39 -04:00
										 |  |  | /* Static Methods */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  | Menu.getApplicationMenu = () => applicationMenu; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // set application menu with a preexisting menu
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | Menu.setApplicationMenu = function (menu: MenuType) { | 
					
						
							| 
									
										
										
										
											2017-11-07 19:44:24 -08:00
										 |  |  |   if (menu && menu.constructor !== Menu) { | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  |     throw new TypeError('Invalid menu'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  |   applicationMenu = menu; | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |   setApplicationMenuWasSet(); | 
					
						
							| 
									
										
										
										
											2019-01-15 21:35:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   if (process.platform === 'darwin') { | 
					
						
							| 
									
										
										
										
											2017-10-24 18:52:12 -04:00
										 |  |  |     if (!menu) return; | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |     menu._callMenuWillShow(); | 
					
						
							| 
									
										
										
										
											2017-10-23 20:04:22 -04:00
										 |  |  |     bindings.setApplicationMenu(menu); | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2020-06-29 16:06:20 +09:00
										 |  |  |     const windows = BaseWindow.getAllWindows(); | 
					
						
							| 
									
										
										
										
											2021-05-13 00:32:30 +05:30
										 |  |  |     windows.map(w => w.setMenu(menu)); | 
					
						
							| 
									
										
										
										
											2016-01-11 18:40:23 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-03-24 13:15:04 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-01-11 18:40:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 08:19:21 -07:00
										 |  |  | Menu.buildFromTemplate = function (template) { | 
					
						
							| 
									
										
										
										
											2018-04-24 11:21:26 -04:00
										 |  |  |   if (!Array.isArray(template)) { | 
					
						
							| 
									
										
										
										
											2018-08-17 15:10:14 -05:00
										 |  |  |     throw new TypeError('Invalid template for Menu: Menu template must be an array'); | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-30 08:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-17 15:10:14 -05:00
										 |  |  |   if (!areValidTemplateItems(template)) { | 
					
						
							|  |  |  |     throw new TypeError('Invalid template for MenuItem: must have at least one of label, role or type'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-30 08:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-23 10:39:08 -07:00
										 |  |  |   const sorted = sortTemplate(template); | 
					
						
							|  |  |  |   const filtered = removeExtraSeparators(sorted); | 
					
						
							| 
									
										
										
										
											2018-02-05 12:55:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-10 14:32:03 +01:00
										 |  |  |   const menu = new Menu(); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |   for (const item of filtered) { | 
					
						
							| 
									
										
										
										
											2019-02-06 10:04:40 -08:00
										 |  |  |     if (item instanceof MenuItem) { | 
					
						
							|  |  |  |       menu.append(item); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       menu.append(new MenuItem(item)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return menu; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-01-11 18:40:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 00:07:39 -04:00
										 |  |  | /* Helper Functions */ | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-17 15:10:14 -05:00
										 |  |  | // validate the template against having the wrong attribute
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | function areValidTemplateItems (template: (MenuItemConstructorOptions | MenuItem)[]) { | 
					
						
							| 
									
										
										
										
											2018-08-17 15:10:14 -05:00
										 |  |  |   return template.every(item => | 
					
						
							| 
									
										
										
										
											2019-02-06 10:04:40 -08:00
										 |  |  |     item != null && | 
					
						
							|  |  |  |     typeof item === 'object' && | 
					
						
							| 
									
										
										
										
											2023-06-27 22:57:33 +02:00
										 |  |  |     (Object.hasOwn(item, 'label') || Object.hasOwn(item, 'role') || item.type === 'separator')); | 
					
						
							| 
									
										
										
										
											2018-08-17 15:10:14 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | function sortTemplate (template: (MenuItemConstructorOptions | MenuItem)[]) { | 
					
						
							| 
									
										
										
										
											2018-05-05 09:37:29 -07:00
										 |  |  |   const sorted = sortMenuItems(template); | 
					
						
							| 
									
										
										
										
											2020-03-17 13:17:55 -07:00
										 |  |  |   for (const item of sorted) { | 
					
						
							| 
									
										
										
										
											2018-05-05 09:37:29 -07:00
										 |  |  |     if (Array.isArray(item.submenu)) { | 
					
						
							|  |  |  |       item.submenu = sortTemplate(item.submenu); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return sorted; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  | // Search between separators to find a radio menu item and return its group id
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | function generateGroupId (items: (MenuItemConstructorOptions | MenuItem)[], pos: number) { | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  |   if (pos > 0) { | 
					
						
							| 
									
										
										
										
											2017-10-24 00:24:57 -04:00
										 |  |  |     for (let idx = pos - 1; idx >= 0; idx--) { | 
					
						
							| 
									
										
										
										
											2021-01-29 21:41:59 +01:00
										 |  |  |       if (items[idx].type === 'radio') return (items[idx] as MenuItem).groupId; | 
					
						
							| 
									
										
										
										
											2017-10-24 00:24:57 -04:00
										 |  |  |       if (items[idx].type === 'separator') break; | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } else if (pos < items.length) { | 
					
						
							| 
									
										
										
										
											2017-10-24 00:24:57 -04:00
										 |  |  |     for (let idx = pos; idx <= items.length - 1; idx++) { | 
					
						
							| 
									
										
										
										
											2021-01-29 21:41:59 +01:00
										 |  |  |       if (items[idx].type === 'radio') return (items[idx] as MenuItem).groupId; | 
					
						
							| 
									
										
										
										
											2017-10-24 00:24:57 -04:00
										 |  |  |       if (items[idx].type === 'separator') break; | 
					
						
							| 
									
										
										
										
											2017-10-22 23:57:23 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |   groupIdIndex += 1; | 
					
						
							|  |  |  |   return groupIdIndex; | 
					
						
							| 
									
										
										
										
											2017-10-23 18:35:16 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-23 14:47:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | function removeExtraSeparators (items: (MenuItemConstructorOptions | MenuItem)[]) { | 
					
						
							| 
									
										
										
										
											2018-02-05 12:55:12 -05:00
										 |  |  |   // fold adjacent separators together
 | 
					
						
							| 
									
										
										
										
											2018-05-04 07:59:40 -07:00
										 |  |  |   let ret = items.filter((e, idx, arr) => { | 
					
						
							|  |  |  |     if (e.visible === false) return true; | 
					
						
							|  |  |  |     return e.type !== 'separator' || idx === 0 || arr[idx - 1].type !== 'separator'; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-02-05 12:55:12 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // remove edge separators
 | 
					
						
							| 
									
										
										
										
											2018-05-04 07:59:40 -07:00
										 |  |  |   ret = ret.filter((e, idx, arr) => { | 
					
						
							|  |  |  |     if (e.visible === false) return true; | 
					
						
							|  |  |  |     return e.type !== 'separator' || (idx !== 0 && idx !== arr.length - 1); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2018-02-05 12:55:12 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 13:24:54 -07:00
										 |  |  | function insertItemByType (this: MenuType, item: MenuItem, pos: number) { | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |   const types = { | 
					
						
							| 
									
										
										
										
											2017-10-25 10:17:41 -04:00
										 |  |  |     normal: () => this.insertItem(pos, item.commandId, item.label), | 
					
						
							|  |  |  |     checkbox: () => this.insertCheckItem(pos, item.commandId, item.label), | 
					
						
							|  |  |  |     separator: () => this.insertSeparator(pos), | 
					
						
							|  |  |  |     submenu: () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu), | 
					
						
							|  |  |  |     radio: () => { | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |       // Grouping radio menu items
 | 
					
						
							|  |  |  |       item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)); | 
					
						
							|  |  |  |       if (this.groupsMap[item.groupId] == null) { | 
					
						
							|  |  |  |         this.groupsMap[item.groupId] = []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.groupsMap[item.groupId].push(item); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Setting a radio menu item should flip other items in the group.
 | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |       checked.set(item, item.checked); | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |       Object.defineProperty(item, 'checked', { | 
					
						
							|  |  |  |         enumerable: true, | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |         get: () => checked.get(item), | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |         set: () => { | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |           for (const other of this.groupsMap[item.groupId]) { | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |             if (other !== item) checked.set(other, false); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:36:43 +02:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2021-06-03 07:59:56 +02:00
										 |  |  |           checked.set(item, true); | 
					
						
							| 
									
										
										
										
											2017-10-23 23:46:39 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       this.insertRadioItem(pos, item.commandId, item.label, item.groupId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   types[item.type](); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 22:35:42 -04:00
										 |  |  | module.exports = Menu; |