mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-25 09:35:37 -05:00
dashboard improvement (#9730)
* dashboard improvement - WIP (#8836) * wip * wip * tabgroup * tab group * agent views * clean up * formats * feedback * fix error * contribute top level server/db dashboard tab (#8868) * tabbedPanel component (#8861) * tabbed panel * tabbed panel * fix errors * revert main.ts changes * use margin * address comments * remove orientation property * content tab group (#8878) * add databases tab * use more extensible approach * remove unnecessary code * add when expression * objects tab for database dashboard (#8892) * fix build errors * fix build error * Dashboard toolbar (#9118) * remove old toolbar with only edit and refresh * remove tasks widgets from server and databases dashboards * adding toolbar to dashboardpage and clicking new query works * restore and new notebook now do something * add backup to toolbar for database dashboards * new notebook connects to db * only show backup and restore for non-azure * new backup and restore svgs * clean up * got toolbar actions to show up from contribution * some cleanup and add database dashboard toolbar contributions * don't show all tasks when there should be no tasks * fix toolbar showing multiple times when switching opening another dashboard from OE * only show toolbar for home page * update to new icons - same icons for light and dark theme * don't show separator if there aren't any actions * read toolbar actions from tasks-widget * remove tasks widget from home dashboard page * show extension's actions in toolbar * clean up * more cleaning up * fix extension actions not always loading the first time * add configure dashboard * remove old edit icon css * change tasks back to original order * make sure tasks widget is the one being removed * collapsible tab panel (#9221) * collapsible vertical tab panel * fix lint error * comments batch 1 * pr comments * update new query icon (#9351) * Update toolbar actions (#9313) * remove edit and configure dashboard and add refresh to toolbar for other dashboard pages too * Add refresh for tabs that have container type with refresh implemented * change refresh to only refresh the current tab * remove map for tab to actions * add back configure dashboard to home toolbar * check if index is -1 before trying to remove tasks widget from widgets * Move objects widget back to database home tab (#9432) * move objects widget back to database home tab and reorder toolbar * change order of actions back to previous order * Allow extensions to add actions to home toolbar (#9269) * add support for extensions to add actions to home toolbar * fix spacing * use menu contribution point * undo previous changes that added dashboardToolbarHomeAction contribution * remove home from name * add context key for tab name * allow actions to also be added to the toolbar of other tabs * add extension contributed actions even if no tasks-widget * fix refresh being added twice after merging * hide the tab list when collapsed (#9529) * update the order of css selectors (#9606) * Update dashboard style to be closer to mockups (#9570) * update style to be closer to mockups * tab panel styling * change back tab styling for tabs in a tab contributed by an extension * change color of borders when theme changes * set dark theme active tab background to same as OE for now * update border colors * move colors to theme file * fix a few issues (#9690) * couple fixes * comments * small dashboard toolbar fixes (#9695) * fix backup icon in toolbar * fix database page toolbar border color * add back center center in common-icons.css (#9703) * change padding so bottom border shows again (#9710) * tab panel fixes (#9724) * tab panel fixes * fix package.nls.json * feedbacks (#9761) * feedbacks * remove comments Co-authored-by: Kim Santiago <31145923+kisantia@users.noreply.github.com>
This commit is contained in:
1
src/sql/base/browser/ui/panel/media/collapse.svg
Normal file
1
src/sql/base/browser/ui/panel/media/collapse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 26 26" height="26px" id="Layer_1" version="1.1" viewBox="0 0 26 26" width="26px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><polygon fill="#231F20" points="23.885,0.58 25.969,2.664 15.133,13.5 25.969,24.336 23.885,26.42 10.965,13.5 "/><polygon fill="#231F20" points="12.885,0.58 14.969,2.664 4.133,13.5 14.969,24.336 12.885,26.42 -0.035,13.5 "/></g></svg>
|
||||
|
After Width: | Height: | Size: 570 B |
12
src/sql/base/browser/ui/panel/media/collapse_inverse.svg
Normal file
12
src/sql/base/browser/ui/panel/media/collapse_inverse.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="26" height="26" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="402" width="582" y="-1" x="-1"/>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<polygon id="svg_2" points="23.885,0.58 25.969,2.664 15.133,13.5 25.969,24.336 23.885,26.42 10.965,13.5 " fill="#ffffff"/>
|
||||
<polygon id="svg_3" points="12.885,0.58 14.969,2.664 4.133,13.5 14.969,24.336 12.885,26.42 -0.035,13.5 " fill="#ffffff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 481 B |
1
src/sql/base/browser/ui/panel/media/expand.svg
Normal file
1
src/sql/base/browser/ui/panel/media/expand.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 26 26" height="26px" id="Layer_1" version="1.1" viewBox="0 0 26 26" width="26px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><polygon fill="#231F20" points="2.049,0.58 -0.035,2.664 10.801,13.5 -0.035,24.336 2.049,26.42 14.969,13.5 "/><polygon fill="#231F20" points="13.049,0.58 10.965,2.664 21.801,13.5 10.965,24.336 13.049,26.42 25.969,13.5 "/></g></svg>
|
||||
|
After Width: | Height: | Size: 569 B |
12
src/sql/base/browser/ui/panel/media/expand_inverse.svg
Normal file
12
src/sql/base/browser/ui/panel/media/expand_inverse.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="26" height="26" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="402" width="582" y="-1" x="-1"/>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<polygon id="svg_2" points="2.1818366795778275,0.048653364181518555 0.09783665463328362,2.1326534152030945 10.933836296200752,12.968653380870819 0.09783665463328362,23.804653823375702 2.1818366795778275,25.888653457164764 15.101836517453194,12.968653380870819 " fill="#ffffff"/>
|
||||
<polygon id="svg_3" points="13.049,0.58 10.965,2.664 21.801,13.5 10.965,24.336 13.049,26.42 25.969,13.5 " fill="#ffffff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
@@ -59,7 +59,7 @@ panel {
|
||||
display: flex;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
min-width: 65px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical .tabList .tab-header {
|
||||
@@ -67,17 +67,16 @@ panel {
|
||||
text-transform: none;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 65px;
|
||||
width: auto;
|
||||
height: 50px;
|
||||
line-height: 45px;
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .tab .tabLabel.codicon {
|
||||
.tabbedPanel .tabList .tab .tabIcon.codicon {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 20px;
|
||||
padding: 20px 25px;
|
||||
line-height: 50px;
|
||||
background-position: 2px center;
|
||||
background-size: 16px;
|
||||
padding: 2px 2px 2px 22px;
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .actions-container {
|
||||
@@ -117,24 +116,20 @@ panel {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical .tabList {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tabbedPanel > .tab-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical > .title > .tabList {
|
||||
.tabbedPanel.vertical > .title > .tabContainer > .monaco-scrollable-element > .tabList {
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.tabbedPanel.horizontal > .title > .tabList {
|
||||
.tabbedPanel.horizontal > .title > .tabContainer > .monaco-scrollable-element > .tabList {
|
||||
flex-flow: row;
|
||||
}
|
||||
|
||||
.tabbedPanel > .title > .monaco-scrollable-element {
|
||||
.tabbedPanel > .title > .tabContainer > .monaco-scrollable-element {
|
||||
flex: 0 1 auto;
|
||||
width: inherit;
|
||||
}
|
||||
@@ -147,3 +142,47 @@ panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabbedPanel .tab-group-header {
|
||||
font-weight: bold;
|
||||
margin: 15px 5px 3px 5px;
|
||||
line-height: 35px;
|
||||
height: 35px;
|
||||
border-style: solid;
|
||||
border-width: 0 0 1px 0;
|
||||
border-color: rgb(214, 214, 214);
|
||||
}
|
||||
|
||||
.tabbedPanel .action-container {
|
||||
display: flex;
|
||||
flex-flow: row-reverse;
|
||||
}
|
||||
|
||||
.tabbedPanel .tab-action {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
background-color: transparent;
|
||||
background-position: 2px center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 11px 11px;
|
||||
}
|
||||
|
||||
.vs .tabbedPanel .tab-action.collapse{
|
||||
background-image: url("collapse.svg");
|
||||
}
|
||||
|
||||
.vs-dark .tabbedPanel .tab-action.collapse,
|
||||
.hc-black .tabbedPanel .tab-action.collapse {
|
||||
background-image: url("collapse_inverse.svg");
|
||||
}
|
||||
|
||||
.vs .tabbedPanel .tab-action.expand {
|
||||
background-image: url("expand.svg");
|
||||
}
|
||||
|
||||
.vs-dark .tabbedPanel .tab-action.expand,
|
||||
.hc-black .tabbedPanel .tab-action.expand {
|
||||
background-image: url("expand_inverse.svg");
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ tab-header .tab-header.active .action-label, /* always show it for active tab
|
||||
tab-header .tab-header:hover .action-label, /* always show it on hover */
|
||||
tab-header .tab-header:focus .action-label { /* always show it on focus */
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import {
|
||||
Component, ContentChildren, QueryList, Inject, forwardRef, NgZone,
|
||||
Input, EventEmitter, Output, ViewChild, ElementRef
|
||||
Input, EventEmitter, Output, ViewChild, ElementRef, ChangeDetectorRef, ViewChildren
|
||||
} from '@angular/core';
|
||||
|
||||
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
|
||||
@@ -19,6 +19,10 @@ import { mixin } from 'vs/base/common/objects';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import * as nls from 'vs/nls';
|
||||
import { TabHeaderComponent } from 'sql/base/browser/ui/panel/tabHeader.component';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
export interface IPanelOptions {
|
||||
/**
|
||||
@@ -48,9 +52,19 @@ let idPool = 0;
|
||||
<div class="tabbedPanel fullsize" [ngClass]="options.layout === NavigationBarLayout.vertical ? 'vertical' : 'horizontal'">
|
||||
<div *ngIf="!options.showTabsWhenOne ? _tabs.length !== 1 : true" class="composite title">
|
||||
<div class="tabContainer">
|
||||
<div class="tabList" role="tablist" scrollable [horizontalScroll]="AutoScrollbarVisibility" [verticalScroll]="HiddenScrollbarVisibility" [scrollYToX]="true">
|
||||
<div *ngIf="options.layout === NavigationBarLayout.vertical" class="action-container">
|
||||
<button [attr.aria-expanded]="_tabExpanded" [title]="toggleTabPanelButtonAriaLabel" [attr.aria-label]="toggleTabPanelButtonAriaLabel" [ngClass]="toggleTabPanelButtonCssClass" tabindex="0" (click)="toggleTabPanel()"></button>
|
||||
</div>
|
||||
<div *ngIf="_tabExpanded" class="tabList" role="tablist" scrollable [horizontalScroll]="AutoScrollbarVisibility" [verticalScroll]="HiddenScrollbarVisibility" [scrollYToX]="true" (keydown)="onKey($event)">
|
||||
<div role="presentation" *ngFor="let tab of _tabs">
|
||||
<tab-header role="presentation" [active]="_activeTab === tab" [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'></tab-header>
|
||||
<ng-container *ngIf="tab.type!=='group-header'">
|
||||
<tab-header role="presentation" [active]="_activeTab === tab" [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'></tab-header>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="tab.type==='group-header' && options.layout === NavigationBarLayout.vertical">
|
||||
<div class="tab-group-header" *ngIf="_tabExpanded">
|
||||
<span>{{tab.title}}</span>
|
||||
</div>
|
||||
</ng-container >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,6 +85,7 @@ export class PanelComponent extends Disposable {
|
||||
@Input() public options?: IPanelOptions;
|
||||
@Input() public actions?: Array<Action>;
|
||||
@ContentChildren(TabComponent) private readonly _tabs!: QueryList<TabComponent>;
|
||||
@ViewChildren(TabHeaderComponent) private readonly _tabHeaders!: QueryList<TabHeaderComponent>;
|
||||
@ViewChild(ScrollableDirective) private scrollable?: ScrollableDirective;
|
||||
|
||||
@Output() public onTabChange = new EventEmitter<TabComponent>();
|
||||
@@ -79,16 +94,32 @@ export class PanelComponent extends Disposable {
|
||||
private _activeTab?: TabComponent;
|
||||
private _actionbar?: ActionBar;
|
||||
private _mru: TabComponent[] = [];
|
||||
private _tabExpanded: boolean = true;
|
||||
|
||||
protected AutoScrollbarVisibility = ScrollbarVisibility.Auto; // used by angular template
|
||||
protected HiddenScrollbarVisibility = ScrollbarVisibility.Hidden; // used by angular template
|
||||
protected NavigationBarLayout = NavigationBarLayout; // used by angular template
|
||||
|
||||
@ViewChild('panelActionbar', { read: ElementRef }) private _actionbarRef!: ElementRef;
|
||||
constructor(@Inject(forwardRef(() => NgZone)) private _zone: NgZone) {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => NgZone)) private _zone: NgZone,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef) {
|
||||
super();
|
||||
}
|
||||
|
||||
public get toggleTabPanelButtonCssClass(): string {
|
||||
return this._tabExpanded ? 'tab-action collapse' : 'tab-action expand';
|
||||
}
|
||||
|
||||
public get toggleTabPanelButtonAriaLabel(): string {
|
||||
return this._tabExpanded ? nls.localize('hideTextLabel', "Hide text labels") : nls.localize('showTextLabel', "Show text labels");
|
||||
}
|
||||
|
||||
toggleTabPanel(): void {
|
||||
this._tabExpanded = !this._tabExpanded;
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.options = mixin(this.options || {}, defaultOptions, false);
|
||||
}
|
||||
@@ -245,4 +276,49 @@ export class PanelComponent extends Disposable {
|
||||
public layout() {
|
||||
this._activeTab?.layout();
|
||||
}
|
||||
|
||||
onKey(e: KeyboardEvent): void {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
let eventHandled: boolean = false;
|
||||
if (event.equals(KeyCode.DownArrow) || event.equals(KeyCode.RightArrow)) {
|
||||
this.focusNextTab();
|
||||
eventHandled = true;
|
||||
} else if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.LeftArrow)) {
|
||||
this.focusPreviousTab();
|
||||
eventHandled = true;
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private focusPreviousTab(): void {
|
||||
const currentIndex = this.focusedTabHeaderIndex;
|
||||
if (currentIndex !== -1) {
|
||||
// Move to the previous tab, if we are at the first tab then move to the last tab.
|
||||
this.focusOnTabHeader(currentIndex === 0 ? this._tabHeaders.length - 1 : currentIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private focusNextTab(): void {
|
||||
const currentIndex = this.focusedTabHeaderIndex;
|
||||
if (currentIndex !== -1) {
|
||||
// Move to the next tab, if we are at the last tab then move to the first tab.
|
||||
this.focusOnTabHeader(currentIndex === this._tabHeaders.length - 1 ? 0 : currentIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private focusOnTabHeader(index: number): void {
|
||||
if (index >= 0 && index <= this._tabHeaders.length - 1) {
|
||||
this._tabHeaders.toArray()[index].focusOnTabHeader();
|
||||
}
|
||||
}
|
||||
|
||||
private get focusedTabHeaderIndex(): number {
|
||||
return this._tabHeaders.toArray().findIndex((header) => {
|
||||
return header.nativeElement === document.activeElement;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ export abstract class TabChild extends AngularDisposable {
|
||||
public abstract layout(): void;
|
||||
}
|
||||
|
||||
export type TabType = 'tab' | 'group-header';
|
||||
|
||||
@Component({
|
||||
selector: 'tab',
|
||||
template: `
|
||||
@@ -29,6 +31,7 @@ export class TabComponent implements OnDestroy {
|
||||
@Input() public iconClass?: string;
|
||||
public _active = false;
|
||||
@Input() public identifier!: string;
|
||||
@Input() public type: TabType = 'tab';
|
||||
@Input() private visibilityType: 'if' | 'visibility' = 'if';
|
||||
private rendered = false;
|
||||
private destroyed: boolean = false;
|
||||
|
||||
@@ -19,10 +19,13 @@ import { CloseTabAction } from 'sql/base/browser/ui/panel/tabActions';
|
||||
@Component({
|
||||
selector: 'tab-header',
|
||||
template: `
|
||||
<div #actionHeader role="presentation" class="tab-header" style="flex: 0 0; flex-direction: row; height: 100%" [class.active]="tab.active" tabindex="0" (keyup)="onKey($event)">
|
||||
<span class="tab" (click)="selectTab(tab)" role="tab" [attr.aria-selected]="tab.active" [attr.aria-controls]="tab.title">
|
||||
<a class="tabLabel" [class.active]="tab.active" #tabLabel>
|
||||
</a>
|
||||
<div #actionHeader role="tab" [attr.aria-selected]="tab.active" [attr.aria-label]="tab.title" class="tab-header" style="flex: 0 0; flex-direction: row; height: 100%" [class.active]="tab.active" tabindex="0" (click)="selectTab(tab)" (keyup)="onKey($event)">
|
||||
<span class="tab" role="presentation">
|
||||
<div role="presentation">
|
||||
<a #tabIcon></a>
|
||||
<a class="tabLabel" [class.active]="tab.active" #tabLabel>
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
<span #actionbar style="flex: 0 0 auto; align-self: end; margin-top: auto; margin-bottom: auto;" ></span>
|
||||
</div>
|
||||
@@ -34,16 +37,23 @@ export class TabHeaderComponent extends Disposable implements AfterContentInit,
|
||||
@Input() public active?: boolean;
|
||||
@Output() public onSelectTab: EventEmitter<TabComponent> = new EventEmitter<TabComponent>();
|
||||
@Output() public onCloseTab: EventEmitter<TabComponent> = new EventEmitter<TabComponent>();
|
||||
@Output() public onFocusTab: EventEmitter<TabComponent> = new EventEmitter<TabComponent>();
|
||||
|
||||
private _actionbar!: ActionBar;
|
||||
|
||||
@ViewChild('actionHeader', { read: ElementRef }) private _actionHeaderRef!: ElementRef;
|
||||
@ViewChild('actionbar', { read: ElementRef }) private _actionbarRef!: ElementRef;
|
||||
@ViewChild('tabLabel', { read: ElementRef }) private _tabLabelRef!: ElementRef;
|
||||
@ViewChild('tabIcon', { read: ElementRef }) private _tabIconRef!: ElementRef;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public get nativeElement(): HTMLElement {
|
||||
return this._actionHeaderRef.nativeElement;
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
if (this.tab.canClose || this.tab.actions) {
|
||||
this._actionbar = new ActionBar(this._actionbarRef.nativeElement);
|
||||
@@ -56,15 +66,14 @@ export class TabHeaderComponent extends Disposable implements AfterContentInit,
|
||||
}
|
||||
}
|
||||
|
||||
let tabLabelcontainer = this._tabLabelRef.nativeElement as HTMLElement;
|
||||
const tabLabelContainer = this._tabLabelRef.nativeElement as HTMLElement;
|
||||
if (this.showIcon && this.tab.iconClass) {
|
||||
tabLabelcontainer.className = 'tabLabel codicon';
|
||||
tabLabelcontainer.classList.add(this.tab.iconClass);
|
||||
} else {
|
||||
tabLabelcontainer.className = 'tabLabel';
|
||||
tabLabelcontainer.textContent = this.tab.title;
|
||||
const tabIconContainer = this._tabIconRef.nativeElement as HTMLElement;
|
||||
tabIconContainer.className = 'tabIcon codicon';
|
||||
tabIconContainer.classList.add(this.tab.iconClass);
|
||||
}
|
||||
tabLabelcontainer.title = this.tab.title;
|
||||
|
||||
tabLabelContainer.textContent = this.tab.title;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -90,7 +99,7 @@ export class TabHeaderComponent extends Disposable implements AfterContentInit,
|
||||
onKey(e: Event) {
|
||||
if (DOM.isAncestor(<HTMLElement>e.target, this._actionHeaderRef.nativeElement) && e instanceof KeyboardEvent) {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Enter)) {
|
||||
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
this.onSelectTab.emit(this.tab);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user