From 5af6b898d92432369ce9495e75d75b02af651531 Mon Sep 17 00:00:00 2001 From: Mitchell Cohen Date: Thu, 6 Jan 2022 13:41:28 -0500 Subject: [PATCH] feat: add Substitutions menu roles on macOS (#32024) --- docs/api/menu-item.md | 6 ++++- lib/browser/api/menu-item-roles.ts | 25 ++++++++++++++++++- .../ui/cocoa/electron_menu_controller.mm | 4 +++ spec-main/api-menu-item-spec.ts | 12 ++++++--- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 45727011f43c..bd50f2777719 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -14,7 +14,7 @@ See [`Menu`](menu.md) for examples. * `menuItem` MenuItem * `browserWindow` [BrowserWindow](browser-window.md) | undefined - This will not be defined if no window is open. * `event` [KeyboardEvent](structures/keyboard-event.md) - * `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the + * `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, 'showSubstitutions', 'toggleSmartQuotes', 'toggleSmartDashes', 'toggleTextReplacement', `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the `click` property will be ignored. See [roles](#roles). * `type` string (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. @@ -100,6 +100,10 @@ The following additional roles are available on _macOS_: * `hide` - Map to the `hide` action. * `hideOthers` - Map to the `hideOtherApplications` action. * `unhide` - Map to the `unhideAllApplications` action. +* `showSubstitutions` - Map to the `orderFrontSubstitutionsPanel` action. +* `toggleSmartQuotes` - Map to the `toggleAutomaticQuoteSubstitution` action. +* `toggleSmartDashes` - Map to the `toggleAutomaticDashSubstitution` action. +* `toggleTextReplacement` - Map to the `toggleAutomaticTextReplacement` action. * `startSpeaking` - Map to the `startSpeaking` action. * `stopSpeaking` - Map to the `stopSpeaking` action. * `front` - Map to the `arrangeInFront` action. diff --git a/lib/browser/api/menu-item-roles.ts b/lib/browser/api/menu-item-roles.ts index 34ffe1b6e2ca..08157029dfc3 100644 --- a/lib/browser/api/menu-item-roles.ts +++ b/lib/browser/api/menu-item-roles.ts @@ -5,7 +5,8 @@ const isWindows = process.platform === 'win32'; const isLinux = process.platform === 'linux'; type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' | - 'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' | + 'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | + 'showsubstitutions' | 'togglesmartquotes' | 'togglesmartdashes' | 'toggletextreplacement' | 'startspeaking' | 'stopspeaking' | 'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'togglespellchecker' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu' | 'sharemenu' interface Role { @@ -133,6 +134,18 @@ export const roleList: Record = { clearrecentdocuments: { label: 'Clear Menu' }, + showsubstitutions: { + label: 'Show Substitutions' + }, + togglesmartquotes: { + label: 'Smart Quotes' + }, + togglesmartdashes: { + label: 'Smart Dashes' + }, + toggletextreplacement: { + label: 'Text Replacement' + }, startspeaking: { label: 'Start Speaking' }, @@ -237,6 +250,16 @@ export const roleList: Record = { { role: 'delete' }, { role: 'selectAll' }, { type: 'separator' }, + { + label: 'Substitutions', + submenu: [ + { role: 'showSubstitutions' }, + { type: 'separator' }, + { role: 'toggleSmartQuotes' }, + { role: 'toggleSmartDashes' }, + { role: 'toggleTextReplacement' } + ] + }, { label: 'Speech', submenu: [ diff --git a/shell/browser/ui/cocoa/electron_menu_controller.mm b/shell/browser/ui/cocoa/electron_menu_controller.mm index 2c1462aa058b..d2ffeb77637a 100644 --- a/shell/browser/ui/cocoa/electron_menu_controller.mm +++ b/shell/browser/ui/cocoa/electron_menu_controller.mm @@ -50,6 +50,10 @@ Role kRolesMap[] = { {@selector(delete:), "delete"}, {@selector(pasteAndMatchStyle:), "pasteandmatchstyle"}, {@selector(selectAll:), "selectall"}, + {@selector(orderFrontSubstitutionsPanel:), "showsubstitutions"}, + {@selector(toggleAutomaticQuoteSubstitution:), "togglesmartquotes"}, + {@selector(toggleAutomaticDashSubstitution:), "togglesmartdashes"}, + {@selector(toggleAutomaticTextReplacement:), "toggletextreplacement"}, {@selector(startSpeaking:), "startspeaking"}, {@selector(stopSpeaking:), "stopspeaking"}, {@selector(performMiniaturize:), "minimize"}, diff --git a/spec-main/api-menu-item-spec.ts b/spec-main/api-menu-item-spec.ts index 4a3d501232ef..268c223ec088 100644 --- a/spec-main/api-menu-item-spec.ts +++ b/spec-main/api-menu-item-spec.ts @@ -351,9 +351,15 @@ describe('MenuItems', () => { expect(item.submenu!.items[7].role).to.equal('delete'); expect(item.submenu!.items[8].role).to.equal('selectall'); expect(item.submenu!.items[9].type).to.equal('separator'); - expect(item.submenu!.items[10].label).to.equal('Speech'); - expect(item.submenu!.items[10].submenu!.items[0].role).to.equal('startspeaking'); - expect(item.submenu!.items[10].submenu!.items[1].role).to.equal('stopspeaking'); + expect(item.submenu!.items[10].label).to.equal('Substitutions'); + expect(item.submenu!.items[10].submenu!.items[0].role).to.equal('showsubstitutions'); + expect(item.submenu!.items[10].submenu!.items[1].type).to.equal('separator'); + expect(item.submenu!.items[10].submenu!.items[2].role).to.equal('togglesmartquotes'); + expect(item.submenu!.items[10].submenu!.items[3].role).to.equal('togglesmartdashes'); + expect(item.submenu!.items[10].submenu!.items[4].role).to.equal('toggletextreplacement'); + expect(item.submenu!.items[11].label).to.equal('Speech'); + expect(item.submenu!.items[11].submenu!.items[0].role).to.equal('startspeaking'); + expect(item.submenu!.items[11].submenu!.items[1].role).to.equal('stopspeaking'); } else { expect(item.submenu!.items[6].role).to.equal('delete'); expect(item.submenu!.items[7].type).to.equal('separator');