DjxWidgetBase.ts
142 lines
| 5.2 KiB
| video/mp2t
|
TypeScriptLexer
cin
|
r83 | import { djbase, djclass } from "../declare"; | ||
cin
|
r65 | import _WidgetBase = require("dijit/_WidgetBase"); | ||
import _AttachMixin = require("dijit/_AttachMixin"); | ||||
cin
|
r112 | import { isNode, isElementNode } from "./traits"; | ||
cin
|
r65 | import registry = require("dijit/registry"); | ||
cin
|
r85 | import on = require("dojo/on"); | ||
cin
|
r102 | import { Scope } from "./Scope"; | ||
cin
|
r146 | import { queueRenderTask, getPriority, render } from "./render"; | ||
cin
|
r112 | import { isNull } from "@implab/core-amd/safe"; | ||
cin
|
r65 | |||
// type Handle = dojo.Handle; | ||||
export interface EventArgs { | ||||
bubbles?: boolean; | ||||
cancelable?: boolean; | ||||
composed?: boolean; | ||||
} | ||||
cin
|
r109 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export interface DjxWidgetBase<Attrs = object, Events extends { [name in keyof Events]: Event } = object> extends | ||||
cin
|
r71 | _WidgetBase<Events> { | ||
cin
|
r72 | |||
cin
|
r73 | /** This property is declared only for type inference to work, it is never assigned | ||
* and should not be used. | ||||
*/ | ||||
cin
|
r72 | readonly _eventMap: Events & GlobalEventHandlersEventMap; | ||
cin
|
r81 | |||
/** The list of pairs of event and method names. When the widget is created all methods from | ||||
* this list will be connected to corresponding events. | ||||
* | ||||
* This property is maintained in the prototype | ||||
*/ | ||||
_eventHandlers: Array<{ | ||||
eventName: string, | ||||
cin
|
r109 | handlerMethod: string; | ||
cin
|
r81 | }>; | ||
cin
|
r71 | } | ||
cin
|
r65 | |||
cin
|
r71 | type _super = { | ||
startup(): void; | ||||
cin
|
r102 | |||
destroy(preserveDom?: boolean): void; | ||||
cin
|
r79 | }; | ||
cin
|
r65 | |||
@djclass | ||||
cin
|
r109 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export abstract class DjxWidgetBase<Attrs = object, Events = object> extends djbase<_super, _AttachMixin>(_WidgetBase, _AttachMixin) { | ||||
cin
|
r102 | private readonly _scope = new Scope(); | ||
cin
|
r65 | |||
cin
|
r146 | private readonly _priority = getPriority() + 1; | ||
cin
|
r65 | buildRendering() { | ||
cin
|
r102 | const node = render(this.render(), this._scope); | ||
if (!isElementNode(node)) | ||||
throw new Error("The render method must return a single DOM element"); | ||||
this.domNode = node as HTMLElement; | ||||
cin
|
r65 | super.buildRendering(); | ||
// now we should get assigned data-dojo-attach-points | ||||
// place the contents of the original srcNode to the containerNode | ||||
const src = this.srcNodeRef; | ||||
const dest = this.containerNode; | ||||
cin
|
r73 | // the donNode is constructed now we need to connect event handlers | ||
this._connectEventHandlers(); | ||||
cin
|
r65 | if (src && dest) { | ||
while (src.firstChild) | ||||
dest.appendChild(src.firstChild); | ||||
} | ||||
} | ||||
cin
|
r146 | /** Schedules a new deferred rendition within the scope of the widget */ | ||
scheduleRender(task: () => void) { | ||||
return queueRenderTask(task, this._scope, this._priority); | ||||
} | ||||
cin
|
r112 | abstract render(): JSX.Element; | ||
cin
|
r65 | |||
cin
|
r72 | private _connectEventHandlers() { | ||
cin
|
r83 | if (this._eventHandlers) | ||
this._eventHandlers.forEach(({ eventName, handlerMethod }) => { | ||||
const handler = this[handlerMethod as keyof this]; | ||||
if (typeof handler === "function") | ||||
cin
|
r109 | on(this.domNode, eventName, handler.bind(this) as (...args: unknown[]) => unknown); | ||
cin
|
r83 | }); | ||
cin
|
r72 | } | ||
cin
|
r65 | _processTemplateNode<T extends (Element | Node | _WidgetBase)>( | ||
baseNode: T, | ||||
cin
|
r112 | getAttrFunc: (baseNode: T, attr: string) => string | undefined, | ||
cin
|
r65 | // tslint:disable-next-line: ban-types | ||
cin
|
r109 | attachFunc: (node: T, type: string, func?: (...args: unknown[]) => unknown) => dojo.Handle | ||
cin
|
r65 | ): boolean { | ||
if (isNode(baseNode)) { | ||||
const w = registry.byNode(baseNode); | ||||
if (w) { | ||||
// from dijit/_WidgetsInTemplateMixin | ||||
this._processTemplateNode(w, | ||||
cin
|
r112 | (n, p) => { | ||
const v = n.get(p as keyof typeof n); | ||||
return isNull(v) ? undefined : String(v); | ||||
}, // callback to get a property of a widget | ||||
cin
|
r65 | (widget, type, callback) => { | ||
if (!callback) | ||||
throw new Error("The callback must be specified"); | ||||
// callback to do data-dojo-attach-event to a widget | ||||
if (type in widget) { | ||||
// back-compat, remove for 2.0 | ||||
return widget.connect(widget, type, callback as EventListener); | ||||
} else { | ||||
// 1.x may never hit this branch, but it's the default for 2.0 | ||||
cin
|
r109 | return widget.on(type as keyof GlobalEventHandlersEventMap, callback); | ||
cin
|
r65 | } | ||
}); | ||||
// don't process widgets internals | ||||
return false; | ||||
} | ||||
} | ||||
cin
|
r109 | // eslint-disable-next-line @typescript-eslint/ban-types | ||
cin
|
r112 | return super._processTemplateNode(baseNode, getAttrFunc as (baseNode: T, attr: string) => string, attachFunc as (node: T, type: string, func?: Function) => dojo.Handle); | ||
cin
|
r65 | } | ||
/** Starts current widget and all its supporting widgets (placed outside | ||||
* `containerNode`) and child widgets (placed inside `containerNode`) | ||||
*/ | ||||
startup() { | ||||
// startup supporting widgets | ||||
registry.findWidgets(this.domNode, this.containerNode).forEach(w => w.startup()); | ||||
super.startup(); | ||||
} | ||||
cin
|
r102 | |||
destroy(preserveDom?: boolean) { | ||||
this._scope.destroy(); | ||||
super.destroy(preserveDom); | ||||
} | ||||
cin
|
r65 | } | ||