docs/RootLayout.js
import { VNode } from 'snabbdom/vnode';
import h from 'snabbdom/h';
import { Type, Injector, Inject, Optional, forwardRef, ProviderArg } from './di';
import { RootInjector } from './RootInjector';
import { Layout } from './layout';
import { Serialized } from './serialization';
import { ViewManager } from './view';
import { defaults } from './utils';
import { Renderer, Renderable, ConfiguredRenderable, RenderableInjector } from './dom';
import {
ConfigurationRef,
ContainerRef,
RootConfigRef,
RenderableArg,
ElementRef,
ContextType
} from './common';
import { UgPlugin } from './UgPlugin';
import { StateContext } from './StateContext';
import { LockState, LOCK_DRAGGING, LOCK_RESIZING } from './LockState';
export interface RootLayoutConfig {
use: RenderableArg<Layout>;
}
export interface RootLayoutCreationConfig {
container: HTMLElement;
plugins: UgPlugin[];
providers: ProviderArg[];
}
export interface RootLayoutCreationConfigArgs {
container: HTMLElement;
plugins?: UgPlugin[];
providers?: ProviderArg[];
interceptors?: ProviderArg[];
}
export class RootLayout extends Renderable {
protected _height: number = 0;
protected _width: number = 0;
protected _vnode: VNode;
protected _isInitialized: boolean = false;
protected _lastVNode: VNode|null = null;
protected _offsetX: number = 0;
protected _offsetY: number = 0;
constructor(
@Inject(ConfigurationRef) protected _config: RootLayoutConfig,
@Inject(Renderer) protected _renderer: Renderer,
@Inject(ElementRef) protected _containerEl: HTMLElement,
@Inject(ViewManager) protected _viewManager: ViewManager,
@Inject(RootConfigRef) protected _rootConfig: RootLayoutCreationConfig,
@Inject(StateContext) protected _stateContext: StateContext,
@Inject(LockState) protected _lockState: LockState
) {
super();
}
get height(): number {
return this._height;
}
get width(): number {
return this._width;
}
get isInitialized(): boolean {
return this._isInitialized;
}
get containerEl(): Node|null {
return this._containerEl;
}
get offsetX(): number {
return this._offsetX;
}
get offsetY(): number {
return this._offsetY;
}
get lockState(): LockState {
return this._lockState;
}
makeVisible(): void {
this._renderer.render();
}
render(): VNode {
return h('div.ug-layout__root', {
style: {
width: `${this._width}px`,
height: `${this._height}px`
}
}, [
this._contentItems[0].render()
]);
}
resize(dimensions?: { height: number, width: number, x: number, y: number }): void {
if (dimensions) {
this._width = dimensions.width;
this._height = dimensions.height;
this._offsetX = dimensions.x;
this._offsetY = dimensions.y;
} else {
const clientRec = this._containerEl.getBoundingClientRect();
this._width = clientRec.width;
this._height = clientRec.height;
this._offsetX = clientRec.left;
this._offsetY = clientRec.top;
}
this._contentItems[0].resize();
}
update(): void {
this._renderer.render();
}
initialize(): void {
this._lockState.set(LOCK_DRAGGING, false);
this._lockState.set(LOCK_RESIZING, false);
this._renderer.initialize(this._containerEl);
this._renderer.useNodeGenerator(() => this.render());
this._isInitialized = true;
for (const plugin of this._rootConfig.plugins) {
plugin.initialize(this);
}
}
load(config: ConfiguredRenderable<RootLayout>|RootLayoutConfig, options: { context?: string } = {}): void {
const { context = ContextType.LOAD } = options;
this._stateContext.setContext(context);
this._contentItems.forEach(item => item.destroy());
this._config = ConfiguredRenderable.resolveConfiguration(config);
this._contentItems = [ this.createChild(this._config.use) ];
this.resize();
this.update();
}
setContainingNode(node: Node): void {
this._renderer.setContainer(node);
this._containerEl = node as HTMLElement;
}
detach(): void {
this._renderer.detach();
}
destroy(): void {
super.destroy();
this._viewManager.destroy();
this._renderer.destroy();
}
isVisible(): boolean {
return true;
}
getPlugins<T extends UgPlugin>(type?: Type<T>): T[] {
return this._rootConfig.plugins.filter(plugin => {
return type ? plugin instanceof type : true;
}) as T[];
}
static create<T extends RootLayout>(config: RootLayoutCreationConfigArgs): T {
const _config = defaults(config, {
plugins: [],
providers: []
}) as RootLayoutCreationConfig;
const rootInjector = new RootInjector([
{ provide: ElementRef, useValue: config.container },
{ provide: RootConfigRef, useValue: config },
..._config.providers
]);
return RenderableInjector.fromRenderable(
RootLayout,
[
{ provide: RootLayout, useExisting: ConfiguredRenderable }
],
rootInjector
)
.get(ConfiguredRenderable);
}
static configure(config: RootLayoutConfig): ConfiguredRenderable<RootLayout> {
return new ConfiguredRenderable(RootLayout, config);
}
}