Inital platform relayering (#6385)

* moving test files and inital refactoring

* relayer extension host code

* fix imports

* make insights work

* relayer dashboard

* relayer notebooks

* moveing more code around

* formatting

* accept angular as browser

* fix serializer

* add missing files

* remove declarations from extensions

* fix build errors

* more relayering

* change urls to relative to help code relayering

* remove layering to prep for merge

* fix hygiene errors

* fix hygiene errors

* fix tests
This commit is contained in:
Anthony Dresser
2019-07-18 17:29:17 -07:00
committed by GitHub
parent 45c13116de
commit c23738f935
576 changed files with 2090 additions and 2788 deletions

View File

@@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* 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/breadcrumb';
import { Component, Inject, forwardRef, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { Router } from '@angular/router';
import { IBreadcrumbService, MenuItem } from './interfaces';
import { IDisposable } from 'vs/base/common/lifecycle';
import { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
@Component({
selector: 'breadcrumb',
template: `
<span style="display: flex; flex-flow: row; align-items: center; margin: 10px">
<ng-template ngFor let-item let-first="first" let-last="last" [ngForOf]="menuItems">
<span style="padding: 5px; display: flex; align-items: center">
<span *ngIf="item.icon" class="icon" style="display: inline-block; margin-right: 5px" [ngClass]="item.icon"></span>
<span *ngIf="first">{{item.label}}</span>
<span *ngIf="last" style="">{{item.label}}</span>
<a class="router-link" *ngIf="!last && !first" (click)="route(item.routerLink)" >{{item.label}}</a>
</span>
<span *ngIf="!last" class="icon chevron-right"></span>
</ng-template>
</span>
`
})
export class BreadcrumbComponent implements OnInit, OnDestroy {
protected menuItems: MenuItem[] = []; // used by angular template
private disposables: Array<IDisposable> = new Array();
constructor(
@Inject(forwardRef(() => IBreadcrumbService)) private _breadcrumbService: IBreadcrumbService,
@Inject(forwardRef(() => Router)) private _router: Router,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef
) { }
ngOnInit() {
this.disposables.push(subscriptionToDisposable(this._breadcrumbService.breadcrumbItem.subscribe((item) => this.updateCrumb(item))));
}
ngOnDestroy() {
this.disposables.forEach(item => item.dispose());
}
private updateCrumb(items: MenuItem[]) {
this.menuItems = items;
this._changeRef.detectChanges();
}
public route(link: any[]): void {
this._router.navigate(link);
}
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InjectionToken, EventEmitter } from '@angular/core';
import { Subject } from 'rxjs/Subject';
export const IBreadcrumbService = new InjectionToken<IBreadcrumbService>('breadcrumbService');
export interface IBreadcrumbService {
breadcrumbItem: Subject<MenuItem[]>;
setBreadcrumbs(page: any): void;
}
export interface MenuItem {
label?: string;
icon?: string;
command?: (event?: any) => void;
url?: string;
routerLink?: any[];
eventEmitter?: EventEmitter<any>;
items?: MenuItem[];
expanded?: boolean;
disabled?: boolean;
visible?: boolean;
target?: string;
routerLinkActiveOptions?: any;
}

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.vs .chevron-right.icon {
background-image: url("chevron_right.svg");
}
.vs-dark .chevron-right.icon,
.hc-black .chevron-right.icon {
background-image: url("chevron_right_inverse.svg");
}
breadcrumb .icon {
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
padding: 8px;
}
breadcrumb .chevron-right.icon {
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
padding: 8px;
}
breadcrumb .router-link {
cursor: pointer;
}

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#231f20;}</style></defs><title>chevron_right</title><polygon class="cls-1" points="13.59 2.21 13.58 2.22 13.58 2.2 13.59 2.21"/><path d="M10.54,8l-7-7,1-1,8,8-8,8-1-1Z"/></svg>

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>chevron_right_inverse</title><path class="cls-1" d="M10.38,8l-7-7,1-1,8,8-8,8-1-1Z"/></svg>

After

Width:  |  Height:  |  Size: 237 B

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
Component, Inject, forwardRef, ElementRef, OnInit, Input,
Output, OnChanges, SimpleChanges, EventEmitter
} from '@angular/core';
import { Checkbox as vsCheckbox } from 'sql/base/browser/ui/checkbox/checkbox';
@Component({
selector: 'checkbox',
template: ''
})
export class Checkbox implements OnInit, OnChanges {
@Input() label: string;
@Input() enabled = true;
@Input() checked = true;
@Input('aria-label') private ariaLabel: string;
@Output() onChange = new EventEmitter<boolean>();
private _checkbox: vsCheckbox;
constructor(
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
) { }
ngOnInit(): void {
this._checkbox = new vsCheckbox(this._el.nativeElement, {
label: this.label,
ariaLabel: this.ariaLabel || this.label,
checked: this.checked,
enabled: this.enabled
});
this._checkbox.onChange(e => { this.onChange.emit(e); });
}
ngOnChanges(changes: SimpleChanges): void {
if (this._checkbox) {
if (changes['label']) {
this._checkbox.label = changes['label'].currentValue;
}
if (changes['enabled']) {
this._checkbox.enabled = changes['enabled'].currentValue;
}
if (changes['checked']) {
this._checkbox.checked = changes['checked'].currentValue;
}
}
}
}

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
tab-header .action-item .action-label {
opacity: 0;
padding: 8px;
margin-top: 0.3em;
}
tab-header .action-item {
line-height: 1.4em;
}
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;
}

View File

@@ -0,0 +1,248 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
Component, ContentChildren, QueryList, Inject, forwardRef, NgZone,
Input, EventEmitter, Output, ViewChild, ElementRef
} from '@angular/core';
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
import { ScrollableDirective } from 'sql/base/browser/ui/scrollable/scrollable.directive';
import { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import * as types from 'vs/base/common/types';
import { mixin } from 'vs/base/common/objects';
import { Disposable } from 'vs/base/common/lifecycle';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
export interface IPanelOptions {
/**
* Whether or not to show the tabs if there is only one tab present
*/
showTabsWhenOne?: boolean;
layout?: NavigationBarLayout;
showIcon?: boolean;
}
export enum NavigationBarLayout {
horizontal = 0,
vertical = 1
}
const defaultOptions: IPanelOptions = {
showTabsWhenOne: true,
layout: NavigationBarLayout.horizontal,
showIcon: false
};
let idPool = 0;
@Component({
selector: 'panel',
template: `
<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 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>
</div>
</div>
</div>
<div class="title-actions">
<div #panelActionbar class="panel-actions" style="flex: 0 0 auto; align-self: end; margin-top: auto; margin-bottom: auto;" >
</div>
</div>
</div>
<div class="tab-content">
<div class="fullsize" style="position: absolute">
<ng-content></ng-content>
</div>
</div>
</div>
`
})
export class PanelComponent extends Disposable {
@Input() public options: IPanelOptions;
@Input() public actions: Array<Action>;
@ContentChildren(TabComponent) private _tabs: QueryList<TabComponent>;
@ViewChild(ScrollableDirective) private scrollable: ScrollableDirective;
@Output() public onTabChange = new EventEmitter<TabComponent>();
@Output() public onTabClose = new EventEmitter<TabComponent>();
private _activeTab: TabComponent;
private _actionbar: ActionBar;
private _mru: TabComponent[];
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) {
super();
}
ngOnInit(): void {
this.options = mixin(this.options || {}, defaultOptions, false);
this._mru = [];
}
ngAfterContentInit(): void {
if (this._tabs && this._tabs.length > 0) {
this.selectTab(this._tabs.first);
}
this._register(subscriptionToDisposable(this._tabs.changes.subscribe(() => {
if (this._tabs && this._tabs.length > 0) {
this.selectTab(this._tabs.first);
}
})));
}
ngOnChanges(): void {
if (this._actionbarRef && !this._actionbar) {
this._actionbar = new ActionBar(this._actionbarRef.nativeElement);
}
if (this.actions && this._actionbar) {
this._actionbar.clear();
this._actionbar.push(this.actions, { icon: true, label: false });
}
}
ngAfterViewInit(): void {
this._tabs.changes.subscribe(() => {
if (this.scrollable) {
this.scrollable.layout();
}
});
if (this.scrollable) {
this.scrollable.layout();
}
}
ngOnDestroy() {
if (this._actionbar) {
this._actionbar.dispose();
}
if (this.actions && this.actions.length > 0) {
this.actions.forEach((action) => action.dispose());
}
this.dispose();
}
/**
* Select a tab based on index (unrecommended)
* @param index index of tab in the html
*/
selectTab(index: number): void;
/**
* Select a tab based on the identifier that was passed into the tab
* @param identifier specified identifer of the tab
*/
selectTab(identifier: string): void;
/**
* Select a tab directly if you have access to the object
* @param tab tab to navigate to
*/
selectTab(tab: TabComponent): void;
selectTab(input: TabComponent | number | string): void {
if (this._tabs && this._tabs.length > 0) {
let foundTab: TabComponent | undefined;
if (input instanceof TabComponent) {
foundTab = input;
} else if (types.isNumber(input)) {
foundTab = this._tabs.toArray()[input];
} else if (types.isString(input)) {
foundTab = this._tabs.find(i => i.identifier === input);
}
if (foundTab) {
const tab = foundTab;
// since we need to compare identifiers in this next step we are going to go through and make sure all tabs have one
this._tabs.forEach(i => {
if (!i.identifier) {
i.identifier = 'tabIndex_' + idPool++;
}
});
if (this._activeTab && tab === this._activeTab) {
this.onTabChange.emit(tab);
return;
}
this._zone.run(() => {
if (this._activeTab) {
this._activeTab.active = false;
}
this._activeTab = tab;
this.setMostRecentlyUsed(tab);
this._activeTab.active = true;
this.onTabChange.emit(tab);
});
}
}
}
/**
* Get the id of the active tab
*/
public get getActiveTab(): string {
return this._activeTab.identifier;
}
/**
* Select on the next tab
*/
public selectOnNextTab(): void {
let activeIndex = this._tabs.toArray().findIndex(i => i === this._activeTab);
let nextTabIndex = activeIndex + 1;
if (nextTabIndex === this._tabs.length) {
nextTabIndex = 0;
}
this.selectTab(nextTabIndex);
}
private findAndRemoveTabFromMRU(tab: TabComponent): void {
let mruIndex = this._mru.findIndex(i => i === tab);
if (mruIndex !== -1) {
// Remove old index
this._mru.splice(mruIndex, 1);
}
}
private setMostRecentlyUsed(tab: TabComponent): void {
this.findAndRemoveTabFromMRU(tab);
// Set tab to front
this._mru.unshift(tab);
}
/**
* Close a tab
* @param tab tab to close
*/
closeTab(tab: TabComponent) {
this.onTabClose.emit(tab);
// remove the closed tab from mru
this.findAndRemoveTabFromMRU(tab);
// Open the most recent tab
if (this._mru.length > 0) {
this.selectTab(this._mru[0]);
}
}
public layout() {
this._activeTab.layout();
}
}

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TabComponent } from './tab.component';
import { TabHeaderComponent } from './tabHeader.component';
import { PanelComponent } from './panel.component';
import { ScrollableModule } from 'sql/base/browser/ui/scrollable/scrollable.module';
@NgModule({
imports: [CommonModule, ScrollableModule],
exports: [TabComponent, PanelComponent],
declarations: [TabComponent, TabHeaderComponent, PanelComponent]
})
export class PanelModule { }

