From 1848e3f6583dfc994283509ab0b2b38ba682a3dc Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Mon, 24 Feb 2020 00:55:06 -0800 Subject: [PATCH] feat: Add OtherItemsProxy TouchBar item (#22270) * feat: Add OtherItemsProxy touchbar item * review! --- docs/api/touch-bar-other-items-proxy.md | 12 ++++ docs/api/touch-bar.md | 4 ++ filenames.auto.gni | 1 + lib/browser/api/touch-bar.js | 23 ++++++- shell/browser/ui/cocoa/electron_touch_bar.mm | 8 ++- spec-main/api-touch-bar-spec.ts | 64 +++++++++++--------- 6 files changed, 83 insertions(+), 29 deletions(-) create mode 100644 docs/api/touch-bar-other-items-proxy.md diff --git a/docs/api/touch-bar-other-items-proxy.md b/docs/api/touch-bar-other-items-proxy.md new file mode 100644 index 0000000000..a58b2ed6f3 --- /dev/null +++ b/docs/api/touch-bar-other-items-proxy.md @@ -0,0 +1,12 @@ +## Class: TouchBarOtherItemsProxy + +> Instantiates a special "other items proxy", which nests TouchBar elements inherited +> from Chromium at the space indicated by the proxy. By default, this proxy is added +> to each TouchBar at the end of the input. For more information, see the AppKit docs on +> [NSTouchBarItemIdentifierOtherItemsProxy](https://developer.apple.com/documentation/appkit/nstouchbaritemidentifierotheritemsproxy) +> +> Note: Only one instance of this class can be added per TouchBar. + +Process: [Main](../tutorial/application-architecture.md#main-and-renderer-processes) + +### `new TouchBarOtherItemsProxy()` _Experimental_ diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 5764ebc6a8..79c575dab1 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -58,6 +58,10 @@ A [`typeof TouchBarSlider`](./touch-bar-slider.md) reference to the `TouchBarSli A [`typeof TouchBarSpacer`](./touch-bar-spacer.md) reference to the `TouchBarSpacer` class. +#### `TouchBarOtherItemsProxy` + +A [`typeof TouchBarOtherItemsProxy`](./touch-bar-other-items-proxy.md) reference to the `TouchBarOtherItemsProxy` class. + ### Instance Properties The following properties are available on instances of `TouchBar`: diff --git a/filenames.auto.gni b/filenames.auto.gni index 6eacd50346..feac6c6e81 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -56,6 +56,7 @@ auto_filenames = { "docs/api/touch-bar-color-picker.md", "docs/api/touch-bar-group.md", "docs/api/touch-bar-label.md", + "docs/api/touch-bar-other-items-proxy.md", "docs/api/touch-bar-popover.md", "docs/api/touch-bar-scrubber.md", "docs/api/touch-bar-segmented-control.md", diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js index c0defb7119..6220cd70e6 100644 --- a/lib/browser/api/touch-bar.js +++ b/lib/browser/api/touch-bar.js @@ -51,13 +51,27 @@ class TouchBar extends EventEmitter { item.child.ordereredItems.forEach(registerItem) } } + + let hasOtherItemsProxy = false items.forEach((item) => { if (!(item instanceof TouchBarItem)) { throw new Error('Each item must be an instance of TouchBarItem') } + + if (item.type === 'other_items_proxy') { + if (!hasOtherItemsProxy) { + hasOtherItemsProxy = true + } else { + throw new Error('Must only have one OtherItemsProxy per TouchBar') + } + } + }) + + // register in separate loop after all items are validated + for (const item of items) { this.ordereredItems.push(item) registerItem(item) - }) + } } set escapeItem (item) { @@ -334,4 +348,11 @@ TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem { } } +TouchBar.TouchBarOtherItemsProxy = class TouchBarOtherItemsProxy extends TouchBarItem { + constructor (config) { + super() + this._addImmutableProperty('type', 'other_items_proxy') + } +} + module.exports = TouchBar diff --git a/shell/browser/ui/cocoa/electron_touch_bar.mm b/shell/browser/ui/cocoa/electron_touch_bar.mm index ff11498659..0810565eca 100644 --- a/shell/browser/ui/cocoa/electron_touch_bar.mm +++ b/shell/browser/ui/cocoa/electron_touch_bar.mm @@ -64,6 +64,8 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; (const std::vector&)dicts { NSMutableArray* identifiers = [NSMutableArray array]; + bool has_other_items_proxy = false; + if (@available(macOS 10.12.2, *)) { for (const auto& item : dicts) { std::string type; @@ -80,6 +82,9 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; } else { identifier = NSTouchBarItemIdentifierFixedSpaceSmall; } + } else if (type == "other_items_proxy") { + identifier = NSTouchBarItemIdentifierOtherItemsProxy; + has_other_items_proxy = true; } else { identifier = [self identifierFromID:item_id type:type]; } @@ -90,7 +95,8 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item"; } } } - [identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy]; + if (!has_other_items_proxy) + [identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy]; } return identifiers; diff --git a/spec-main/api-touch-bar-spec.ts b/spec-main/api-touch-bar-spec.ts index 312e544319..7092a714be 100644 --- a/spec-main/api-touch-bar-spec.ts +++ b/spec-main/api-touch-bar-spec.ts @@ -3,7 +3,7 @@ import { BrowserWindow, TouchBar } from 'electron' import { closeWindow } from './window-helpers' import { expect } from 'chai' -const { TouchBarButton, TouchBarColorPicker, TouchBarGroup, TouchBarLabel, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer } = TouchBar +const { TouchBarButton, TouchBarColorPicker, TouchBarGroup, TouchBarLabel, TouchBarOtherItemsProxy, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer } = TouchBar describe('TouchBar module', () => { it('throws an error when created without an options object', () => { @@ -32,6 +32,13 @@ describe('TouchBar module', () => { }).to.throw('Escape item must be an instance of TouchBarItem') }) + it('throws an error if multiple OtherItemProxy items are added', () => { + expect(() => { + const touchBar = new TouchBar({ items: [new TouchBarOtherItemsProxy(), new TouchBarOtherItemsProxy()] }) + touchBar.toString() + }).to.throw('Must only have one OtherItemsProxy per TouchBar') + }) + describe('BrowserWindow behavior', () => { let window: BrowserWindow @@ -47,32 +54,35 @@ describe('TouchBar module', () => { it('can be added to and removed from a window', () => { const label = new TouchBarLabel({ label: 'bar' }) - const touchBar = new TouchBar({ items: [ - new TouchBarButton({ label: 'foo', backgroundColor: '#F00', click: () => {} }), - new TouchBarButton({ - icon: path.join(__dirname, 'fixtures', 'assets', 'logo.png'), - iconPosition: 'right', - click: () => {} - }), - new TouchBarColorPicker({ selectedColor: '#F00', change: () => {} }), - new TouchBarGroup({ items: new TouchBar({ items: [new TouchBarLabel({ label: 'hello' })] }) }), - label, - new TouchBarPopover({ items: new TouchBar({ items: [new TouchBarButton({ label: 'pop' })] }) }), - new TouchBarSlider({ label: 'slide', value: 5, minValue: 2, maxValue: 75, change: () => {} }), - new TouchBarSpacer({ size: 'large' }), - new TouchBarSegmentedControl({ - segmentStyle: 'capsule', - segments: [{ label: 'baz', enabled: false }], - selectedIndex: 5 - }), - new TouchBarSegmentedControl({ segments: [] }), - new TouchBarScrubber({ - items: [{ label: 'foo' }, { label: 'bar' }, { label: 'baz' }], - selectedStyle: 'outline', - mode: 'fixed', - showArrowButtons: true - }) - ] }) + const touchBar = new TouchBar({ + items: [ + new TouchBarButton({ label: 'foo', backgroundColor: '#F00', click: () => { } }), + new TouchBarButton({ + icon: path.join(__dirname, 'fixtures', 'assets', 'logo.png'), + iconPosition: 'right', + click: () => { } + }), + new TouchBarColorPicker({ selectedColor: '#F00', change: () => { } }), + new TouchBarGroup({ items: new TouchBar({ items: [new TouchBarLabel({ label: 'hello' })] }) }), + label, + new TouchBarOtherItemsProxy(), + new TouchBarPopover({ items: new TouchBar({ items: [new TouchBarButton({ label: 'pop' })] }) }), + new TouchBarSlider({ label: 'slide', value: 5, minValue: 2, maxValue: 75, change: () => { } }), + new TouchBarSpacer({ size: 'large' }), + new TouchBarSegmentedControl({ + segmentStyle: 'capsule', + segments: [{ label: 'baz', enabled: false }], + selectedIndex: 5 + }), + new TouchBarSegmentedControl({ segments: [] }), + new TouchBarScrubber({ + items: [{ label: 'foo' }, { label: 'bar' }, { label: 'baz' }], + selectedStyle: 'outline', + mode: 'fixed', + showArrowButtons: true + }) + ] + }) const escapeButton = new TouchBarButton({ label: 'foo' }) window.setTouchBar(touchBar) touchBar.escapeItem = escapeButton