This repository was archived by the owner on Jul 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
Support Injector instances in Registry and add inject decorator #668
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
aed0ec3
Support Injector instances in Registry and add inject decorator
agubler 93df2d1
Support generic typing for injector
agubler f077004
add jsdoc
agubler ab323d4
ensure test is covering the specified scenario
agubler b06081f
remove runtime warns
agubler f201460
rename context to injector
agubler e6272e6
use the private attribute, as per other uses in WidgetBase
agubler dd5fd86
rename context to payload
agubler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,26 @@ | ||
import { WidgetBase } from './WidgetBase'; | ||
import { | ||
Constructor, | ||
DNode, | ||
RegistryLabel, | ||
WidgetBaseInterface, | ||
WidgetProperties | ||
} from './interfaces'; | ||
import { inject, GetProperties } from './decorators/inject'; | ||
import { Constructor, DNode, RegistryLabel } from './interfaces'; | ||
import { w } from './d'; | ||
import { BaseInjector, defaultMappers, Mappers } from './Injector'; | ||
|
||
export type Container<T extends WidgetBaseInterface> = Constructor<WidgetBase<Partial<T['properties']> & WidgetProperties>>; | ||
export type Container<T extends WidgetBase> = Constructor<WidgetBase<Partial<T['properties']>>>; | ||
|
||
export function Container<W extends WidgetBaseInterface>( | ||
export function Container<W extends WidgetBase> ( | ||
component: Constructor<W> | RegistryLabel, | ||
name: RegistryLabel, | ||
mappers: Partial<Mappers> = defaultMappers | ||
{ getProperties }: { getProperties: GetProperties } | ||
): Container<W> { | ||
const { | ||
getProperties = defaultMappers.getProperties, | ||
getChildren = defaultMappers.getChildren | ||
} = mappers; | ||
|
||
return class extends WidgetBase<any> { | ||
@inject({ name, getProperties }) | ||
class WidgetContainer extends WidgetBase<Partial<W['properties']>> { | ||
public __setProperties__(properties: Partial<W['properties']>): void { | ||
super.__setProperties__(properties as any); | ||
this.invalidate(); | ||
} | ||
protected render(): DNode { | ||
const { properties, children } = this; | ||
|
||
return w<BaseInjector<any>>(name, { | ||
scope: this, | ||
render: () => w(component, properties, children), | ||
getProperties, | ||
properties, | ||
getChildren, | ||
children | ||
}); | ||
return w(component, this.properties, this.children); | ||
} | ||
}; | ||
} | ||
return WidgetContainer; | ||
} | ||
|
||
export default Container; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,22 @@ | ||
import { assign } from '@dojo/core/lang'; | ||
import { Evented } from '@dojo/core/Evented'; | ||
import { | ||
diffProperty, | ||
WidgetBase | ||
} from './WidgetBase'; | ||
import { decorate, isHNode, isWNode } from './d'; | ||
import { always } from './diff'; | ||
import { | ||
Constructor, | ||
DNode, | ||
HNode, | ||
WidgetProperties, | ||
WNode | ||
} from './interfaces'; | ||
|
||
export interface GetProperties { | ||
<P extends WidgetProperties>(inject: any, properties: P): any; | ||
} | ||
export class Injector<T = any> extends Evented { | ||
|
||
export interface GetChildren { | ||
(inject: any, children: DNode[]): DNode[]; | ||
} | ||
private _payload: T; | ||
|
||
/** | ||
* The binding mappers for properties and children. | ||
*/ | ||
export interface Mappers { | ||
getProperties: GetProperties; | ||
getChildren: GetChildren; | ||
} | ||
|
||
/** | ||
* Default noop Mappers for the container. | ||
*/ | ||
export const defaultMappers: Mappers = { | ||
getProperties(inject: any, properties: any): any { | ||
return Object.create(null); | ||
}, | ||
getChildren(inject: any, children: DNode[]): DNode[] { | ||
return []; | ||
} | ||
}; | ||
|
||
/** | ||
* Base context class that extends Evented and | ||
* returns the context using `.get()`. | ||
*/ | ||
export class Context<T = any> extends Evented { | ||
|
||
private _context: T; | ||
|
||
constructor(context: T = <T> {}) { | ||
constructor(payload: T) { | ||
super({}); | ||
this._context = context; | ||
this._payload = payload; | ||
} | ||
|
||
public get(): T { | ||
return this._context; | ||
return this._payload; | ||
} | ||
|
||
public set(context: T): void { | ||
this._context = context; | ||
public set(payload: T): void { | ||
this._payload = payload; | ||
this.emit({ type: 'invalidate' }); | ||
} | ||
} | ||
|
||
export interface InjectorProperties extends WidgetProperties { | ||
scope: WidgetBase; | ||
render(): DNode | DNode[]; | ||
getProperties?: GetProperties; | ||
properties: any; | ||
getChildren?: GetChildren; | ||
children: DNode[]; | ||
} | ||
|
||
export interface Base<C = Context> { | ||
toInject(): C; | ||
} | ||
|
||
export class Base<C = Context> extends WidgetBase<InjectorProperties> implements Base<C> { | ||
|
||
protected context: C = <C> {}; | ||
|
||
public toInject(): C { | ||
return this.context; | ||
} | ||
} | ||
|
||
export class BaseInjector<C extends Evented = Context> extends Base<C> { | ||
|
||
constructor(context?: C) { | ||
super(); | ||
if (context) { | ||
this.context = context; | ||
this.context.on('invalidate', this.invalidate.bind(this)); | ||
} | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Mixin that extends the supplied Injector class with the proxy `render` and passing the provided to `context` to the Injector | ||
* class via the constructor. | ||
*/ | ||
export function Injector<C, T extends Constructor<Base<C>>>(Base: T, context: C): T { | ||
|
||
@diffProperty('render', always) | ||
class Injector extends Base { | ||
|
||
constructor(...args: any[]) { | ||
super(context); | ||
} | ||
|
||
protected decorateBind(node: DNode | DNode[]): DNode | DNode[] { | ||
const { scope } = this.properties; | ||
decorate(node, (node: WNode | HNode) => { | ||
if (isHNode(node)) { | ||
(<any> node.properties).bind = scope; | ||
} | ||
else { | ||
node.coreProperties.bind = scope; | ||
} | ||
}, (node: DNode) => { return isHNode(node) || isWNode(node); }); | ||
|
||
return node; | ||
} | ||
|
||
protected render(): DNode | DNode[] { | ||
const { | ||
render, | ||
properties, | ||
getProperties = defaultMappers.getProperties, | ||
children, | ||
getChildren = defaultMappers.getChildren | ||
} = this.properties; | ||
const injectedChildren = getChildren(this.toInject(), children); | ||
|
||
assign(properties, getProperties(this.toInject(), properties)); | ||
if (injectedChildren && injectedChildren.length) { | ||
children.push(...injectedChildren); | ||
} | ||
|
||
return this.decorateBind(render()); | ||
} | ||
|
||
protected runAfterRenders(dNode: DNode | DNode[]): DNode | DNode[] { | ||
return super.runAfterRenders.call(this.properties.scope, dNode); | ||
} | ||
} | ||
return Injector; | ||
} | ||
|
||
export default Injector; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have we thought how we can better support this in the future? this is the equivalent of
shouldComponentUpdate
set totrue
in react?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have thought about it, shall raise an enhancement issue - for now this is the only way I could support it.