Browse Source

Merge pull request #8880 from mst128256/2814

Default menu items for 'Edit' and 'Window' #2814
Kevin Sawicki 8 years ago
parent
commit
57edc28b0d
4 changed files with 130 additions and 1 deletions
  1. 3 0
      docs/api/menu-item.md
  2. 75 0
      lib/browser/api/menu-item-roles.js
  3. 1 1
      lib/browser/api/menu-item.js
  4. 51 0
      spec/api-menu-spec.js

+ 3 - 0
docs/api/menu-item.md

@@ -64,6 +64,9 @@ The `role` property can have following values:
 * `zoomin` - Zoom in the focused page by 10%
 * `zoomout` - Zoom out the focused page by 10%
 
+* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.)
+* `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.)
+
 On macOS `role` can also have following additional values:
 
 * `about` - Map to the `orderFrontStandardAboutPanel` action

+ 75 - 0
lib/browser/api/menu-item-roles.js

@@ -154,6 +154,68 @@ const roles = {
         webContents.setZoomLevel(zoomLevel - 0.5)
       })
     }
+  },
+  // Edit submenu (should fit both Mac & Windows)
+  editMenu: {
+    label: 'Edit',
+    submenu: [
+      {
+        role: 'undo'
+      },
+      {
+        role: 'redo'
+      },
+      {
+        type: 'separator'
+      },
+      {
+        role: 'cut'
+      },
+      {
+        role: 'copy'
+      },
+      {
+        role: 'paste'
+      },
+
+      process.platform === 'darwin' ? {
+        role: 'pasteandmatchstyle'
+      } : null,
+
+      {
+        role: 'delete'
+      },
+
+      process.platform === 'win32' ? {
+        type: 'separator'
+      } : null,
+
+      {
+        role: 'selectall'
+      }
+    ]
+  },
+
+  // Window submenu should be used for Mac only
+  windowMenu: {
+    label: 'Window',
+    submenu: [
+      {
+        role: 'minimize'
+      },
+      {
+        role: 'close'
+      },
+
+      process.platform === 'darwin' ? {
+        type: 'separator'
+      } : null,
+
+      process.platform === 'darwin' ? {
+        role: 'front'
+      } : null
+
+    ]
   }
 }
 
@@ -176,6 +238,19 @@ exports.getDefaultAccelerator = (role) => {
   if (roles.hasOwnProperty(role)) return roles[role].accelerator
 }
 
+exports.getDefaultSubmenu = (role) => {
+  if (!roles.hasOwnProperty(role)) return
+
+  let {submenu} = roles[role]
+
+  // remove null items from within the submenu
+  if (Array.isArray(submenu)) {
+    submenu = submenu.filter((item) => item != null)
+  }
+
+  return submenu
+}
+
 exports.execute = (role, focusedWindow, focusedWebContents) => {
   if (!canExecuteRole(role)) return false
 

+ 1 - 1
lib/browser/api/menu-item.js

@@ -11,7 +11,7 @@ const MenuItem = function (options) {
   for (let key in options) {
     if (!(key in this)) this[key] = options[key]
   }
-
+  this.submenu = this.submenu || roles.getDefaultSubmenu(this.role)
   if (this.submenu != null && this.submenu.constructor !== Menu) {
     this.submenu = Menu.buildFromTemplate(this.submenu)
   }

+ 51 - 0
spec/api-menu-spec.js

@@ -455,6 +455,57 @@ describe('menu module', function () {
     })
   })
 
+  describe('MenuItem editMenu', function () {
+    it('includes a default submenu layout when submenu is empty', function () {
+      var item = new MenuItem({role: 'editMenu'})
+      assert.equal(item.label, 'Edit')
+      assert.equal(item.submenu.items[0].role, 'undo')
+      assert.equal(item.submenu.items[1].role, 'redo')
+      assert.equal(item.submenu.items[2].type, 'separator')
+      assert.equal(item.submenu.items[3].role, 'cut')
+      assert.equal(item.submenu.items[4].role, 'copy')
+      assert.equal(item.submenu.items[5].role, 'paste')
+
+      if (process.platform === 'darwin') {
+        assert.equal(item.submenu.items[6].role, 'pasteandmatchstyle')
+        assert.equal(item.submenu.items[7].role, 'delete')
+        assert.equal(item.submenu.items[8].role, 'selectall')
+      }
+
+      if (process.platform === 'win32') {
+        assert.equal(item.submenu.items[6].role, 'delete')
+        assert.equal(item.submenu.items[7].type, 'separator')
+        assert.equal(item.submenu.items[8].role, 'selectall')
+      }
+    })
+
+    it('overrides default layout when submenu is specified', function () {
+      var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]})
+      assert.equal(item.label, 'Edit')
+      assert.equal(item.submenu.items[0].role, 'close')
+    })
+  })
+
+  describe('MenuItem windowMenu', function () {
+    it('includes a default submenu layout when submenu is empty', function () {
+      var item = new MenuItem({role: 'windowMenu'})
+      assert.equal(item.label, 'Window')
+      assert.equal(item.submenu.items[0].role, 'minimize')
+      assert.equal(item.submenu.items[1].role, 'close')
+
+      if (process.platform === 'darwin') {
+        assert.equal(item.submenu.items[2].type, 'separator')
+        assert.equal(item.submenu.items[3].role, 'front')
+      }
+    })
+
+    it('overrides default layout when submenu is specified', function () {
+      var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]})
+      assert.equal(item.label, 'Window')
+      assert.equal(item.submenu.items[0].role, 'copy')
+    })
+  })
+
   describe('MenuItem with custom properties in constructor', function () {
     it('preserves the custom properties', function () {
       var template = [{