lib/common/src/widgets/widgets.commons.ts
Every custom widget component class has to have the static property and the static method of this interface.
Properties |
|
controlType |
controlType:
|
Type : Type<C>
|
label |
label:
|
Type : string
|
Optional |
widgetMatch |
widgetMatch:
|
Type : WidgetMatchFn<C>
|
import {
Type,
InjectionToken,
Directive
} from '@angular/core'
import { assert } from '@rcc/core'
/**
* Represents any kind of WidgetControl.
* This class is meant to be extended and not to be instantiated on its own.
* Every time you want to create a new type of widget, you should define a control class extending this base class.
* A control class defined this way will serve as indicator of your widget type and consists of all the data and methods,
* widgets of your new widget type can make use of.
*
* This class does nothing on its own. {@link /modules/WidgetsModule.html#readme | Howto Widgets}
*/
export class WidgetControl{}
/**
* A method that evaluates how well the parent object suits a given instance of a {@link WidgetControl} extension.
*
* Return values are interpreted like this:
*
* ```
* -1: can't handle this kind of WidgetControl instance
* 0: can handle this kind of WidgetControl instance - if need be
* 1: good at handling this kind of WidgetControl instance
* >= 2: specifically made to handle this kind of WidgetControl instance
* ```
* You should very rarely return a value greater than 2.
*
* {@link WidgetsModule|More on Widgets}
*/
export type WidgetMatchFn<C extends WidgetControl> = (control : C) => number
/**
* Every custom widget component class has to have the static property and the static method of this interface.
*
* {@link /modules/WidgetsModule.html#readme | More on Widgets}
*/
export interface WidgetComponentType<C extends WidgetControl = WidgetControl>{
label? : string
controlType : Type<C>
widgetMatch : WidgetMatchFn<C>
new (widgetControl: C): WidgetComponent<C>
}
/**
* Every custom WidgetComponent has to extend this class.
* {@link /modules/WidgetsModule.html#readme | More on Widgets}
*
* And every extension has to have the following static property and method matching your extension of WidgetControl `MyWidgetControl extends WidgetControl`:
* ```ts
*
* class MyWidgetComponent<MyWidgetControl> extends WidgetComponent<MyWidgetControl>{
*
* static controlType : Type<MyWidgetControl>
* static widgetMatch : WidgetMatchFn<MyWidgetControl>
*
* constructor(myWidgetControl: MyWidgetControl){
* super(myWidgetControl)
* ...
* }
* }
* ```
*
*
*/
@Directive()
export class WidgetComponent<C extends WidgetControl> {
static label : string
static controlType : Type<unknown>
static widgetMatch : WidgetMatchFn<unknown> = () => { throw "WidgetComponent missing static widgetMatch()" }
constructor(widgetControl: C){
const staticSelf = (this.constructor as WidgetComponentType<C>)
const widgetComponentTypeName = staticSelf.name
const expectedControlType = staticSelf.controlType
const actualControlType = widgetControl.constructor
assert(widgetControl, `${widgetComponentTypeName} -> WidgetComponent.constructor missing static idgetControl.`)
assert(expectedControlType, `${widgetComponentTypeName} -> WidgetComponent.constructor missing static controlType`)
assert(expectedControlType == actualControlType, `${widgetComponentTypeName} -> WidgetComponent.constructor controlType mismatch: expected ${expectedControlType.name}, got ${actualControlType.name} instead.`)
assert(staticSelf.widgetMatch(widgetControl) >= 0, `${widgetComponentTypeName} -> WidgetComponent.constructor() control mismatch.`)
}
}
/**
* Token to register WidgetCompoents.{@link WidgetsModule|More on Widgets}. Don't use this on it's own, instead use {@link provideWidgets}
*/
export const WIDGETS = new InjectionToken<Type<WidgetComponent<unknown>>>('WidgetComponents')
/**
* Registers {@link WidgetComponent}s to be used by {@link RccWidgetComponent}.
*
* * ```
* @NgModule({
* providers: [
* provideWidgets(MyTranslator, ...),
* ...
* ],
* ...
* })
* ```
*/
export function provideWidget(widgetComponent: Type<WidgetComponent<unknown>>){
assert(typeof (widgetComponent as any).controlType == 'function', 'provideWidget: provided widgetComponent lacks static property "controlType"')
return {
provide: WIDGETS,
useValue: widgetComponent,
multi: true
}
}