mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 17:22:45 -05:00
* Genericify components * Fix compile issue * Fix feedback * Genericify azdata components (#12164) * azdata generics * Add the withProps method to azdata proposed as there may be mistakes with the interfaces in the generics * Fix build issues because of other extensions * Remove extra spaces
199 lines
6.2 KiB
TypeScript
199 lines
6.2 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
import { ChangeDetectorRef, Component, ElementRef, forwardRef, Inject, Input, OnDestroy, QueryList, ViewChildren } from '@angular/core';
|
|
import * as azdata from 'azdata';
|
|
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
|
|
import { createIconCssClass } from 'sql/workbench/browser/modelComponents/iconUtils';
|
|
import * as DOM from 'vs/base/browser/dom';
|
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
|
|
|
import 'vs/css!./media/card';
|
|
import 'vs/css!./media/verticalCard';
|
|
|
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
|
import { deepClone } from 'vs/base/common/objects';
|
|
|
|
@Component({
|
|
templateUrl: decodeURI(require.toUrl('./radioCardGroup.component.html'))
|
|
})
|
|
export default class RadioCardGroup extends ComponentBase<azdata.RadioCardGroupComponentProperties> implements IComponent, OnDestroy {
|
|
@Input() descriptor: IComponentDescriptor;
|
|
@Input() modelStore: IModelStore;
|
|
@ViewChildren('cardDiv') cardElements: QueryList<ElementRef>;
|
|
|
|
private focusedCardId: string | undefined;
|
|
private iconClasses: { [key: string]: string } = {};
|
|
|
|
constructor(
|
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
|
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
|
) {
|
|
super(changeRef, el);
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.baseInit();
|
|
}
|
|
|
|
setLayout(layout: any): void {
|
|
this.layout();
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
Object.keys(this.iconClasses).forEach((key) => {
|
|
DOM.removeCSSRulesContainingSelector(this.iconClasses[key]);
|
|
});
|
|
this.baseDestroy();
|
|
}
|
|
|
|
onKeyDown(event: KeyboardEvent): void {
|
|
if (!this.enabled || this.cards.length === 0) {
|
|
return;
|
|
}
|
|
|
|
let e = new StandardKeyboardEvent(event);
|
|
if (e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space) {
|
|
if (this.focusedCardId && !this.selectedCardId) {
|
|
this.selectCard(this.focusedCardId);
|
|
}
|
|
DOM.EventHelper.stop(e, true);
|
|
}
|
|
else if (e.keyCode === KeyCode.LeftArrow || e.keyCode === KeyCode.UpArrow) {
|
|
if (this.focusedCardId) {
|
|
this.selectCard(this.findPreviousCard(this.focusedCardId));
|
|
}
|
|
DOM.EventHelper.stop(e, true);
|
|
} else if (e.keyCode === KeyCode.RightArrow || e.keyCode === KeyCode.DownArrow) {
|
|
if (this.focusedCardId) {
|
|
this.selectCard(this.findNextCard(this.focusedCardId));
|
|
}
|
|
DOM.EventHelper.stop(e, true);
|
|
}
|
|
}
|
|
|
|
private getCardById(cardId: string): azdata.RadioCard {
|
|
const filteredCards = this.cards.filter(c => { return c.id === cardId; });
|
|
if (filteredCards.length === 1) {
|
|
return filteredCards[0];
|
|
} else {
|
|
throw new Error(`There should be one and only one matching card for the giving card id, actual number: ${filteredCards.length}, card id: ${cardId}.`);
|
|
}
|
|
}
|
|
|
|
private findPreviousCard(cardId: string): string {
|
|
const currentIndex = this.cards.indexOf(this.getCardById(cardId));
|
|
const previousCardIndex = currentIndex === 0 ? this.cards.length - 1 : currentIndex - 1;
|
|
return this.cards[previousCardIndex].id;
|
|
}
|
|
|
|
private findNextCard(cardId: string): string {
|
|
const currentIndex = this.cards.indexOf(this.getCardById(cardId));
|
|
const nextCardIndex = currentIndex === this.cards.length - 1 ? 0 : currentIndex + 1;
|
|
return this.cards[nextCardIndex].id;
|
|
}
|
|
|
|
public get cards(): azdata.RadioCard[] {
|
|
return this.getProperties().cards ?? [];
|
|
}
|
|
|
|
public get cardWidth(): string | undefined {
|
|
return this.getProperties().cardWidth ?? undefined;
|
|
}
|
|
|
|
public get cardHeight(): string | undefined {
|
|
return this.getProperties().cardHeight ?? undefined;
|
|
}
|
|
|
|
public get iconWidth(): string | undefined {
|
|
return this.getProperties().iconWidth ?? undefined;
|
|
}
|
|
|
|
public get iconHeight(): string | undefined {
|
|
return this.getProperties().iconHeight ?? undefined;
|
|
}
|
|
|
|
public get selectedCardId(): string | undefined {
|
|
return this.getProperties().selectedCardId ?? undefined;
|
|
}
|
|
|
|
public get orientation(): string {
|
|
const x = this.getProperties().orientation ?? 'horizontal';
|
|
return x;
|
|
}
|
|
|
|
public getIconClass(cardId: string): string {
|
|
if (!this.iconClasses[cardId]) {
|
|
this.iconClasses[cardId] = `cardIcon icon ${createIconCssClass(this.getCardById(cardId).icon)}`;
|
|
}
|
|
return this.iconClasses[cardId];
|
|
}
|
|
|
|
public setProperties(properties: { [key: string]: any }) {
|
|
super.setProperties(properties);
|
|
// This is the entry point for the extension to set the selectedCardId
|
|
if (this.selectedCardId) {
|
|
this.selectCard(this.selectedCardId);
|
|
}
|
|
}
|
|
|
|
public selectCard(cardId: string): void {
|
|
if (!this.enabled || this.cards.length === 0) {
|
|
return;
|
|
}
|
|
const cardElement = this.getCardElement(cardId);
|
|
cardElement.nativeElement.focus();
|
|
this.setPropertyFromUI<string | undefined>((props, value) => props.selectedCardId = value, cardId);
|
|
this._changeRef.detectChanges();
|
|
this.fireEvent({
|
|
eventType: ComponentEventType.onDidChange,
|
|
args: {
|
|
cardId,
|
|
card: deepClone(this.getCardById(cardId))
|
|
}
|
|
});
|
|
}
|
|
|
|
public onLinkClick(event: Event, cardId: string, textContents: azdata.RadioCardDescription): void {
|
|
event.stopPropagation();
|
|
this.fireEvent({
|
|
eventType: ComponentEventType.onDidClick,
|
|
args: {
|
|
cardId,
|
|
textContents: deepClone(textContents),
|
|
card: deepClone(this.getCardById(cardId))
|
|
}
|
|
});
|
|
}
|
|
|
|
public getCardElement(cardId: string): ElementRef {
|
|
const card = this.getCardById(cardId);
|
|
return this.cardElements.toArray()[this.cards.indexOf(card)];
|
|
}
|
|
|
|
public getTabIndex(cardId: string): number {
|
|
if (!this.enabled) {
|
|
return -1;
|
|
}
|
|
else if (!this.selectedCardId) {
|
|
return this.cards.indexOf(this.getCardById(cardId)) === 0 ? 0 : -1;
|
|
} else {
|
|
return cardId === this.selectedCardId ? 0 : -1;
|
|
}
|
|
}
|
|
|
|
public isCardSelected(cardId: string): boolean {
|
|
return cardId === this.selectedCardId;
|
|
}
|
|
|
|
public onCardFocus(cardId: string): void {
|
|
this.focusedCardId = cardId;
|
|
}
|
|
|
|
public onCardBlur(cardId: string): void {
|
|
this.focusedCardId = undefined;
|
|
}
|
|
}
|