##// END OF EJS Templates
fixed NlsBundle locale package loading...
fixed NlsBundle locale package loading corrected DjxFragment params and return value fixed regression in DjxWidgetBase attach points processing fixed empty RenditionBase startup

File last commit:

r110:1a190b3a757d v1.4.0 default
r112:2ccfaae984e9 v1.4.4 default
Show More
tsx.ts
187 lines | 6.5 KiB | video/mp2t | TypeScriptLexer
import { Constructor } from "@implab/core-amd/interfaces";
import { HtmlRendition } from "./tsx/HtmlRendition";
import { WidgetRendition } from "./tsx/WidgetRendition";
import { isElementNode, isWidget, isWidgetConstructor, Rendition } from "./tsx/traits";
import { FunctionRendition } from "./tsx/FunctionRendition";
import Stateful = require("dojo/Stateful");
import _WidgetBase = require("dijit/_WidgetBase");
import { DjxWidgetBase } from "./tsx/DjxWidgetBase";
import { WatchRendition } from "./tsx/WatchRendition";
import { Observable, observe, OrderUpdate, Subscribable } from "./observable";
import djAttr = require("dojo/dom-attr");
import djClass = require("dojo/dom-class");
import { AnimationAttrs, WatchForRendition } from "./tsx/WatchForRendition";
export function createElement<T extends Constructor | string | ((props: object) => Element)>(elementType: T, ...args: unknown[]): 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: unknown) => Element);
if (args)
args.forEach(x => ctx.visitNext(x));
return ctx;
} else {
throw new Error(`The element type '${String(elementType)}' is unsupported`);
}
}
export interface EventDetails<T = unknown> {
detail: T;
}
export interface EventSelector {
selectorTarget: HTMLElement;
target: HTMLElement;
}
export type DojoMouseEvent<T = unknown> = MouseEvent & EventSelector & EventDetails<T>;
type StatefulProps<T> = T extends Stateful<infer A> ? A :
T extends _WidgetBase ? T : never;
/**
* 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
* @returns Rendition which is created instantly
*/
export function watch<W extends _WidgetBase, K extends keyof W>(
target: W,
prop: K,
render: (model: W[K]) => unknown
): 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
* @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]) => unknown
): Rendition;
export function watch<V>(subj: Subscribable<V>, render: (model: V) => unknown): Rendition;
export function watch(
...args: [Stateful, string, (model: unknown) => unknown] |
[Subscribable<unknown>, (model: unknown) => unknown]
) {
if (args.length === 3) {
const [target, prop, render] = args;
return new WatchRendition(
render,
observe(({next}) => {
const h = target.watch(
prop,
(_prop, oldValue, newValue) => oldValue !== newValue && next(newValue)
);
next(target.get(prop));
return () => h.remove();
})
);
} else {
const [subj, render] = args;
return new WatchRendition(render, subj);
}
}
export const watchFor = <T>(source: T[] | Subscribable<OrderUpdate<T>>, render: (item: T, index: number) => unknown, opts: AnimationAttrs = {}) => {
return new WatchForRendition({
...opts,
subject: source,
component: render
});
};
export const prop: {
<T extends Stateful, K extends string & keyof StatefulProps<T>>(target: T, name: K): Observable<StatefulProps<T>[K]>;
<T extends _WidgetBase, K extends keyof T>(target: T, name: K): Observable<T[K]>;
} = (target: Stateful, name: string) => {
return observe(({next}) => {
const h = target.watch(
name,
(_prop, oldValue, newValue) => oldValue !== newValue && next(newValue)
);
next(target.get(name));
return () => h.remove();
});
};
export const attach = <W extends DjxWidgetBase, K extends keyof W>(target: W, name: K) => (v: W[K]) => target.set(name, v);
export const bind = <K extends string, T>(attr: K, subj: Subscribable<T>) => {
let h = { unsubscribe() { } };
return (el: Element | { set(name: K, value: T): void; } | undefined) => {
if (el) {
if (isElementNode(el)) {
h = subj.subscribe({
next: value => djAttr.set(el, attr, value)
});
} else {
h = subj.subscribe({
next: value => el.set(attr, value)
});
}
} else {
h.unsubscribe();
}
};
};
export const toggleClass = (className: string, subj: Subscribable<boolean>) => {
let h = { unsubscribe() { } };
return (elOrWidget: HTMLElement | _WidgetBase | undefined) => {
const el = isWidget(elOrWidget) ? elOrWidget.domNode : elOrWidget;
if (el) {
h = subj.subscribe({
next: v => djClass.toggle(el, className, v)
});
} else {
h.unsubscribe();
}
};
};
export const all = <T, A extends JSX.Ref<T>[]>(...cbs: A): JSX.Ref<T> => (arg: T | undefined) => cbs.forEach(cb => cb(arg));
/** 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<object, { [p in E]: EV }>,
EV extends Event
>(
target: T,
key: K,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void>
) => {
const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key }));
target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers;
};