mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from master
This commit is contained in:
@@ -28,10 +28,6 @@
|
||||
.monaco-action-bar .action-item {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
-ms-transition: -ms-transform 50ms ease;
|
||||
-webkit-transition: -webkit-transform 50ms ease;
|
||||
-moz-transition: -moz-transform 50ms ease;
|
||||
-o-transition: -o-transform 50ms ease;
|
||||
transition: transform 50ms ease;
|
||||
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
|
||||
}
|
||||
@@ -41,11 +37,7 @@
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated .action-item.active {
|
||||
-ms-transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||
-webkit-transform: scale(1.272019649, 1.272019649);
|
||||
-moz-transform: scale(1.272019649, 1.272019649);
|
||||
-o-transform: scale(1.272019649, 1.272019649);
|
||||
transform: scale(1.272019649, 1.272019649);
|
||||
transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .icon {
|
||||
@@ -87,10 +79,6 @@
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated.vertical .action-item.active {
|
||||
-ms-transform: translate(5px, 0);
|
||||
-webkit-transform: translate(5px, 0);
|
||||
-moz-transform: translate(5px, 0);
|
||||
-o-transform: translate(5px, 0);
|
||||
transform: translate(5px, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./actionbar';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { Disposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { SelectBox, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, IRunEvent } from 'vs/base/common/actions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
@@ -36,77 +32,78 @@ export interface IBaseActionItemOptions {
|
||||
isMenu?: boolean;
|
||||
}
|
||||
|
||||
export class BaseActionItem implements IActionItem {
|
||||
export class BaseActionItem extends Disposable implements IActionItem {
|
||||
|
||||
public builder: Builder;
|
||||
public _callOnDispose: lifecycle.IDisposable[];
|
||||
public _context: any;
|
||||
public _action: IAction;
|
||||
element?: HTMLElement;
|
||||
_context: any;
|
||||
_action: IAction;
|
||||
|
||||
private _actionRunner: IActionRunner;
|
||||
|
||||
constructor(context: any, action: IAction, protected options?: IBaseActionItemOptions) {
|
||||
this._callOnDispose = [];
|
||||
super();
|
||||
|
||||
this._context = context || this;
|
||||
this._action = action;
|
||||
|
||||
if (action instanceof Action) {
|
||||
this._callOnDispose.push(action.onDidChange(event => {
|
||||
if (!this.builder) {
|
||||
this._register(action.onDidChange(event => {
|
||||
if (!this.element) {
|
||||
// we have not been rendered yet, so there
|
||||
// is no point in updating the UI
|
||||
return;
|
||||
}
|
||||
this._handleActionChangeEvent(event);
|
||||
|
||||
this.handleActionChangeEvent(event);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
protected _handleActionChangeEvent(event: IActionChangeEvent): void {
|
||||
private handleActionChangeEvent(event: IActionChangeEvent): void {
|
||||
if (event.enabled !== void 0) {
|
||||
this._updateEnabled();
|
||||
this.updateEnabled();
|
||||
}
|
||||
|
||||
if (event.checked !== void 0) {
|
||||
this._updateChecked();
|
||||
this.updateChecked();
|
||||
}
|
||||
|
||||
if (event.class !== void 0) {
|
||||
this._updateClass();
|
||||
this.updateClass();
|
||||
}
|
||||
|
||||
if (event.label !== void 0) {
|
||||
this._updateLabel();
|
||||
this._updateTooltip();
|
||||
this.updateLabel();
|
||||
this.updateTooltip();
|
||||
}
|
||||
|
||||
if (event.tooltip !== void 0) {
|
||||
this._updateTooltip();
|
||||
this.updateTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
public get callOnDispose() {
|
||||
return this._callOnDispose;
|
||||
}
|
||||
|
||||
public set actionRunner(actionRunner: IActionRunner) {
|
||||
set actionRunner(actionRunner: IActionRunner) {
|
||||
this._actionRunner = actionRunner;
|
||||
}
|
||||
|
||||
public get actionRunner(): IActionRunner {
|
||||
get actionRunner(): IActionRunner {
|
||||
return this._actionRunner;
|
||||
}
|
||||
|
||||
public getAction(): IAction {
|
||||
getAction(): IAction {
|
||||
return this._action;
|
||||
}
|
||||
|
||||
public isEnabled(): boolean {
|
||||
isEnabled(): boolean {
|
||||
return this._action.enabled;
|
||||
}
|
||||
|
||||
public setActionContext(newContext: any): void {
|
||||
setActionContext(newContext: any): void {
|
||||
this._context = newContext;
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
this.builder = $(container);
|
||||
render(container: HTMLElement): void {
|
||||
this.element = container;
|
||||
Gesture.addTarget(container);
|
||||
|
||||
const enableDragging = this.options && this.options.draggable;
|
||||
@@ -114,20 +111,19 @@ export class BaseActionItem implements IActionItem {
|
||||
container.draggable = true;
|
||||
}
|
||||
|
||||
this.builder.on(EventType.Tap, e => this.onClick(e));
|
||||
this._register(DOM.addDisposableListener(this.element, EventType.Tap, e => this.onClick(e)));
|
||||
|
||||
this.builder.on(DOM.EventType.MOUSE_DOWN, (e) => {
|
||||
this._register(DOM.addDisposableListener(this.element, DOM.EventType.MOUSE_DOWN, e => {
|
||||
if (!enableDragging) {
|
||||
DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
|
||||
}
|
||||
|
||||
const mouseEvent = e as MouseEvent;
|
||||
if (this._action.enabled && mouseEvent.button === 0) {
|
||||
this.builder.addClass('active');
|
||||
if (this._action.enabled && e.button === 0 && this.element) {
|
||||
DOM.addClass(this.element, 'active');
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this.builder.on(DOM.EventType.CLICK, (e) => {
|
||||
this._register(DOM.addDisposableListener(this.element, DOM.EventType.CLICK, e => {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
|
||||
// > Writing to the clipboard
|
||||
@@ -142,82 +138,90 @@ export class BaseActionItem implements IActionItem {
|
||||
} else {
|
||||
platform.setImmediate(() => this.onClick(e));
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this.builder.on([DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT], (e) => {
|
||||
DOM.EventHelper.stop(e);
|
||||
this.builder.removeClass('active');
|
||||
this._register(DOM.addDisposableListener(this.element, DOM.EventType.DBLCLICK, e => {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
}));
|
||||
|
||||
[DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(event => {
|
||||
this._register(DOM.addDisposableListener(this.element!, event, e => {
|
||||
DOM.EventHelper.stop(e);
|
||||
DOM.removeClass(this.element!, 'active');
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
public onClick(event: DOM.EventLike): void {
|
||||
onClick(event: DOM.EventLike): void {
|
||||
DOM.EventHelper.stop(event, true);
|
||||
|
||||
let context: any;
|
||||
if (types.isUndefinedOrNull(this._context) || !types.isObject(this._context)) {
|
||||
if (types.isUndefinedOrNull(this._context)) {
|
||||
context = event;
|
||||
} else {
|
||||
context = this._context;
|
||||
context.event = event;
|
||||
|
||||
if (types.isObject(context)) {
|
||||
context.event = event;
|
||||
}
|
||||
}
|
||||
|
||||
this._actionRunner.run(this._action, context);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
if (this.builder) {
|
||||
this.builder.domFocus();
|
||||
this.builder.addClass('focused');
|
||||
focus(): void {
|
||||
if (this.element) {
|
||||
this.element.focus();
|
||||
DOM.addClass(this.element, 'focused');
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
if (this.builder) {
|
||||
this.builder.domBlur();
|
||||
this.builder.removeClass('focused');
|
||||
blur(): void {
|
||||
if (this.element) {
|
||||
this.element.blur();
|
||||
DOM.removeClass(this.element, 'focused');
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateEnabled(): void {
|
||||
protected updateEnabled(): void {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
protected _updateLabel(): void {
|
||||
protected updateLabel(): void {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
protected _updateTooltip(): void {
|
||||
protected updateTooltip(): void {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
protected _updateClass(): void {
|
||||
protected updateClass(): void {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
protected _updateChecked(): void {
|
||||
protected updateChecked(): void {
|
||||
// implement in subclass
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.builder) {
|
||||
this.builder.destroy();
|
||||
this.builder = null;
|
||||
dispose(): void {
|
||||
if (this.element) {
|
||||
DOM.removeNode(this.element);
|
||||
this.element = undefined;
|
||||
}
|
||||
|
||||
this._callOnDispose = lifecycle.dispose(this._callOnDispose);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class Separator extends Action {
|
||||
|
||||
public static readonly ID = 'vs.actions.separator';
|
||||
static readonly ID = 'vs.actions.separator';
|
||||
|
||||
constructor(label?: string, order?: number) {
|
||||
constructor(label?: string) {
|
||||
super(Separator.ID, label, label ? 'separator text' : 'separator');
|
||||
this.checked = false;
|
||||
this.radio = false;
|
||||
this.enabled = false;
|
||||
this.order = order;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,9 +233,10 @@ export interface IActionItemOptions extends IBaseActionItemOptions {
|
||||
|
||||
export class ActionItem extends BaseActionItem {
|
||||
|
||||
protected $e: Builder;
|
||||
protected label: HTMLElement;
|
||||
protected options: IActionItemOptions;
|
||||
private cssClass: string;
|
||||
|
||||
private cssClass?: string;
|
||||
|
||||
constructor(context: any, action: IAction, options: IActionItemOptions = {}) {
|
||||
super(context, action, options);
|
||||
@@ -242,45 +247,47 @@ export class ActionItem extends BaseActionItem {
|
||||
this.cssClass = '';
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
|
||||
this.$e = $('a.action-label').appendTo(this.builder);
|
||||
if (this.element) {
|
||||
this.label = DOM.append(this.element, DOM.$('a.action-label'));
|
||||
}
|
||||
if (this._action.id === Separator.ID) {
|
||||
// A separator is a presentation item
|
||||
this.$e.attr({ role: 'presentation' });
|
||||
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
|
||||
} else {
|
||||
if (this.options.isMenu) {
|
||||
this.$e.attr({ role: 'menuitem' });
|
||||
this.label.setAttribute('role', 'menuitem');
|
||||
} else {
|
||||
this.$e.attr({ role: 'button' });
|
||||
this.label.setAttribute('role', 'button');
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.label && this.options.keybinding) {
|
||||
$('span.keybinding').text(this.options.keybinding).appendTo(this.builder);
|
||||
if (this.options.label && this.options.keybinding && this.element) {
|
||||
DOM.append(this.element, DOM.$('span.keybinding')).textContent = this.options.keybinding;
|
||||
}
|
||||
|
||||
this._updateClass();
|
||||
this._updateLabel();
|
||||
this._updateTooltip();
|
||||
this._updateEnabled();
|
||||
this._updateChecked();
|
||||
this.updateClass();
|
||||
this.updateLabel();
|
||||
this.updateTooltip();
|
||||
this.updateEnabled();
|
||||
this.updateChecked();
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
focus(): void {
|
||||
super.focus();
|
||||
this.$e.domFocus();
|
||||
|
||||
this.label.focus();
|
||||
}
|
||||
|
||||
public _updateLabel(): void {
|
||||
updateLabel(): void {
|
||||
if (this.options.label) {
|
||||
this.$e.text(this.getAction().label);
|
||||
this.label.textContent = this.getAction().label;
|
||||
}
|
||||
}
|
||||
|
||||
public _updateTooltip(): void {
|
||||
let title: string = null;
|
||||
updateTooltip(): void {
|
||||
let title: string | null = null;
|
||||
|
||||
if (this.getAction().tooltip) {
|
||||
title = this.getAction().tooltip;
|
||||
@@ -294,54 +301,67 @@ export class ActionItem extends BaseActionItem {
|
||||
}
|
||||
|
||||
if (title) {
|
||||
this.$e.attr({ title: title });
|
||||
this.label.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
public _updateClass(): void {
|
||||
updateClass(): void {
|
||||
if (this.cssClass) {
|
||||
this.$e.removeClass(this.cssClass);
|
||||
DOM.removeClasses(this.label, this.cssClass);
|
||||
}
|
||||
|
||||
if (this.options.icon) {
|
||||
this.cssClass = this.getAction().class;
|
||||
this.$e.addClass('icon');
|
||||
DOM.addClass(this.label, 'icon');
|
||||
if (this.cssClass) {
|
||||
this.$e.addClass(this.cssClass);
|
||||
DOM.addClasses(this.label, this.cssClass);
|
||||
}
|
||||
this._updateEnabled();
|
||||
|
||||
this.updateEnabled();
|
||||
} else {
|
||||
this.$e.removeClass('icon');
|
||||
DOM.removeClass(this.label, 'icon');
|
||||
}
|
||||
}
|
||||
|
||||
public _updateEnabled(): void {
|
||||
updateEnabled(): void {
|
||||
if (this.getAction().enabled) {
|
||||
this.builder.removeClass('disabled');
|
||||
this.$e.removeClass('disabled');
|
||||
this.$e.attr({ tabindex: 0 });
|
||||
this.label.removeAttribute('aria-disabled');
|
||||
if (this.element) {
|
||||
DOM.removeClass(this.element, 'disabled');
|
||||
}
|
||||
DOM.removeClass(this.label, 'disabled');
|
||||
this.label.tabIndex = 0;
|
||||
} else {
|
||||
this.builder.addClass('disabled');
|
||||
this.$e.addClass('disabled');
|
||||
DOM.removeTabIndexAndUpdateFocus(this.$e.getHTMLElement());
|
||||
this.label.setAttribute('aria-disabled', 'true');
|
||||
if (this.element) {
|
||||
DOM.addClass(this.element, 'disabled');
|
||||
}
|
||||
DOM.addClass(this.label, 'disabled');
|
||||
DOM.removeTabIndexAndUpdateFocus(this.label);
|
||||
}
|
||||
}
|
||||
|
||||
public _updateChecked(): void {
|
||||
updateChecked(): void {
|
||||
if (this.getAction().checked) {
|
||||
this.$e.addClass('checked');
|
||||
DOM.addClass(this.label, 'checked');
|
||||
} else {
|
||||
this.$e.removeClass('checked');
|
||||
DOM.removeClass(this.label, 'checked');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export enum ActionsOrientation {
|
||||
export const enum ActionsOrientation {
|
||||
HORIZONTAL,
|
||||
HORIZONTAL_REVERSE,
|
||||
VERTICAL,
|
||||
VERTICAL_REVERSE,
|
||||
}
|
||||
|
||||
export interface ActionTrigger {
|
||||
keys: KeyCode[];
|
||||
keyDown: boolean;
|
||||
}
|
||||
|
||||
export interface IActionItemProvider {
|
||||
(action: IAction): IActionItem;
|
||||
}
|
||||
@@ -353,54 +373,69 @@ export interface IActionBarOptions {
|
||||
actionRunner?: IActionRunner;
|
||||
ariaLabel?: string;
|
||||
animated?: boolean;
|
||||
isMenu?: boolean;
|
||||
triggerKeys?: ActionTrigger;
|
||||
}
|
||||
|
||||
let defaultOptions: IActionBarOptions = {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
context: null
|
||||
context: null,
|
||||
triggerKeys: {
|
||||
keys: [KeyCode.Enter, KeyCode.Space],
|
||||
keyDown: false
|
||||
}
|
||||
};
|
||||
|
||||
export interface IActionOptions extends IActionItemOptions {
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export class ActionBar implements IActionRunner {
|
||||
export class ActionBar extends Disposable implements IActionRunner {
|
||||
|
||||
public options: IActionBarOptions;
|
||||
options: IActionBarOptions;
|
||||
|
||||
private _actionRunner: IActionRunner;
|
||||
private _context: any;
|
||||
|
||||
// Items
|
||||
public items: IActionItem[];
|
||||
private focusedItem: number;
|
||||
items: IActionItem[];
|
||||
protected focusedItem?: number;
|
||||
private focusTracker: DOM.IFocusTracker;
|
||||
|
||||
// Elements
|
||||
public domNode: HTMLElement;
|
||||
private actionsList: HTMLElement;
|
||||
domNode: HTMLElement;
|
||||
protected actionsList: HTMLElement;
|
||||
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private _onDidBlur = this._register(new Emitter<void>());
|
||||
get onDidBlur(): Event<void> { return this._onDidBlur.event; }
|
||||
|
||||
private _onDidBlur = new Emitter<void>();
|
||||
private _onDidCancel = new Emitter<void>();
|
||||
private _onDidRun = new Emitter<IRunEvent>();
|
||||
private _onDidBeforeRun = new Emitter<IRunEvent>();
|
||||
private _onDidCancel = this._register(new Emitter<void>());
|
||||
get onDidCancel(): Event<void> { return this._onDidCancel.event; }
|
||||
|
||||
private _onDidRun = this._register(new Emitter<IRunEvent>());
|
||||
get onDidRun(): Event<IRunEvent> { return this._onDidRun.event; }
|
||||
|
||||
private _onDidBeforeRun = this._register(new Emitter<IRunEvent>());
|
||||
get onDidBeforeRun(): Event<IRunEvent> { return this._onDidBeforeRun.event; }
|
||||
|
||||
constructor(container: HTMLElement, options: IActionBarOptions = defaultOptions) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
this._context = options.context;
|
||||
this.toDispose = [];
|
||||
this._actionRunner = this.options.actionRunner;
|
||||
|
||||
if (!this._actionRunner) {
|
||||
this._actionRunner = new ActionRunner();
|
||||
this.toDispose.push(this._actionRunner);
|
||||
if (!this.options.triggerKeys) {
|
||||
this.options.triggerKeys = defaultOptions.triggerKeys;
|
||||
}
|
||||
|
||||
this.toDispose.push(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));
|
||||
this.toDispose.push(this._actionRunner.onDidBeforeRun(e => this._onDidBeforeRun.fire(e)));
|
||||
if (this.options.actionRunner) {
|
||||
this._actionRunner = this.options.actionRunner;
|
||||
} else {
|
||||
this._actionRunner = new ActionRunner();
|
||||
this._register(this._actionRunner);
|
||||
}
|
||||
|
||||
this._register(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));
|
||||
this._register(this._actionRunner.onDidBeforeRun(e => this._onDidBeforeRun.fire(e)));
|
||||
|
||||
this.items = [];
|
||||
this.focusedItem = undefined;
|
||||
@@ -437,8 +472,8 @@ export class ActionBar implements IActionRunner {
|
||||
break;
|
||||
}
|
||||
|
||||
$(this.domNode).on(DOM.EventType.KEY_DOWN, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
let eventHandled = true;
|
||||
|
||||
if (event.equals(previousKey)) {
|
||||
@@ -447,8 +482,11 @@ export class ActionBar implements IActionRunner {
|
||||
this.focusNext();
|
||||
} else if (event.equals(KeyCode.Escape)) {
|
||||
this.cancel();
|
||||
} else if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
// Nothing, just staying out of the else branch
|
||||
} else if (this.isTriggerKeyEvent(event)) {
|
||||
// Staying out of the else branch even if not triggered
|
||||
if (this.options.triggerKeys && this.options.triggerKeys.keyDown) {
|
||||
this.doTrigger(event);
|
||||
}
|
||||
} else {
|
||||
eventHandled = false;
|
||||
}
|
||||
@@ -457,14 +495,17 @@ export class ActionBar implements IActionRunner {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
$(this.domNode).on(DOM.EventType.KEY_UP, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_UP, e => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
|
||||
// Run action on Enter/Space
|
||||
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
this.doTrigger(event);
|
||||
if (this.isTriggerKeyEvent(event)) {
|
||||
if (this.options.triggerKeys && !this.options.triggerKeys.keyDown) {
|
||||
this.doTrigger(event);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
@@ -473,84 +514,32 @@ export class ActionBar implements IActionRunner {
|
||||
else if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) {
|
||||
this.updateFocusedItem();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this.focusTracker = DOM.trackFocus(this.domNode);
|
||||
this.toDispose.push(this.focusTracker.onDidBlur(() => {
|
||||
this.focusTracker = this._register(DOM.trackFocus(this.domNode));
|
||||
this._register(this.focusTracker.onDidBlur(() => {
|
||||
if (document.activeElement === this.domNode || !DOM.isAncestor(document.activeElement, this.domNode)) {
|
||||
this._onDidBlur.fire();
|
||||
this.focusedItem = undefined;
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));
|
||||
this._register(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));
|
||||
|
||||
this.actionsList = document.createElement('ul');
|
||||
this.actionsList.className = 'actions-container';
|
||||
if (this.options.isMenu) {
|
||||
this.actionsList.setAttribute('role', 'menu');
|
||||
} else {
|
||||
this.actionsList.setAttribute('role', 'toolbar');
|
||||
}
|
||||
this.actionsList.setAttribute('role', 'toolbar');
|
||||
|
||||
if (this.options.ariaLabel) {
|
||||
this.actionsList.setAttribute('aria-label', this.options.ariaLabel);
|
||||
}
|
||||
|
||||
if (this.options.isMenu) {
|
||||
this.domNode.tabIndex = 0;
|
||||
|
||||
$(this.domNode).on(DOM.EventType.MOUSE_OUT, (e) => {
|
||||
let relatedTarget = (e as MouseEvent).relatedTarget as HTMLElement;
|
||||
if (!DOM.isAncestor(relatedTarget, this.domNode)) {
|
||||
this.focusedItem = undefined;
|
||||
this.updateFocus();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
$(this.actionsList).on(DOM.EventType.MOUSE_OVER, (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
if (!target || !DOM.isAncestor(target, this.actionsList) || target === this.actionsList) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (target.parentElement !== this.actionsList) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
if (DOM.hasClass(target, 'action-item')) {
|
||||
const lastFocusedItem = this.focusedItem;
|
||||
this.setFocusedItem(target);
|
||||
|
||||
if (lastFocusedItem !== this.focusedItem) {
|
||||
this.updateFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.domNode.appendChild(this.actionsList);
|
||||
|
||||
container.appendChild(this.domNode);
|
||||
}
|
||||
|
||||
public get onDidBlur(): Event<void> {
|
||||
return this._onDidBlur.event;
|
||||
}
|
||||
|
||||
public get onDidCancel(): Event<void> {
|
||||
return this._onDidCancel.event;
|
||||
}
|
||||
|
||||
public get onDidRun(): Event<IRunEvent> {
|
||||
return this._onDidRun.event;
|
||||
}
|
||||
|
||||
public get onDidBeforeRun(): Event<IRunEvent> {
|
||||
return this._onDidBeforeRun.event;
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
setAriaLabel(label: string): void {
|
||||
if (label) {
|
||||
this.actionsList.setAttribute('aria-label', label);
|
||||
} else {
|
||||
@@ -558,14 +547,15 @@ export class ActionBar implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
private setFocusedItem(element: HTMLElement): void {
|
||||
for (let i = 0; i < this.actionsList.children.length; i++) {
|
||||
let elem = this.actionsList.children[i];
|
||||
if (element === elem) {
|
||||
this.focusedItem = i;
|
||||
break;
|
||||
}
|
||||
private isTriggerKeyEvent(event: StandardKeyboardEvent): boolean {
|
||||
let ret = false;
|
||||
if (this.options.triggerKeys) {
|
||||
this.options.triggerKeys.keys.forEach(keyCode => {
|
||||
ret = ret || event.equals(keyCode);
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private updateFocusedItem(): void {
|
||||
@@ -578,32 +568,31 @@ export class ActionBar implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
public get context(): any {
|
||||
get context(): any {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
public set context(context: any) {
|
||||
set context(context: any) {
|
||||
this._context = context;
|
||||
this.items.forEach(i => i.setActionContext(context));
|
||||
}
|
||||
|
||||
public get actionRunner(): IActionRunner {
|
||||
get actionRunner(): IActionRunner | undefined {
|
||||
return this._actionRunner;
|
||||
}
|
||||
|
||||
public set actionRunner(actionRunner: IActionRunner) {
|
||||
set actionRunner(actionRunner: IActionRunner | undefined) {
|
||||
if (actionRunner) {
|
||||
this._actionRunner = actionRunner;
|
||||
this.items.forEach(item => item.actionRunner = actionRunner);
|
||||
}
|
||||
}
|
||||
|
||||
public getContainer(): HTMLElement {
|
||||
getContainer(): HTMLElement {
|
||||
return this.domNode;
|
||||
}
|
||||
|
||||
public push(arg: IAction | IAction[], options: IActionOptions = {}): void {
|
||||
|
||||
push(arg: IAction | IAction[], options: IActionOptions = {}): void {
|
||||
const actions: IAction[] = !Array.isArray(arg) ? [arg] : arg;
|
||||
|
||||
let index = types.isNumber(options.index) ? options.index : null;
|
||||
@@ -614,12 +603,12 @@ export class ActionBar implements IActionRunner {
|
||||
actionItemElement.setAttribute('role', 'presentation');
|
||||
|
||||
// Prevent native context menu on actions
|
||||
$(actionItemElement).on(DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {
|
||||
this._register(DOM.addDisposableListener(actionItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
}));
|
||||
|
||||
let item: IActionItem = null;
|
||||
let item: IActionItem | null = null;
|
||||
|
||||
if (this.options.actionItemProvider) {
|
||||
item = this.options.actionItemProvider(action);
|
||||
@@ -641,52 +630,73 @@ export class ActionBar implements IActionRunner {
|
||||
this.items.splice(index, 0, item);
|
||||
index++;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public getWidth(index: number): number {
|
||||
getWidth(index: number): number {
|
||||
if (index >= 0 && index < this.actionsList.children.length) {
|
||||
return this.actionsList.children.item(index).clientWidth;
|
||||
const item = this.actionsList.children.item(index);
|
||||
if (item) {
|
||||
return item.clientWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public getHeight(index: number): number {
|
||||
getHeight(index: number): number {
|
||||
if (index >= 0 && index < this.actionsList.children.length) {
|
||||
return this.actionsList.children.item(index).clientHeight;
|
||||
const item = this.actionsList.children.item(index);
|
||||
if (item) {
|
||||
return item.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public pull(index: number): void {
|
||||
pull(index: number): void {
|
||||
if (index >= 0 && index < this.items.length) {
|
||||
this.items.splice(index, 1);
|
||||
this.actionsList.removeChild(this.actionsList.childNodes[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
this.items = lifecycle.dispose(this.items);
|
||||
$(this.actionsList).empty();
|
||||
clear(): void {
|
||||
this.items = dispose(this.items);
|
||||
DOM.clearNode(this.actionsList);
|
||||
}
|
||||
|
||||
public length(): number {
|
||||
length(): number {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
isEmpty(): boolean {
|
||||
return this.items.length === 0;
|
||||
}
|
||||
|
||||
public focus(selectFirst?: boolean): void {
|
||||
focus(index?: number): void;
|
||||
focus(selectFirst?: boolean): void;
|
||||
focus(arg?: any): void {
|
||||
let selectFirst: boolean = false;
|
||||
let index: number | undefined = void 0;
|
||||
if (arg === undefined) {
|
||||
selectFirst = true;
|
||||
} else if (typeof arg === 'number') {
|
||||
index = arg;
|
||||
} else if (typeof arg === 'boolean') {
|
||||
selectFirst = arg;
|
||||
}
|
||||
|
||||
if (selectFirst && typeof this.focusedItem === 'undefined') {
|
||||
// Focus the first enabled item
|
||||
this.focusedItem = this.items.length - 1;
|
||||
this.focusNext();
|
||||
} else {
|
||||
if (index !== undefined) {
|
||||
this.focusedItem = index;
|
||||
}
|
||||
|
||||
this.updateFocus();
|
||||
}
|
||||
}
|
||||
@@ -736,22 +746,22 @@ export class ActionBar implements IActionRunner {
|
||||
this.updateFocus(true);
|
||||
}
|
||||
|
||||
private updateFocus(fromRight?: boolean): void {
|
||||
protected updateFocus(fromRight?: boolean): void {
|
||||
if (typeof this.focusedItem === 'undefined') {
|
||||
this.domNode.focus();
|
||||
this.actionsList.focus();
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
let item = this.items[i];
|
||||
|
||||
let actionItem = <any>item;
|
||||
let actionItem = item;
|
||||
|
||||
if (i === this.focusedItem) {
|
||||
if (types.isFunction(actionItem.isEnabled)) {
|
||||
if (actionItem.isEnabled() && types.isFunction(actionItem.focus)) {
|
||||
actionItem.focus(fromRight);
|
||||
} else {
|
||||
this.domNode.focus();
|
||||
this.actionsList.focus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -771,7 +781,7 @@ export class ActionBar implements IActionRunner {
|
||||
let actionItem = this.items[this.focusedItem];
|
||||
if (actionItem instanceof BaseActionItem) {
|
||||
const context = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context;
|
||||
this.run(actionItem._action, context).done();
|
||||
this.run(actionItem._action, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,78 +793,63 @@ export class ActionBar implements IActionRunner {
|
||||
this._onDidCancel.fire();
|
||||
}
|
||||
|
||||
public run(action: IAction, context?: any): TPromise<void> {
|
||||
run(action: IAction, context?: any): Thenable<void> {
|
||||
return this._actionRunner.run(action, context);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.items !== null) {
|
||||
lifecycle.dispose(this.items);
|
||||
}
|
||||
this.items = null;
|
||||
dispose(): void {
|
||||
dispose(this.items);
|
||||
this.items = [];
|
||||
|
||||
if (this.focusTracker) {
|
||||
this.focusTracker.dispose();
|
||||
this.focusTracker = null;
|
||||
}
|
||||
DOM.removeNode(this.getContainer());
|
||||
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
|
||||
$(this.getContainer()).destroy();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectActionItem extends BaseActionItem {
|
||||
protected selectBox: SelectBox;
|
||||
protected toDispose: lifecycle.IDisposable[];
|
||||
|
||||
constructor(ctx: any, action: IAction, options: string[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions
|
||||
) {
|
||||
constructor(ctx: any, action: IAction, options: string[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) {
|
||||
super(ctx, action);
|
||||
this.selectBox = new SelectBox(options, selected, contextViewProvider, null, selectBoxOptions);
|
||||
|
||||
this.toDispose = [];
|
||||
this.toDispose.push(this.selectBox);
|
||||
this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
|
||||
|
||||
this._register(this.selectBox);
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
public setOptions(options: string[], selected?: number, disabled?: number): void {
|
||||
setOptions(options: string[], selected?: number, disabled?: number): void {
|
||||
this.selectBox.setOptions(options, selected, disabled);
|
||||
}
|
||||
|
||||
public select(index: number): void {
|
||||
select(index: number): void {
|
||||
this.selectBox.select(index);
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.selectBox.onDidSelect(e => {
|
||||
this.actionRunner.run(this._action, this.getActionContext(e.selected)).done();
|
||||
this._register(this.selectBox.onDidSelect(e => {
|
||||
this.actionRunner.run(this._action, this.getActionContext(e.selected, e.index));
|
||||
}));
|
||||
}
|
||||
|
||||
protected getActionContext(option: string) {
|
||||
protected getActionContext(option: string, index: number) {
|
||||
return option;
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
focus(): void {
|
||||
if (this.selectBox) {
|
||||
this.selectBox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
blur(): void {
|
||||
if (this.selectBox) {
|
||||
this.selectBox.blur();
|
||||
}
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
render(container: HTMLElement): void {
|
||||
this.selectBox.render(container);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user