View File

@@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Component, Input, ContentChild, OnDestroy, TemplateRef, ChangeDetectorRef, forwardRef, Inject } from '@angular/core';
import { Action } from 'vs/base/common/actions';
import { Disposable } from 'vs/base/common/lifecycle';
export abstract class TabChild extends Disposable {
public abstract layout(): void;
}
@Component({
selector: 'tab',
template: `
<div role="tabpanel" [attr.aria-labelledby]="identifier" tabindex="0" class="visibility" [class.hidden]="shouldBeHidden()" *ngIf="shouldBeIfed()" class="fullsize">
<ng-container *ngTemplateOutlet="templateRef"></ng-container>
</div>
`
})
export class TabComponent implements OnDestroy {
private _child: TabChild;
@ContentChild(TemplateRef) templateRef: TemplateRef<any>;
@Input() public title: string;
@Input() public canClose: boolean;
@Input() public actions: Array<Action>;
@Input() public iconClass: string;
public _active = false;
@Input() public identifier: string;
@Input() private visibilityType: 'if' | 'visibility' = 'if';
private rendered = false;
private destroyed: boolean = false;
@ContentChild(TabChild) public set child(tab: TabChild) {
this._child = tab;
if (this.active && this._child) {
this._child.layout();
}
}
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef
) { }
public set active(val: boolean) {
if (!this.destroyed) {
this._active = val;
if (this.active) {
this.rendered = true;
}
this._cd.detectChanges();
if (this.active && this._child) {
this._child.layout();
}
}
}
public get active(): boolean {
return this._active;
}
ngOnDestroy() {
this.destroyed = true;
if (this.actions && this.actions.length > 0) {
this.actions.forEach((action) => action.dispose());
}
}
shouldBeIfed(): boolean {
if (this.active) {
return true;
} else if (this.visibilityType === 'visibility' && this.rendered) {
return true;
} else {
return false;
}
}
shouldBeHidden(): boolean {
if (this.visibilityType === 'visibility' && !this.active) {
return true;
} else {
return false;
}
}
public layout() {
if (this._child) {
this._child.layout();
}
}
}

