提交 6d770e76 编写于 作者: B Benjamin Pasero 提交者: GitHub

webkit-mask for status bar icons (fixes #23526) (#24997)

上级 9ac64297
......@@ -29,10 +29,8 @@ export interface IBaseDropdownOptions {
}
export class BaseDropdown extends ActionRunner {
/*protected*/ toDispose: IDisposable[];
/*protected*/ $el: Builder;
private _toDispose: IDisposable[];
private $el: Builder;
private $boxContainer: Builder;
private $action: Builder;
private $label: Builder;
......@@ -41,7 +39,7 @@ export class BaseDropdown extends ActionRunner {
constructor(container: HTMLElement, options: IBaseDropdownOptions) {
super();
this.toDispose = [];
this._toDispose = [];
this.$el = $('.dropdown').appendTo(container);
......@@ -87,25 +85,37 @@ export class BaseDropdown extends ActionRunner {
let cleanupFn = labelRenderer(this.$label.getHTMLElement());
if (cleanupFn) {
this.toDispose.push(cleanupFn);
this._toDispose.push(cleanupFn);
}
this.toDispose.push(new Gesture(this.$label.getHTMLElement()));
this._toDispose.push(new Gesture(this.$label.getHTMLElement()));
}
public get toDispose(): IDisposable[] {
return this._toDispose;
}
public get element(): Builder {
return this.$el;
}
public get label(): Builder {
return this.$label;
}
public set tooltip(tooltip: string) {
this.$label.title(tooltip);
}
/*protected*/ show(): void {
public show(): void {
// noop
}
/*protected*/ public hide(): void {
public hide(): void {
// noop
}
/*protected*/ public onEvent(e: Event, activeElement: HTMLElement): void {
protected onEvent(e: Event, activeElement: HTMLElement): void {
this.hide();
}
......@@ -113,7 +123,7 @@ export class BaseDropdown extends ActionRunner {
super.dispose();
this.hide();
this.toDispose = dispose(this.toDispose);
this._toDispose = dispose(this.toDispose);
if (this.$boxContainer) {
this.$boxContainer.destroy();
......@@ -137,27 +147,19 @@ export interface IDropdownOptions extends IBaseDropdownOptions {
}
export class Dropdown extends BaseDropdown {
/*protected*/ _contextViewProvider: IContextViewProvider;
private contextViewProvider: IContextViewProvider;
constructor(container: HTMLElement, options: IDropdownOptions) {
super(container, options);
this.contextViewProvider = options.contextViewProvider;
}
/*protected*/ public set contextViewProvider(contextViewProvider: IContextViewProvider) {
this._contextViewProvider = contextViewProvider;
}
/*protected*/ public get contextViewProvider(): IContextViewProvider {
return this._contextViewProvider;
this.contextViewProvider = options.contextViewProvider;
}
/*protected*/ show(): void {
this.$el.addClass('active');
public show(): void {
this.element.addClass('active');
this._contextViewProvider.showContextView({
getAnchor: () => this.$el.getHTMLElement(),
this.contextViewProvider.showContextView({
getAnchor: () => this.element.getHTMLElement(),
render: (container) => {
return this.renderContents(container);
......@@ -168,18 +170,18 @@ export class Dropdown extends BaseDropdown {
},
onHide: () => {
this.$el.removeClass('active');
this.element.removeClass('active');
}
});
}
/*protected*/ public hide(): void {
if (this._contextViewProvider) {
this._contextViewProvider.hideContextView();
public hide(): void {
if (this.contextViewProvider) {
this.contextViewProvider.hideContextView();
}
}
/*protected*/ public renderContents(container: HTMLElement): IDisposable {
protected renderContents(container: HTMLElement): IDisposable {
return null;
}
}
......@@ -210,11 +212,10 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions {
}
export class DropdownMenu extends BaseDropdown {
/*protected*/ _contextMenuProvider: IContextMenuProvider;
private _contextMenuProvider: IContextMenuProvider;
private _menuOptions: IMenuOptions;
/*protected*/ _actions: IAction[];
/*protected*/ actionProvider: IActionProvider;
private _actions: IAction[];
private actionProvider: IActionProvider;
private menuClassName: string;
constructor(container: HTMLElement, options: IDropdownMenuOptions) {
......@@ -226,14 +227,6 @@ export class DropdownMenu extends BaseDropdown {
this.menuClassName = options.menuClassName || '';
}
/*protected*/ public set contextMenuProvider(contextMenuProvider: IContextMenuProvider) {
this._contextMenuProvider = contextMenuProvider;
}
/*protected*/ public get contextMenuProvider(): IContextMenuProvider {
return this._contextMenuProvider;
}
public set menuOptions(options: IMenuOptions) {
this._menuOptions = options;
}
......@@ -242,7 +235,7 @@ export class DropdownMenu extends BaseDropdown {
return this._menuOptions;
}
/*protected*/ public get actions(): IAction[] {
private get actions(): IAction[] {
if (this.actionProvider) {
return this.actionProvider.getActions();
}
......@@ -250,25 +243,25 @@ export class DropdownMenu extends BaseDropdown {
return this._actions;
}
/*protected*/ public set actions(actions: IAction[]) {
private set actions(actions: IAction[]) {
this._actions = actions;
}
/*protected*/ show(): void {
this.$el.addClass('active');
public show(): void {
this.element.addClass('active');
this._contextMenuProvider.showContextMenu({
getAnchor: () => this.$el.getHTMLElement(),
getAnchor: () => this.element.getHTMLElement(),
getActions: () => TPromise.as(this.actions),
getActionsContext: () => this.menuOptions ? this.menuOptions.context : null,
getActionItem: (action) => this.menuOptions && this.menuOptions.actionItemProvider ? this.menuOptions.actionItemProvider(action) : null,
getKeyBinding: (action: IAction) => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : null,
getMenuClassName: () => this.menuClassName,
onHide: () => this.$el.removeClass('active')
onHide: () => this.element.removeClass('active')
});
}
/*protected*/ public hide(): void {
public hide(): void {
// noop
}
}
......
......@@ -22,7 +22,7 @@ export class LinksDropdownMenu extends DropdownMenu {
this.tooltip = options.tooltip;
}
/*protected*/ public onEvent(e: Event, activeElement: HTMLElement): void {
protected onEvent(e: Event, activeElement: HTMLElement): void {
if (e instanceof KeyboardEvent && ((<KeyboardEvent>e).ctrlKey || (isMacintosh && (<KeyboardEvent>e).metaKey))) {
return; // allow to use Ctrl/Meta in workspace dropdown menu
}
......
......@@ -73,6 +73,7 @@ export class FeedbackDropdown extends Dropdown {
contextViewProvider: options.contextViewProvider,
labelRenderer: (container: HTMLElement): IDisposable => {
$(container).addClass('send-feedback');
return null;
}
});
......@@ -84,8 +85,8 @@ export class FeedbackDropdown extends Dropdown {
}
});
this.$el.addClass('send-feedback');
this.$el.title(nls.localize('sendFeedback', "Tweet Feedback"));
this.element.addClass('send-feedback');
this.element.title(nls.localize('sendFeedback', "Tweet Feedback"));
this.feedbackService = options.feedbackService;
......@@ -105,7 +106,7 @@ export class FeedbackDropdown extends Dropdown {
this.requestFeatureLink = product.requestFeatureUrl;
}
public renderContents(container: HTMLElement): IDisposable {
protected renderContents(container: HTMLElement): IDisposable {
const $form = $('form.feedback-form').attr({
action: 'javascript:void(0);',
tabIndex: '-1'
......
......@@ -11,6 +11,8 @@ import { FeedbackDropdown, IFeedback, IFeedbackService } from './feedback';
import { IContextViewService } 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 } from "vs/workbench/common/theme";
import { IThemeService } from "vs/platform/theme/common/themeService";
class TwitterFeedbackService implements IFeedbackService {
......@@ -45,20 +47,35 @@ class TwitterFeedbackService implements IFeedbackService {
}
}
export class FeedbackStatusbarItem implements IStatusbarItem {
export class FeedbackStatusbarItem extends Themable implements IStatusbarItem {
private dropdown: FeedbackDropdown;
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IContextViewService private contextViewService: IContextViewService
@IContextViewService private contextViewService: IContextViewService,
@IThemeService themeService: IThemeService
) {
super(themeService);
}
protected updateStyles(): void {
super.updateStyles();
if (this.dropdown) {
this.dropdown.label.style('background-color', this.getColor(STATUS_BAR_FOREGROUND));
}
}
public render(element: HTMLElement): IDisposable {
if (product.sendASmile) {
return this.instantiationService.createInstance(FeedbackDropdown, element, {
this.dropdown = this.instantiationService.createInstance(FeedbackDropdown, element, {
contextViewProvider: this.contextViewService,
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService)
});
this.updateStyles();
return this.dropdown;
}
return null;
......
......@@ -158,7 +158,7 @@
}
.monaco-shell .statusbar-item > .dropdown.send-feedback > .dropdown-label.send-feedback {
background: url('smiley.svg') center center no-repeat;
-webkit-mask: url('smiley.svg') no-repeat 50% 50%; /* use mask to be able to change color dynamically */
width: 26px;
}
......
......@@ -11,7 +11,7 @@
background: url('task.svg') 50% 2px no-repeat;
background-size: 18px;
cursor: pointer;
height: 24px;
height: 22px;
width: 24px;
vertical-align: top;
}
......@@ -30,23 +30,33 @@
padding: 0 5px 0 5px;
}
.task-statusbar-item-label-error {
.task-statusbar-item-label > .task-statusbar-item-label-counter {
display: inline-block;
padding: 0px 0px 2px 16px;
background: url('status-error.svg') 0px 6px no-repeat;
background-size: 11px;
vertical-align: top;
padding-left: 2px;
padding-right: 2px;
}
.task-statusbar-item-label-warning {
.task-statusbar-item-label > .task-statusbar-item-label-error,
.task-statusbar-item-label > .task-statusbar-item-label-warning,
.task-statusbar-item-label > .task-statusbar-item-label-info {
display: inline-block;
padding: 0px 0px 2px 22px;
background: url('status-warning.svg') 6px 6px no-repeat;
background-size: 11px;
padding-right: 8px;
width: 8px;
height: 22px;
}
.task-statusbar-item-label-info {
display: inline-block;
padding: 0px 0px 2px 22px;
background: url('status-info.svg') 6px 6px no-repeat;
background-size: 11px;
.task-statusbar-item-label > .task-statusbar-item-label-error {
-webkit-mask: url('status-error.svg') no-repeat 50% 50%;
-webkit-mask-size: 11px;
}
.task-statusbar-item-label > .task-statusbar-item-label-warning {
-webkit-mask: url('status-warning.svg') no-repeat 50% 50%;
-webkit-mask-size: 11px;
}
.task-statusbar-item-label > .task-statusbar-item-label-info {
-webkit-mask: url('status-info.svg') no-repeat 50% 50%;
-webkit-mask-size: 11px;
}
\ No newline at end of file
......@@ -249,44 +249,48 @@ class ViewTerminalAction extends Action {
}
}
class StatusBarItem implements IStatusbarItem {
private panelService: IPanelService;
private markerService: IMarkerService;
private taskService: ITaskService;
private outputService: IOutputService;
class StatusBarItem extends Themable implements IStatusbarItem {
private intervalToken: any;
private activeCount: number;
private static progressChars: string = '|/-\\';
private icons: HTMLElement[];
constructor(
@IPanelService private panelService: IPanelService,
@IMarkerService private markerService: IMarkerService,
@IOutputService private outputService: IOutputService,
@ITaskService private taskService: ITaskService,
@IPartService private partService: IPartService,
@IThemeService themeService: IThemeService
) {
super(themeService);
constructor( @IPanelService panelService: IPanelService,
@IMarkerService markerService: IMarkerService, @IOutputService outputService: IOutputService,
@ITaskService taskService: ITaskService,
@IPartService private partService: IPartService) {
this.panelService = panelService;
this.markerService = markerService;
this.outputService = outputService;
this.taskService = taskService;
this.activeCount = 0;
this.icons = [];
}
public render(container: HTMLElement): IDisposable {
protected updateStyles(): void {
super.updateStyles();
let callOnDispose: IDisposable[] = [],
element = document.createElement('div'),
// icon = document.createElement('a'),
progress = document.createElement('div'),
label = document.createElement('a'),
error = document.createElement('div'),
warning = document.createElement('div'),
info = document.createElement('div');
this.icons.forEach(icon => {
icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND);
});
}
Dom.addClass(element, 'task-statusbar-item');
public render(container: HTMLElement): IDisposable {
let callOnDispose: IDisposable[] = [];
const element = document.createElement('div');
const progress = document.createElement('div');
const label = document.createElement('a');
const errorIcon = document.createElement('div');
const warningIcon = document.createElement('div');
const infoIcon = document.createElement('div');
const error = document.createElement('div');
const warning = document.createElement('div');
const info = document.createElement('div');
// dom.addClass(icon, 'task-statusbar-item-icon');
// element.appendChild(icon);
Dom.addClass(element, 'task-statusbar-item');
Dom.addClass(progress, 'task-statusbar-item-progress');
element.appendChild(progress);
......@@ -297,22 +301,31 @@ class StatusBarItem implements IStatusbarItem {
element.appendChild(label);
element.title = nls.localize('problems', "Problems");
Dom.addClass(error, 'task-statusbar-item-label-error');
Dom.addClass(errorIcon, 'task-statusbar-item-label-error');
label.appendChild(errorIcon);
this.icons.push(errorIcon);
Dom.addClass(error, 'task-statusbar-item-label-counter');
error.innerHTML = '0';
label.appendChild(error);
Dom.addClass(warning, 'task-statusbar-item-label-warning');
Dom.addClass(warningIcon, 'task-statusbar-item-label-warning');
label.appendChild(warningIcon);
this.icons.push(warningIcon);
Dom.addClass(warning, 'task-statusbar-item-label-counter');
warning.innerHTML = '0';
label.appendChild(warning);
Dom.addClass(info, 'task-statusbar-item-label-info');
Dom.addClass(infoIcon, 'task-statusbar-item-label-info');
label.appendChild(infoIcon);
this.icons.push(infoIcon);
$(infoIcon).hide();
Dom.addClass(info, 'task-statusbar-item-label-counter');
label.appendChild(info);
$(info).hide();
// callOnDispose.push(dom.addListener(icon, 'click', (e:MouseEvent) => {
// this.outputService.showOutput(TaskService.OutputChannel, e.ctrlKey || e.metaKey, true);
// }));
callOnDispose.push(Dom.addDisposableListener(label, 'click', (e: MouseEvent) => {
const panel = this.panelService.getActivePanel();
if (panel && panel.getId() === Constants.MARKERS_PANEL_ID) {
......@@ -322,23 +335,24 @@ class StatusBarItem implements IStatusbarItem {
}
}));
let updateStatus = (element: HTMLDivElement, stats: number): boolean => {
let updateStatus = (element: HTMLDivElement, icon: HTMLDivElement, stats: number): boolean => {
if (stats > 0) {
element.innerHTML = stats.toString();
$(element).show();
$(icon).show();
return true;
} else {
$(element).hide();
$(icon).hide();
return false;
}
};
let manyMarkers = nls.localize('manyMarkers', "99+");
let updateLabel = (stats: MarkerStatistics) => {
error.innerHTML = stats.errors < 100 ? stats.errors.toString() : manyMarkers;
warning.innerHTML = stats.warnings < 100 ? stats.warnings.toString() : manyMarkers;
updateStatus(info, stats.infos);
updateStatus(info, infoIcon, stats.infos);
};
this.markerService.onMarkerChanged((changedResources) => {
......@@ -390,6 +404,8 @@ class StatusBarItem implements IStatusbarItem {
container.appendChild(element);
this.updateStyles();
return {
dispose: () => {
callOnDispose = dispose(callOnDispose);
......@@ -1262,6 +1278,8 @@ let schema: IJSONSchema = {
import schemaVersion1 from './jsonSchema_v1';
import schemaVersion2 from './jsonSchema_v2';
import { Themable, STATUS_BAR_FOREGROUND } from "vs/workbench/common/theme";
import { IThemeService } from "vs/platform/theme/common/themeService";
schema.definitions = {
...schemaVersion1.definitions,
...schemaVersion2.definitions,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册