menuItemActionItem.ts 4.5 KB
Newer Older
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import {localize} from 'vs/nls';
9
import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding';
10
import {IMenu, MenuItemAction} from 'vs/platform/actions/common/actions';
11 12
import {IMessageService} from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
13
import {IAction} from 'vs/base/common/actions';
14
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
15
import {ActionItem, Separator} from 'vs/base/browser/ui/actionbar/actionbar';
16
import {domEvent} from 'vs/base/browser/event';
17
import {Emitter} from 'vs/base/common/event';
18

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

export function fillInActions(menu: IMenu, target: IAction[] | { primary: IAction[]; secondary: IAction[];}): void {
	const actions = menu.getActions();
	if (actions.length === 0) {
		return;
	}

	for (let tuple of actions) {
		let [group, actions] = tuple;
		if (group === 'navigation') {
			if (Array.isArray<IAction>(target)) {
				target.unshift(...actions);
			} else {
				target.primary.unshift(...actions);
			}
		} else {
			if (Array.isArray<IAction>(target)) {
				target.push(new Separator(), ...actions);
			} else {
				target.secondary.push(new Separator(), ...actions);
			}
		}
	}
}


45
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService): ActionItem {
46
	if (action instanceof MenuItemAction) {
47
		return new MenuItemActionItem(action, keybindingService, messageService);
48 49 50
	}
}

51 52 53 54 55 56

const _altKey = new class extends Emitter<boolean> {

	private _subscriptions: IDisposable[] = [];

	constructor() {
57 58 59 60 61
		super();

		this._subscriptions.push(domEvent(document.body, 'keydown')(e => this.fire(e.altKey)));
		this._subscriptions.push(domEvent(document.body, 'keyup')(e => this.fire(false)));
		this._subscriptions.push(domEvent(document.body, 'mouseleave')(e => this.fire(false)));
62 63
	}

64 65 66
	dispose() {
		super.dispose();
		this._subscriptions = dispose(this._subscriptions);
67 68 69
	}
};

70 71 72 73 74 75
class MenuItemActionItem extends ActionItem {

	private _altKeyDown: boolean = false;

	constructor(
		action: MenuItemAction,
76 77
		@IKeybindingService private _keybindingService: IKeybindingService,
		@IMessageService private _messageService: IMessageService
78 79 80 81
	) {
		super(undefined, action, { icon: !!action.command.iconClass, label: !action.command.iconClass });
	}

82
	private get _command() {
83 84 85 86 87 88 89 90
		const {command, altCommand} = <MenuItemAction>this._action;
		return this._altKeyDown && altCommand || command;
	}

	onClick(event: MouseEvent): void {
		event.preventDefault();
		event.stopPropagation();

91 92 93
		(<MenuItemAction>this._action).run(this._altKeyDown).done(undefined, err => {
			this._messageService.show(Severity.Error, err);
		});
94 95 96 97 98
	}

	render(container: HTMLElement): void {
		super.render(container);

99
		let altSubscription: IDisposable;
100 101
		let mouseOver: boolean;
		this._callOnDispose.push(domEvent(container, 'mouseleave')(_ => {
102
			mouseOver = false;
103
			if (!this._altKeyDown) {
104 105
				// stop listen on ALT
				altSubscription.dispose();
106 107
			}
		}));
108
		this._callOnDispose.push(domEvent(container, 'mouseenter')(e => {
109
			mouseOver = true;
110
			altSubscription = _altKey.event(value => {
111

112
				this._altKeyDown = value;
113 114 115
				this._updateLabel();
				this._updateTooltip();
				this._updateClass();
116 117 118 119 120

				if (!mouseOver) {
					// stop listening on ALT
					altSubscription.dispose();
				}
121
			});
122 123 124 125 126
		}));
	}

	_updateLabel(): void {
		if (this.options.label) {
127
			this.$e.text(this._command.title);
128 129 130 131 132
		}
	}

	_updateTooltip(): void {
		const element = this.$e.getHTMLElement();
133
		const keybinding = this._keybindingService.lookupKeybindings(this._command.id)[0];
134 135 136
		const keybindingLabel = keybinding && this._keybindingService.getLabelFor(keybinding);

		element.title = keybindingLabel
137 138
			? localize('titleAndKb', "{0} ({1})", this._command.title, keybindingLabel)
			: this._command.title;
139 140 141 142 143
	}

	_updateClass(): void {
		if (this.options.icon) {
			const element = this.$e.getHTMLElement();
144 145 146 147 148 149 150
			const {command, altCommand} = (<MenuItemAction>this._action);
			if (this._command !== command) {
				element.classList.remove(command.iconClass);
			} else if (altCommand) {
				element.classList.remove(altCommand.iconClass);
			}
			element.classList.add('icon', this._command.iconClass);
151 152 153
		}
	}
}