/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/divContainer';
import {
Component, Input, Inject, ChangeDetectorRef, forwardRef,
ViewChild, ElementRef, OnDestroy, Renderer2, AfterViewInit
} from '@angular/core';
import * as azdata from 'azdata';
import { ContainerBase } from 'sql/workbench/browser/modelComponents/componentBase';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IComponentDescriptor, IComponent, IModelStore, ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
import { convertSize } from 'sql/base/browser/dom';
import { ILogService } from 'vs/platform/log/common/log';
import { registerThemingParticipant, IColorTheme, IThemeService, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
class DivItem {
constructor(public descriptor: IComponentDescriptor, public config: azdata.DivItemLayout) { }
}
@Component({
template: `
`
})
export default class DivContainer extends ContainerBase implements IComponent, OnDestroy, AfterViewInit {
@Input() descriptor: IComponentDescriptor;
@Input() modelStore: IModelStore;
@ViewChild('divContainer', { read: ElementRef }) divContainer;
private _height: string;
private _width: string;
private _overflowY: string;
private viewInitialized: boolean;
private cancelClick: Function;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(forwardRef(() => Renderer2)) private renderer: Renderer2,
@Inject(ILogService) logService: ILogService,
@Inject(IThemeService) themeService: IThemeService,
) {
super(changeRef, el, logService);
this._overflowY = ''; // default
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
const editorHoverBackground = theme.getColor(colorRegistry.editorHoverBackground).toString();
if (editorHoverBackground) {
collector.addRule(`
.clickable-divContainer:hover {
background-color: ${editorHoverBackground};
}
`);
}
});
}
ngAfterViewInit(): void {
this.viewInitialized = true;
this.updateClickListener();
this.baseInit();
}
override ngOnDestroy(): void {
this.baseDestroy();
}
/// IComponent implementation
public setLayout(layout: azdata.DivLayout): void {
this._height = convertSize(layout.height);
this._width = convertSize(layout.width);
this.layout();
}
public override setProperties(properties: { [key: string]: any; }): void {
super.setProperties(properties);
if (this.overflowY !== this._overflowY) {
this.updateOverflowY();
}
this.updateScroll();
this.updateClickable();
}
private updateOverflowY() {
this._overflowY = this.overflowY;
if (this._overflowY) {
let element = this.divContainer.nativeElement;
element.style.overflowY = this._overflowY;
}
}
private updateScroll() {
let element = this.divContainer.nativeElement;
element.scrollTop = element.scrollTop - this.yOffsetChange;
element.dispatchEvent(new Event('scroll'));
}
private updateClickable(): void {
const element = this.divContainer.nativeElement;
if (this.clickable) {
element.tabIndex = 0;
element.style.cursor = 'pointer';
} else {
element.removeAttribute('tabIndex');
element.style.cursor = 'default';
}
this.updateClickListener();
}
private onClick() {
this.fireEvent({
eventType: ComponentEventType.onDidClick,
args: undefined
});
}
// CSS-bound properties
public override get height(): string {
return this._height;
}
public override get width(): string {
return this._width;
}
// CSS-bound properties
public get overflowY(): string {
return this.getPropertyOrDefault((props) => props.overflowY, '');
}
public set overflowY(newValue: string) {
this.setPropertyFromUI((properties, newValue) => { properties.overflowY = newValue; }, newValue);
}
public get yOffsetChange(): number {
return this.getPropertyOrDefault((props) => props.yOffsetChange, 0);
}
public set yOffsetChange(newValue: number) {
this.setPropertyFromUI((properties, newValue) => { properties.yOffsetChange = newValue; }, newValue);
}
public get clickable(): boolean {
return this.getPropertyOrDefault((props) => props.clickable, false);
}
public onKey(e: KeyboardEvent) {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
this.onClick();
e.stopPropagation();
}
}
public getItemOrder(item: DivItem): number {
return item.config ? item.config.order : 0;
}
public getItemStyles(item: DivItem): azdata.CssStyles {
return item.config && item.config.CSSStyles ? item.config.CSSStyles : {};
}
private updateClickListener(): void {
// We can't hook into the listener until the view is initialized
if (!this.viewInitialized) {
return;
}
if (this.clickable && !this.cancelClick) {
this.cancelClick = this.renderer.listen(this.divContainer.nativeElement, 'click', () => this.onClick());
} else if (!this.clickable && this.cancelClick) {
this.cancelClick();
this.cancelClick = undefined;
}
}
}