Skip to content

Commit 5e8b9d1

Browse files
committed
1 parent 7a34ec5 commit 5e8b9d1

File tree

2 files changed

+64
-45
lines changed

2 files changed

+64
-45
lines changed

src/vs/workbench/contrib/feedback/browser/feedback.ts

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
import 'vs/css!./media/feedback';
77
import * as nls from 'vs/nls';
8-
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
9-
import { Dropdown } from 'vs/base/browser/ui/dropdown/dropdown';
8+
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
109
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
1110
import * as dom from 'vs/base/browser/dom';
1211
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -24,6 +23,8 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
2423
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
2524
import { KeyCode } from 'vs/base/common/keyCodes';
2625
import { Codicon } from 'vs/base/common/codicons';
26+
import { Emitter } from 'vs/base/common/event';
27+
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
2728

2829
export interface IFeedback {
2930
feedback: string;
@@ -35,13 +36,16 @@ export interface IFeedbackDelegate {
3536
getCharacterLimit(sentiment: number): number;
3637
}
3738

38-
export interface IFeedbackDropdownOptions {
39-
contextViewProvider: IContextViewService;
39+
export interface IFeedbackWidgetOptions {
4040
feedbackService: IFeedbackDelegate;
4141
onFeedbackVisibilityChange?: (visible: boolean) => void;
4242
}
4343

44-
export class FeedbackDropdown extends Dropdown {
44+
export class FeedbackWidget extends Disposable {
45+
private visible: boolean | undefined;
46+
private _onDidChangeVisibility = new Emitter<boolean>();
47+
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
48+
4549
private maxFeedbackCharacters: number;
4650

4751
private feedback: string = '';
@@ -63,8 +67,9 @@ export class FeedbackDropdown extends Dropdown {
6367
private isPure: boolean = true;
6468

6569
constructor(
66-
container: HTMLElement,
67-
private options: IFeedbackDropdownOptions,
70+
private options: IFeedbackWidgetOptions,
71+
@IContextViewService private readonly contextViewService: IContextViewService,
72+
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
6873
@ICommandService private readonly commandService: ICommandService,
6974
@ITelemetryService private readonly telemetryService: ITelemetryService,
7075
@IIntegrityService private readonly integrityService: IIntegrityService,
@@ -73,7 +78,7 @@ export class FeedbackDropdown extends Dropdown {
7378
@IProductService productService: IProductService,
7479
@IOpenerService private readonly openerService: IOpenerService
7580
) {
76-
super(container, options);
81+
super();
7782

7883
this.feedbackDelegate = options.feedbackService;
7984
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
@@ -87,23 +92,18 @@ export class FeedbackDropdown extends Dropdown {
8792
this.isPure = false;
8893
}
8994
});
90-
91-
dom.addClass(this.element, 'send-feedback');
92-
this.element.title = nls.localize('sendFeedback', "Tweet Feedback");
9395
}
9496

95-
protected getAnchor(): HTMLElement | IAnchor {
96-
const position = dom.getDomNodePagePosition(this.element);
97+
private getAnchor(): HTMLElement | IAnchor {
98+
const dimension = this.layoutService.dimension;
9799

98100
return {
99-
x: position.left + position.width, // center above the container
100-
y: position.top - 26, // above status bar and beak
101-
width: position.width,
102-
height: position.height
101+
x: dimension.width - 8,
102+
y: dimension.height - 31
103103
};
104104
}
105105

106-
protected renderContents(container: HTMLElement): IDisposable {
106+
private renderContents(container: HTMLElement): IDisposable {
107107
const disposables = new DisposableStore();
108108

109109
dom.addClass(container, 'monaco-menu-container');
@@ -380,7 +380,26 @@ export class FeedbackDropdown extends Dropdown {
380380
}
381381

382382
show(): void {
383-
super.show();
383+
if (this.visible) {
384+
return;
385+
}
386+
387+
this.visible = true;
388+
this._onDidChangeVisibility.fire(true);
389+
390+
this.contextViewService.showContextView({
391+
getAnchor: () => this.getAnchor(),
392+
393+
render: (container) => {
394+
return this.renderContents(container);
395+
},
396+
397+
onDOMEvent: (e, activeElement) => {
398+
this.onEvent(e, activeElement);
399+
},
400+
401+
onHide: () => this.onHide()
402+
});
384403

385404
if (this.options.onFeedbackVisibilityChange) {
386405
this.options.onFeedbackVisibilityChange(true);
@@ -389,13 +408,17 @@ export class FeedbackDropdown extends Dropdown {
389408
this.updateCharCountText();
390409
}
391410

392-
protected onHide(): void {
411+
private onHide(): void {
393412
if (this.options.onFeedbackVisibilityChange) {
394413
this.options.onFeedbackVisibilityChange(false);
395414
}
396415
}
397416

398417
hide(): void {
418+
if (!this.visible) {
419+
return;
420+
}
421+
399422
if (this.feedbackDescriptionInput) {
400423
this.feedback = this.feedbackDescriptionInput.value;
401424
}
@@ -409,10 +432,17 @@ export class FeedbackDropdown extends Dropdown {
409432
this.statusbarService.updateEntryVisibility('status.feedback', false);
410433
}
411434

412-
super.hide();
435+
this.visible = false;
436+
this._onDidChangeVisibility.fire(false);
437+
438+
this.contextViewService.hideContextView();
439+
}
440+
441+
isVisible(): boolean {
442+
return !!this.visible;
413443
}
414444

415-
onEvent(e: Event, activeElement: HTMLElement): void {
445+
private onEvent(e: Event, activeElement: HTMLElement): void {
416446
if (e instanceof KeyboardEvent) {
417447
const keyboardEvent = <KeyboardEvent>e;
418448
if (keyboardEvent.keyCode === 27) { // Escape

src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Disposable } from 'vs/base/common/lifecycle';
7-
import { FeedbackDropdown, IFeedback, IFeedbackDelegate } from 'vs/workbench/contrib/feedback/browser/feedback';
8-
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
7+
import { FeedbackWidget, IFeedback, IFeedbackDelegate } from 'vs/workbench/contrib/feedback/browser/feedback';
98
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
109
import { IProductService } from 'vs/platform/product/common/productService';
1110
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
@@ -50,15 +49,13 @@ class TwitterFeedbackService implements IFeedbackDelegate {
5049
}
5150

5251
export class FeedbackStatusbarConribution extends Disposable implements IWorkbenchContribution {
53-
private dropdown: FeedbackDropdown | undefined;
52+
private widget: FeedbackWidget | undefined;
5453
private entry: IStatusbarEntryAccessor | undefined;
5554

5655
constructor(
5756
@IStatusbarService statusbarService: IStatusbarService,
5857
@IProductService productService: IProductService,
59-
@IInstantiationService private instantiationService: IInstantiationService,
60-
@IContextViewService private contextViewService: IContextViewService
61-
) {
58+
@IInstantiationService private instantiationService: IInstantiationService) {
6259
super();
6360

6461
if (productService.sendASmile) {
@@ -76,26 +73,18 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
7673
}
7774

7875
private toggleFeedback(): void {
79-
if (!this.dropdown) {
80-
const statusContainr = document.getElementById('status.feedback');
81-
if (statusContainr) {
82-
const icon = statusContainr.getElementsByClassName('codicon').item(0) as HTMLElement | null;
83-
if (!icon) {
84-
throw new Error('Could not find icon');
85-
}
86-
this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, icon, {
87-
contextViewProvider: this.contextViewService,
88-
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService),
89-
onFeedbackVisibilityChange: visible => this.entry!.update(this.getStatusEntry(visible))
90-
}));
91-
}
76+
if (!this.widget) {
77+
this.widget = this._register(this.instantiationService.createInstance(FeedbackWidget, {
78+
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService),
79+
onFeedbackVisibilityChange: visible => this.entry!.update(this.getStatusEntry(visible))
80+
}));
9281
}
9382

94-
if (this.dropdown) {
95-
if (!this.dropdown.isVisible()) {
96-
this.dropdown.show();
83+
if (this.widget) {
84+
if (!this.widget.isVisible()) {
85+
this.widget.show();
9786
} else {
98-
this.dropdown.hide();
87+
this.widget.hide();
9988
}
10089
}
10190
}

0 commit comments

Comments
 (0)