tsx.ts
119 lines
| 4.4 KiB
| video/mp2t
|
TypeScriptLexer
cin
|
r89 | import { Constructor, IDestroyable, IRemovable } from "@implab/core-amd/interfaces"; | ||
cin
|
r65 | import { HtmlRendition } from "./tsx/HtmlRendition"; | ||
import { WidgetRendition } from "./tsx/WidgetRendition"; | ||||
cin
|
r89 | import { destroy, isWidgetConstructor, Rendition } from "./tsx/traits"; | ||
cin
|
r65 | import { FunctionRendition } from "./tsx/FunctionRendition"; | ||
cin
|
r89 | import Stateful = require("dojo/Stateful"); | ||
import _WidgetBase = require("dijit/_WidgetBase"); | ||||
import { DjxWidgetBase } from "./tsx/DjxWidgetBase"; | ||||
cin
|
r65 | |||
export function createElement<T extends Constructor | string | ((props: any) => Element)>(elementType: T, ...args: any[]): Rendition { | ||||
if (typeof elementType === "string") { | ||||
const ctx = new HtmlRendition(elementType); | ||||
if (args) | ||||
args.forEach(x => ctx.visitNext(x)); | ||||
return ctx; | ||||
} else if (isWidgetConstructor(elementType)) { | ||||
const ctx = new WidgetRendition(elementType); | ||||
if (args) | ||||
args.forEach(x => ctx.visitNext(x)); | ||||
return ctx; | ||||
} else if (typeof elementType === "function") { | ||||
const ctx = new FunctionRendition(elementType as (props: any) => Element); | ||||
if (args) | ||||
args.forEach(x => ctx.visitNext(x)); | ||||
return ctx; | ||||
} else { | ||||
throw new Error(`The element type '${elementType}' is unsupported`); | ||||
} | ||||
} | ||||
export interface EventDetails<T = any> { | ||||
detail: T; | ||||
} | ||||
export interface EventSelector { | ||||
selectorTarget: HTMLElement; | ||||
target: HTMLElement; | ||||
} | ||||
export type DojoMouseEvent<T = any> = MouseEvent & EventSelector & EventDetails<T>; | ||||
cin
|
r89 | |||
type StatefulProps<T> = T extends Stateful<infer A> ? A : never; | ||||
type CleanFn = (instance: IRemovable | IDestroyable) => void; | ||||
/** | ||||
* Observers the property and calls render callback each change. | ||||
* | ||||
* @param target The target object which property will be observed. | ||||
* @param prop The name of the property. | ||||
* @param render The callback which will be called every time the value is changed | ||||
* @param cleanupOrOwner The object with method `own` or an callback to register lifecycle for the observer. | ||||
* @returns Rendition which is created instantly | ||||
*/ | ||||
export function watch<W extends _WidgetBase, K extends keyof W>( | ||||
target: W, | ||||
prop: K, | ||||
render: (model: W[K]) => any, | ||||
cleanupOrOwner?: { own: CleanFn } | CleanFn | ||||
): Rendition; | ||||
/** | ||||
* Observers the property and calls render callback each change. | ||||
* | ||||
* @param target The target object which property will be observed. | ||||
* @param prop The name of the property. | ||||
* @param render The callback which will be called every time the value is changed | ||||
* @param cleanupOrOwner The object with method `own` or an callback to register lifecycle for the observer. | ||||
* @returns Rendition which is created instantly | ||||
*/ | ||||
export function watch<T extends Stateful, K extends keyof StatefulProps<T>>( | ||||
target: T, | ||||
prop: K, | ||||
render: (model: StatefulProps<T>[K]) => any, | ||||
cleanupOrOwner?: { own: CleanFn } | CleanFn | ||||
): Rendition; | ||||
export function watch<T extends Stateful, K extends keyof StatefulProps<T> & string>( | ||||
target: T, | ||||
prop: K, | ||||
render: (model: StatefulProps<T>[K]) => any, | ||||
cleanupOrOwner: { own: CleanFn } | CleanFn = () => { } | ||||
) { | ||||
let rendition = new FunctionRendition(() => render(target.get(prop))); | ||||
const _own = cleanupOrOwner instanceof Function ? cleanupOrOwner : (x: IRemovable) => cleanupOrOwner.own(x); | ||||
_own(target.watch(prop, (_name, oldValue, newValue) => { | ||||
if (oldValue !== newValue) { | ||||
const newRendition = new FunctionRendition(() => render(newValue)); | ||||
newRendition.placeAt(rendition.getDomNode(), "replace"); | ||||
destroy(rendition.getDomNode()); | ||||
rendition = newRendition; | ||||
} | ||||
})); | ||||
return rendition; | ||||
} | ||||
/** Decorates the method which will be registered as the handle for the specified event. | ||||
* This decorator can be applied to DjxWidgetBase subclass methods. | ||||
* | ||||
* ``` | ||||
* @on("click") | ||||
* _onClick(eventObj: MouseEvent) { | ||||
* // ... | ||||
* } | ||||
* ``` | ||||
*/ | ||||
export const on = <E extends string>(...eventNames: E[]) => | ||||
<K extends string, | ||||
T extends DjxWidgetBase<any, { [p in E]: EV }>, | ||||
EV extends Event | ||||
>( | ||||
target: T, | ||||
key: K, | ||||
_descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void> | ||||
): any => { | ||||
cin
|
r93 | const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key })); | ||
cin
|
r89 | target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers; | ||
}; | ||||