##// 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:

r109:4a375b9c654a default
r112:2ccfaae984e9 v1.4.4 default
Show More
render.ts
112 lines | 3.0 KiB | video/mp2t | TypeScriptLexer
import { TraceSource } from "@implab/core-amd/log/TraceSource";
import { isPromise } from "@implab/core-amd/safe";
import { id as mid } from "module";
import { IScope, Scope } from "./Scope";
import { isNode, isRendition, isWidget } from "./traits";
const trace = TraceSource.get(mid);
interface Context {
scope: IScope;
hooks?: (() => void)[];
}
let _context: Context = {
scope: Scope.dummy
};
const guard = (cb: () => unknown) => {
try {
const result = cb();
if (isPromise(result)) {
const warn = (ret: unknown) => trace.error("The callback {0} competed asynchronously. result = {1}", cb, ret);
result.then(warn, warn);
}
} catch (e) {
trace.error(e);
}
};
export const beginRender = (scope: IScope = getScope()) => {
const prev = _context;
_context = {
scope,
hooks: []
};
return endRender(prev);
};
/**
* Completes render operation
*/
const endRender = (prev: Context) => () => {
const { hooks } = _context;
if (hooks)
hooks.forEach(guard);
_context = prev;
};
export const renderHook = (hook: () => void) => {
const { hooks } = _context;
if (hooks)
hooks.push(hook);
else
guard(hook);
};
export const refHook = <T>(value: T, ref: JSX.Ref<T>) => {
const { hooks, scope } = _context;
if (hooks)
hooks.push(() => ref(value));
else
guard(() => ref(value));
scope.own(() => ref(undefined));
};
/** Returns the current scope */
export const getScope = () => _context.scope;
/** Schedules the rendition to be rendered to the DOM Node
* @param rendition The rendition to be rendered
* @param scope The scope
*/
export const render = (rendition: unknown, scope = Scope.dummy) => {
const complete = beginRender(scope);
try {
return getItemDom(rendition);
} finally {
complete();
}
};
/** Renders DOM element for different types of the argument. */
export const getItemDom = (v: unknown) => {
if (typeof v === "string" || typeof v === "number" || v instanceof RegExp || v instanceof Date) {
// primitive types converted to the text nodes
return document.createTextNode(v.toString());
} else if (isNode(v)) {
// nodes are kept as is
return v;
} else if (isRendition(v)) {
// renditions are instantiated
return v.getDomNode();
} else if (isWidget(v)) {
// widgets are converted to it's markup
return v.domNode;
} else if (typeof v === "boolean" || v === null || v === undefined) {
// null | undefined | boolean are removed
return document.createDocumentFragment();
} else if (v instanceof Array) {
// arrays will be translated to document fragments
const fragment = document.createDocumentFragment();
v.map(item => getItemDom(item))
.forEach(node => fragment.appendChild(node));
return fragment;
} else {
// bug: explicit error otherwise
throw new Error(`Invalid parameter: ${String(v)}`);
}
};