##// END OF EJS Templates
`Subscribable` is made compatible with rxjs, added map, filter and scan...
`Subscribable` is made compatible with rxjs, added map, filter and scan methods to observables. `watch` can accept either stateful object and a property name to observe or the subscribable value. added ref attribute to the markup elements and widgets. `bind`, `tooggleClass` and `attach` methods can be passed to `ref` attribute in the markup to interact with elemnts and widgets.

File last commit:

r102:c65ea2350b1a v1.3
r102:c65ea2350b1a v1.3
Show More
traits.ts
213 lines | 6.9 KiB | video/mp2t | TypeScriptLexer
import { IDestroyable } from "@implab/core-amd/interfaces";
import { isDestroyable } from "@implab/core-amd/safe";
import _WidgetBase = require("dijit/_WidgetBase");
import registry = require("dijit/registry");
interface _WidgetBaseConstructor {
new <A = {}, E extends { [k in keyof E]: Event } = {}>(params?: Partial<_WidgetBase<E> & A>, srcNodeRef?: dojo.NodeOrString): _WidgetBase<E> & dojo._base.DeclareCreatedObject;
prototype: _WidgetBase<any>;
}
export type DojoNodePosition = "first" | "after" | "before" | "last" | "replace" | "only" | number;
export type DojoNodeLocation = [Node, DojoNodePosition];
export interface Rendition<TNode extends Node = Node> {
getDomNode(): TNode;
placeAt(refNode: string | Node, position?: DojoNodePosition): void;
}
/**
* @deprecated use Rendition
*/
export type BuildContext<TNode extends Node = Node> = Rendition<TNode>;
export interface IRecursivelyDestroyable {
destroyRecursive(): void;
}
export const isNode = (el: unknown): el is Node => !!(el && (el as Node).nodeName && (el as Node).nodeType);
export const isElementNode = (el: unknown): el is Element => isNode(el) && el.nodeType === 1;
export const isTextNode = (el: unknown): el is Text => isNode(el) && el.nodeType === 3;
export const isProcessingInstructionNode = (el: unknown): el is ProcessingInstruction => isNode(el) && el.nodeType === 7;
export const isCommentNode = (el: unknown): el is Comment => isNode(el) && el.nodeType === 8;
export const isDocumentNode = (el: unknown): el is Document => isNode(el) && el.nodeType === 9;
export const isDocumentTypeNode = (el: unknown): el is DocumentType => isNode(el) && el.nodeType === 10;
export const isDocumentFragmentNode = (el: any): el is DocumentFragment => isNode(el) && el.nodeType === 11;
export const isWidget = (v: unknown): v is _WidgetBase => !!(v && "domNode" in (v as _WidgetBase));
export const isRendition = (v: unknown): v is Rendition => !!(v && typeof (v as Rendition).getDomNode === "function");
/**
* @deprecated use isRendition
*/
export const isBuildContext = isRendition;
export const isPlainObject = (v: object) => {
if (typeof v !== "object")
return false;
const vp = Object.getPrototypeOf(v);
return !vp || vp === Object.prototype;
}
export const isWidgetConstructor = (v: unknown): v is _WidgetBaseConstructor =>
typeof v === "function" && v.prototype && (
"domNode" in v.prototype ||
"buildRendering" in v.prototype
);
/** Tests whether the specified node is placed in visible dom.
* @param {Node} node The node to test
*/
export const isInPage = (node: Node) => node === document.body ? false : document.body.contains(node);
export const isRecursivelyDestroyable = (target: unknown): target is IRecursivelyDestroyable =>
!!(target && typeof (target as IRecursivelyDestroyable).destroyRecursive === "function");
/** Destroys DOM Node with all contained widgets.
* If the specified node is the root node of a widget, then the
* widget will be destroyed.
*
* @param target DOM Node or widget to destroy
*/
export const destroy = (target: Node | IDestroyable | IRecursivelyDestroyable) => {
if (isRecursivelyDestroyable(target)) {
target.destroyRecursive();
} else if (isDestroyable(target)) {
target.destroy();
} else if (isNode(target)) {
if (isElementNode(target)) {
const w = registry.byNode(target);
if (w) {
w.destroyRecursive();
return;
} else {
emptyNode(target);
}
}
const parent = target.parentNode;
if (parent)
parent.removeChild(target);
}
}
/** Empties a content of the specified node and destroys all contained widgets.
*
* @param target DOM node to empty.
*/
export const emptyNode = (target: Node) => {
registry.findWidgets(target).forEach(destroy);
for (let c; c = target.lastChild;) { // intentional assignment
target.removeChild(c);
}
}
/** This function starts all widgets inside the DOM node if the target is a node
* or starts widget itself if the target is the widget. If the specified node
* associated with the widget that widget will be started.
*
* @param target DOM node to find and start widgets or the widget itself.
*/
export const startupWidgets = (target: Node | _WidgetBase, skipNode?: Node) => {
if (isNode(target)) {
if (isElementNode(target)) {
const w = registry.byNode(target);
if (w) {
if (w.startup)
w.startup();
} else {
registry.findWidgets(target, skipNode).forEach(x => x.startup());
}
}
} else {
if (target.startup)
target.startup();
}
}
/** Places the specified DOM node at the specified location.
*
* @param node The node which should be placed
* @param refNodeOrId The reference node where the created
* DOM should be placed.
* @param position Optional parameter, specifies the
* position relative to refNode. Default is "last" (i.e. last child).
*/
export const placeAt = (node: Node, refNodeOrId: string | Node, position: DojoNodePosition = "last") => {
const ref = typeof refNodeOrId == "string" ? document.getElementById(refNodeOrId) : refNodeOrId;
if (!ref)
return;
const parent = ref.parentNode;
if (typeof position == "number") {
if (ref.childNodes.length <= position) {
ref.appendChild(node);
} else {
ref.insertBefore(node, ref.childNodes[position]);
}
} else {
switch (position) {
case "before":
parent && parent.insertBefore(node, ref);
break;
case "after":
parent && parent.insertBefore(node, ref.nextSibling);
break;
case "first":
ref.insertBefore(node, ref.firstChild);
break;
case "last":
ref.appendChild(node);
break;
case "only":
emptyNode(ref);
ref.appendChild(node);
break;
case "replace":
if (parent)
parent.replaceChild(node, ref);
destroy(ref);
break;
}
}
}
/** Collects nodes from collection to an array.
*
* @param collection The collection of nodes.
* @returns The array of nodes.
*/
export const collectNodes = (collection: NodeListOf<ChildNode>) => {
const items = [];
for (let i = 0, n = collection.length; i < n; i++) {
items.push(collection[i]);
}
return items;
};
export const isMounted = (node: Node) => {
if (node.parentNode) {
const parentWidget = registry.getEnclosingWidget(node.parentNode);
if (parentWidget && parentWidget._started)
return true;
}
if (isInPage(node))
return true;
return false;
};