View File

@@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------------------------
* 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/tabHeader';
import { Component, AfterContentInit, OnDestroy, Input, Output, ElementRef, ViewChild, EventEmitter } from '@angular/core';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import * as DOM from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { TabComponent } from './tab.component';
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>
</span>
<span #actionbar style="flex: 0 0 auto; align-self: end; margin-top: auto; margin-bottom: auto;" ></span>
</div>
`
})
export class TabHeaderComponent extends Disposable implements AfterContentInit, OnDestroy {
@Input() public tab: TabComponent;
@Input() public showIcon: boolean;
@Input() public active: boolean;
@Output() public onSelectTab: EventEmitter<TabComponent> = new EventEmitter<TabComponent>();
@Output() public onCloseTab: 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;
constructor() {
super();
}
ngAfterContentInit(): void {
if (this.tab.canClose || this.tab.actions) {
this._actionbar = new ActionBar(this._actionbarRef.nativeElement);
if (this.tab.actions) {
this._actionbar.push(this.tab.actions, { icon: true, label: false });
}
if (this.tab.canClose) {
let closeAction = this._register(new CloseTabAction(this.closeTab, this));
this._actionbar.push(closeAction, { icon: true, label: false });
}
}
let tabLabelcontainer = this._tabLabelRef.nativeElement as HTMLElement;
if (this.showIcon && this.tab.iconClass) {
tabLabelcontainer.className = 'tabLabel icon';
tabLabelcontainer.classList.add(this.tab.iconClass);
} else {
tabLabelcontainer.className = 'tabLabel';
tabLabelcontainer.textContent = this.tab.title;
}
tabLabelcontainer.title = this.tab.title;
}
ngOnDestroy() {
if (this._actionbar) {
this._actionbar.dispose();
}
this.dispose();
}
selectTab(tab: TabComponent) {
this.onSelectTab.emit(tab);
}
closeTab() {
this.onCloseTab.emit(this.tab);
}
focusOnTabHeader() {
let header = <HTMLElement>this._actionHeaderRef.nativeElement;
header.focus();
}
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)) {
this.onSelectTab.emit(this.tab);
e.stopPropagation();
}
}
}
}

View File

@@ -0,0 +1,86 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Directive, Inject, forwardRef, ElementRef, Input } from '@angular/core';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { getContentHeight, addDisposableListener, EventType, getContentWidth } from 'vs/base/browser/dom';
import { AngularDisposable } from 'sql/base/browser/lifecycle';
@Directive({
selector: '[scrollable]'
})
export class ScrollableDirective extends AngularDisposable {
private scrollableElement: ScrollableElement;
private parent: HTMLElement;
private scrolled: HTMLElement;
@Input() horizontalScroll: ScrollbarVisibility;
@Input() verticalScroll: ScrollbarVisibility;
@Input() useShadow = false;
@Input() scrollYToX = false;
constructor(
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
) {
super();
}
ngOnInit() {
this.scrolled = this._el.nativeElement as HTMLElement;
this.parent = this.scrolled.parentElement!;
const next = this.scrolled.nextSibling;
this.parent.removeChild(this.scrolled);
this.scrolled.style.position = 'relative';
this.scrollableElement = new ScrollableElement(this.scrolled, {
horizontal: this.horizontalScroll,
vertical: this.verticalScroll,
useShadows: this.useShadow,
scrollYToX: this.scrollYToX,
horizontalScrollbarSize: 3
});
this.scrollableElement.onScroll(e => {
if (this.verticalScroll === ScrollbarVisibility.Auto) {
this.scrolled.style.bottom = e.scrollTop + 'px';
} else if (this.horizontalScroll === ScrollbarVisibility.Auto) {
this.scrolled.scrollLeft = e.scrollLeft;
}
});
this.parent.insertBefore(this.scrollableElement.getDomNode(), next);
const initialHeight = getContentHeight(this.scrolled);
const initalWidth = getContentWidth(this.scrolled);
this.resetScrollDimensions();
this._register(addDisposableListener(window, EventType.RESIZE, () => {
this.resetScrollDimensions();
}));
// unforunately because of angular rendering behavior we need to do a double check to make sure nothing changed after this point
setTimeout(() => {
let currentheight = getContentHeight(this.scrolled);
let currentWidth = getContentWidth(this.scrolled);
if (initialHeight !== currentheight || initalWidth !== currentWidth) {
this.resetScrollDimensions();
}
}, 200);
}
private resetScrollDimensions() {
this.scrollableElement.setScrollDimensions({
scrollHeight: this.verticalScroll === ScrollbarVisibility.Auto ? getContentHeight(this.scrolled) : undefined,
height: this.verticalScroll === ScrollbarVisibility.Auto ? getContentHeight(this.parent) : undefined,
scrollWidth: this.horizontalScroll === ScrollbarVisibility.Auto ? this.scrolled.scrollWidth : undefined,
width: this.horizontalScroll === ScrollbarVisibility.Auto ? this.scrolled.offsetWidth : undefined
});
}
public layout() {
this.resetScrollDimensions();
}
}

View File

@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ScrollableDirective } from './scrollable.directive';
@NgModule({
imports: [CommonModule],
exports: [ScrollableDirective],
declarations: [ScrollableDirective]
})
export class ScrollableModule { }