##// END OF EJS Templates
Corrected Scope.own() to cleanup the supplied object immediately when the scope is disposed already
Corrected Scope.own() to cleanup the supplied object immediately when the scope is disposed already

File last commit:

r109:4a375b9c654a default
r131:c7d9ad82b374 v1.8.1 default
Show More
WidgetRendition.ts
130 lines | 4.8 KiB | video/mp2t | TypeScriptLexer
/ djx / src / main / ts / tsx / WidgetRendition.ts
import { argumentNotNull } from "@implab/core-amd/safe";
import { RenditionBase } from "./RenditionBase";
import { DojoNodePosition, isElementNode, isInPage, isWidget, placeAt } from "./traits";
import registry = require("dijit/registry");
import ContentPane = require("dijit/layout/ContentPane");
import { getItemDom, refHook } from "./render";
// tslint:disable-next-line: class-name
export interface _Widget {
domNode: Node;
containerNode?: Node;
placeAt?(refNode: string | Node, position?: DojoNodePosition): void;
startup?(): void;
addChild?(widget: unknown, index?: number): void;
}
export type _WidgetCtor = new (attrs: object, srcNode?: string | Node) => _Widget;
export class WidgetRendition extends RenditionBase<Node> {
readonly widgetClass: _WidgetCtor;
_instance: _Widget | undefined;
constructor(widgetClass: _WidgetCtor) {
super();
argumentNotNull(widgetClass, "widgetClass");
this.widgetClass = widgetClass;
}
_addChild(child: unknown): void {
const instance = this._getInstance();
if (instance.addChild) {
if (child instanceof WidgetRendition) {
// layout containers add custom logic to addChild methods
instance.addChild(child.getWidgetInstance());
} else if (isWidget(child)) {
instance.addChild(child);
} else {
const childDom = getItemDom(child);
const w = isElementNode(childDom) ? registry.byNode(childDom) : undefined;
if (w) {
instance.addChild(w);
} else {
if (!instance.containerNode)
throw new Error("Failed to add DOM content. The widget doesn't have a containerNode");
// the current widget isn't started, it's children shouldn't start too
placeAt(getItemDom(child), instance.containerNode, "last");
}
}
} else {
if (!instance.containerNode)
throw new Error("The widget doesn't have neither addChild nor containerNode");
// the current widget isn't started, it's children shouldn't start too
placeAt(getItemDom(child), instance.containerNode, "last");
}
}
protected _create({ref, ...attrs}: {ref?: JSX.Ref<_Widget>}, children: unknown[]) {
if (this.widgetClass.prototype instanceof ContentPane) {
// a special case for the ContentPane this is for
// compatibility with that heavy widget, all
// regular containers could be easily manipulated
// through `containerNode` property or `addChild` method.
// render children to the DocumentFragment
const content = document.createDocumentFragment();
children.forEach(child => content.appendChild(getItemDom(child)));
// set the content property to the parameters of the widget
const _attrs = { ...attrs, content };
this._instance = new this.widgetClass(_attrs);
} else {
this._instance = new this.widgetClass(attrs);
children.forEach(x => this._addChild(x));
}
if (ref)
refHook(this._instance, ref);
}
private _getInstance() {
if (!this._instance)
throw new Error("The instance of the widget isn't created");
return this._instance;
}
protected _getDomNode() {
if (!this._instance)
throw new Error("The instance of the widget isn't created");
return this._instance.domNode;
}
/** Overrides default placeAt implementation. Calls placeAt of the
* widget and then starts it.
*
* @param refNode A node or id of the node where the widget should be placed.
* @param position A position relative to refNode.
*/
placeAt(refNode: string | Node, position?: DojoNodePosition) {
this.ensureCreated();
const instance = this._getInstance();
if (typeof instance.placeAt === "function") {
instance.placeAt(refNode, position);
// fix the dojo startup behavior when the widget is placed
// directly to the document and doesn't have any enclosing widgets
const parentWidget = instance.domNode.parentNode ?
registry.getEnclosingWidget(instance.domNode.parentNode) : null;
if (!parentWidget && isInPage(instance.domNode) && typeof instance.startup === "function")
instance.startup();
} else {
// the widget doesn't have a placeAt method, strange but whatever
super.placeAt(refNode, position);
}
}
getWidgetInstance() {
this.ensureCreated();
return this._getInstance();
}
}