提交 840587c0 编写于 作者: B Benjamin Pasero

tweet feedback button - make it hideable (fixes #7893)

上级 48efc7fd
......@@ -36,8 +36,6 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWin
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: null, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);
if (isMacintosh) {
......@@ -52,23 +50,29 @@ if (!!product.reportIssueUrl) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueAction, ReportPerformanceIssueAction.ID, ReportPerformanceIssueAction.LABEL), 'Help: Report Performance Issue', helpCategory);
}
if (KeybindingsReferenceAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory);
}
if (OpenDocumentationUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory);
}
if (OpenIntroductoryVideosUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIntroductoryVideosUrlAction, OpenIntroductoryVideosUrlAction.ID, OpenIntroductoryVideosUrlAction.LABEL), 'Help: Introductory Videos', helpCategory);
}
if (OpenTipsAndTricksUrlAction.AVAILABLE) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory);
}
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD]
}), 'View: Zoom In', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.US_MINUS,
......@@ -76,11 +80,13 @@ workbenchActionsRegistry.registerWorkbenchAction(
linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] }
}), 'View: Zoom Out', viewCategory
);
workbenchActionsRegistry.registerWorkbenchAction(
new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0
}), 'View: Reset Zoom', viewCategory
);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseMessagesAction, CloseMessagesAction.ID, CloseMessagesAction.LABEL, { primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] }, MessagesVisibleContext), 'Close Notification Messages');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory);
if (isWindows || isLinux) {
......@@ -269,7 +275,6 @@ configurationRegistry.registerConfiguration({
}
});
// Configuration: Window
configurationRegistry.registerConfiguration({
......
......@@ -273,7 +273,6 @@ export class ElectronWindow extends Themable {
}
private updateWindowZoomLevel(): void {
const windowConfig: IWindowsConfiguration = this.configurationService.getValue<IWindowsConfiguration>();
let newZoomLevel = 0;
......
......@@ -6,11 +6,30 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { StatusbarAlignment, IStatusbarRegistry, Extensions, StatusbarItemDescriptor } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { FeedbackStatusbarItem } from './feedbackStatusbarItem';
import { FeedbackStatusbarItem } from 'vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem';
import { localize } from 'vs/nls';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
// Register Statusbar item
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(new StatusbarItemDescriptor(
FeedbackStatusbarItem,
StatusbarAlignment.RIGHT,
-100 /* Low Priority */
));
\ No newline at end of file
));
// Configuration: Workbench
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'workbench',
'order': 7,
'title': localize('workbenchConfigurationTitle', "Workbench"),
'type': 'object',
'properties': {
'workbench.statusBar.feedback.visible': {
'type': 'boolean',
'default': true,
'description': localize('feedbackVisibility', "Controls the visibility of the Twitter feedback (smiley) in the status bar at the bottom of the workbench.")
}
}
});
\ No newline at end of file
......@@ -11,7 +11,6 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { Builder, $ } from 'vs/base/browser/builder';
import { Dropdown } from 'vs/base/browser/ui/dropdown/dropdown';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import product from 'vs/platform/node/product';
import * as dom from 'vs/base/browser/dom';
import { ICommandService } from 'vs/platform/commands/common/commands';
......@@ -20,6 +19,9 @@ import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
import { editorWidgetBackground, widgetShadow, inputBorder, inputForeground, inputBackground, inputActiveOptionBorder, editorBackground, buttonBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
export const FEEDBACK_VISIBLE_CONFIG = 'workbench.statusBar.feedback.visible';
export interface IFeedback {
feedback: string;
......@@ -43,35 +45,34 @@ enum FormEvent {
}
export class FeedbackDropdown extends Dropdown {
protected maxFeedbackCharacters: number;
private maxFeedbackCharacters: number;
protected feedback: string;
protected sentiment: number;
protected aliasEnabled: boolean;
protected isSendingFeedback: boolean;
protected autoHideTimeout: number;
private feedback: string;
private sentiment: number;
private isSendingFeedback: boolean;
private autoHideTimeout: number;
protected feedbackService: IFeedbackService;
private feedbackService: IFeedbackService;
protected feedbackForm: HTMLFormElement;
protected feedbackDescriptionInput: HTMLTextAreaElement;
protected smileyInput: Builder;
protected frownyInput: Builder;
protected sendButton: Builder;
protected remainingCharacterCount: Builder;
private feedbackForm: HTMLFormElement;
private feedbackDescriptionInput: HTMLTextAreaElement;
private smileyInput: Builder;
private frownyInput: Builder;
private sendButton: Builder;
private hideButton: HTMLInputElement;
private remainingCharacterCount: Builder;
protected requestFeatureLink: string;
protected reportIssueLink: string;
private requestFeatureLink: string;
private _isPure: boolean;
constructor(
container: HTMLElement,
options: IFeedbackDropdownOptions,
@ITelemetryService protected telemetryService: ITelemetryService,
@ICommandService private commandService: ICommandService,
@IIntegrityService protected integrityService: IIntegrityService,
@IThemeService private themeService: IThemeService
@IIntegrityService private integrityService: IIntegrityService,
@IThemeService private themeService: IThemeService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService
) {
super(container, {
contextViewProvider: options.contextViewProvider,
......@@ -106,8 +107,7 @@ export class FeedbackDropdown extends Dropdown {
this.sendButton = null;
this.reportIssueLink = product.reportIssueUrl;
this.requestFeatureLink = product.requestFeatureUrl;
this.requestFeatureLink = product.sendASmile.requestFeatureUrl;
}
protected renderContents(container: HTMLElement): IDisposable {
......@@ -197,10 +197,17 @@ export class FeedbackDropdown extends Dropdown {
const $buttons = $('div.form-buttons').appendTo($form);
const $hideButtonContainer = $('div.hide-button').appendTo($buttons);
this.hideButton = $('input.hide-button').type('checkbox').attr('checked', '').id('hide-button').appendTo($hideButtonContainer).getHTMLElement() as HTMLInputElement;
$('label').attr('for', 'hide-button').text(nls.localize('showFeedback', "Show Feedback Smiley in Status Bar")).appendTo($hideButtonContainer);
this.sendButton = this.invoke($('input.send').type('submit').attr('disabled', '').value(nls.localize('tweet', "Tweet")).appendTo($buttons), () => {
if (this.isSendingFeedback) {
return;
}
this.onSubmit();
});
......@@ -242,7 +249,7 @@ export class FeedbackDropdown extends Dropdown {
this.feedbackDescriptionInput.value ? this.sendButton.removeAttribute('disabled') : this.sendButton.attr('disabled', '');
}
protected setSentiment(smile: boolean): void {
private setSentiment(smile: boolean): void {
if (smile) {
this.smileyInput.addClass('checked');
this.smileyInput.attr('aria-checked', 'true');
......@@ -254,14 +261,16 @@ export class FeedbackDropdown extends Dropdown {
this.smileyInput.removeClass('checked');
this.smileyInput.attr('aria-checked', 'false');
}
this.sentiment = smile ? 1 : 0;
this.maxFeedbackCharacters = this.feedbackService.getCharacterLimit(this.sentiment);
this.updateCharCountText();
$(this.feedbackDescriptionInput).attr({ maxlength: this.maxFeedbackCharacters });
}
protected invoke(element: Builder, callback: () => void): Builder {
private invoke(element: Builder, callback: () => void): Builder {
element.on('click', callback);
element.on('keypress', (e) => {
if (e instanceof KeyboardEvent) {
const keyboardEvent = <KeyboardEvent>e;
......@@ -270,6 +279,7 @@ export class FeedbackDropdown extends Dropdown {
}
}
});
return element;
}
......@@ -283,6 +293,10 @@ export class FeedbackDropdown extends Dropdown {
this.autoHideTimeout = null;
}
if (!this.hideButton.checked) {
this.configurationService.updateValue(FEEDBACK_VISIBLE_CONFIG, false).done(null, errors.onUnexpectedError);
}
super.hide();
}
......@@ -295,7 +309,7 @@ export class FeedbackDropdown extends Dropdown {
}
}
protected onSubmit(): void {
private onSubmit(): void {
if ((this.feedbackForm.checkValidity && !this.feedbackForm.checkValidity())) {
return;
}
......@@ -338,13 +352,13 @@ export class FeedbackDropdown extends Dropdown {
}
}
protected resetForm(): void {
private resetForm(): void {
if (this.feedbackDescriptionInput) {
this.feedbackDescriptionInput.value = '';
}
this.sentiment = 1;
this.maxFeedbackCharacters = this.feedbackService.getCharacterLimit(this.sentiment);
this.aliasEnabled = false;
}
}
......
......@@ -5,15 +5,22 @@
'use strict';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { FeedbackDropdown, IFeedback, IFeedbackService } from './feedback';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { FeedbackDropdown, IFeedback, IFeedbackService, FEEDBACK_VISIBLE_CONFIG } from 'vs/workbench/parts/feedback/electron-browser/feedback';
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import product from 'vs/platform/node/product';
import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { clearNode, EventHelper } from 'vs/base/browser/dom';
import { $ } from 'vs/base/browser/builder';
import { localize } from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
class TwitterFeedbackService implements IFeedbackService {
......@@ -50,20 +57,38 @@ class TwitterFeedbackService implements IFeedbackService {
export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
private dropdown: FeedbackDropdown;
private enabled: boolean;
private container: HTMLElement;
private hideAction: HideAction;
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IContextViewService private contextViewService: IContextViewService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@IThemeService themeService: IThemeService
) {
super(themeService);
this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG);
this.hideAction = this.instantiationService.createInstance(HideAction);
this.toUnbind.push(this.hideAction);
this.registerListeners();
}
private registerListeners(): void {
this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles()));
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
}
private onConfigurationUpdated(event: IConfigurationChangeEvent): void {
if (event.affectsConfiguration(FEEDBACK_VISIBLE_CONFIG)) {
this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG);
this.update();
}
}
protected updateStyles(): void {
......@@ -75,17 +100,66 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
}
public render(element: HTMLElement): IDisposable {
if (product.sendASmile) {
this.dropdown = this.instantiationService.createInstance(FeedbackDropdown, element, {
contextViewProvider: this.contextViewService,
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService)
this.container = element;
// Prevent showing dropdown on anything but left click
$(this.container).on('mousedown', (e: MouseEvent) => {
if (e.button !== 0) {
EventHelper.stop(e, true);
}
}, this.toUnbind, true);
// Offer context menu to hide status bar entry
$(this.container).on('contextmenu', e => {
EventHelper.stop(e, true);
this.contextMenuService.showContextMenu({
getAnchor: () => this.container,
getActions: () => TPromise.as([this.hideAction])
});
}, this.toUnbind);
return this.update();
}
private update(): IDisposable {
const enabled = product.sendASmile && this.enabled;
// Create
if (enabled) {
if (!this.dropdown) {
this.dropdown = this.instantiationService.createInstance(FeedbackDropdown, this.container, {
contextViewProvider: this.contextViewService,
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService)
});
this.toUnbind.push(this.dropdown);
this.updateStyles();
this.updateStyles();
return this.dropdown;
return this.dropdown;
}
}
// Dispose
else {
dispose(this.dropdown);
this.dropdown = void 0;
clearNode(this.container);
}
return null;
}
}
class HideAction extends Action {
constructor(
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService
) {
super('feedback.hide', localize('hide', "Hide"));
}
public run(extensionId: string): TPromise<any> {
return this.configurationService.updateValue(FEEDBACK_VISIBLE_CONFIG, false);
}
}
\ No newline at end of file
......@@ -156,6 +156,14 @@
background-color: #eaeaea;
}
.monaco-shell .feedback-form .form-buttons {
display: flex;
}
.monaco-shell .feedback-form .form-buttons .hide-button {
align-self: center;
}
.monaco-shell .feedback-form .form-buttons .send {
color: white;
border: none;
......@@ -169,6 +177,7 @@
padding-right: 12px;
border: 4px solid #007ACC;
border-radius: 4px;
margin-left: auto;
}
.monaco-shell .feedback-form .form-buttons .send.in-progress,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册