##// END OF EJS Templates
Added DjxFragment...
cin -
r19:8f4d5e2c719a v1.0.0-rc8 default
parent child
Show More
@@ -0,0 +1,23
1 import { _Widget } from "./WidgetContext";
2 import { MapOf } from "@implab/core-amd/interfaces";
3
4 /** Special widget used to create a document fragment */
5 export class DjxFragment implements _Widget {
6
7 domNode: Node;
8
9 containerNode?: Node;
10
11 constructor() {
12 this.domNode = this.containerNode = document.createDocumentFragment();
13 }
14
15 get(attr: string) {
16 return undefined;
17 }
18 set(attr: string, value: any): void;
19 set(attrs: MapOf<any>): void;
20 set() {
21 /* do nothing */
22 }
23 } No newline at end of file
@@ -1,95 +1,97
1 1 import { id as mid } from "module";
2 2 import { TraceSource } from "@implab/core-amd/log/TraceSource";
3 3 import { MapOf } from "@implab/core-amd/interfaces";
4 4 import { mixin } from "@implab/core-amd/safe";
5 5
6 6 const trace = TraceSource.get(mid);
7 7
8 8
9 9 function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => any): () => void {
10 10 // Add an event listener to a DOM node
11 11 node.addEventListener(eventName, handler, false);
12 12
13 13 return () => node.removeEventListener(eventName, handler, false);
14 14 }
15 15
16 16 interface NodeLoadResult {
17 17 node: HTMLElement;
18 18 }
19 19
20 20 class DomInject {
21 21 injectionPoint = document.head;
22 22 injectBefore = document.head.firstChild;
23 23
24 24 _map: MapOf<Promise<NodeLoadResult>> = {};
25 25
26 26 _inject<T extends keyof HTMLElementTagNameMap>(name: T, attr: Partial<HTMLElementTagNameMap[T]>) {
27 27 const node = document.createElement(name);
28 28
29 29 return new Promise<NodeLoadResult>((ok, fail) => {
30 30
31 31 const cleanup = () => {
32 32 noerr();
33 33 noload();
34 34 };
35 35
36 36 const noload = on(node, "load", () => {
37 37 ok({ node });
38 38 cleanup();
39 39 });
40 40
41 41 const noerr = on(node, "error", e => {
42 42 fail({
43 43 erorr: e,
44 44 node
45 45 });
46 46 cleanup();
47 47 });
48 48
49 49 mixin(node, attr);
50 50
51 51 this.injectionPoint.insertBefore(node, this.injectBefore);
52 52 });
53 53 }
54 54
55 55 async injectScript(url: string) {
56 56 let d = this._map[url];
57 57 if (!d) {
58 58 trace.log("js {0}", url);
59 59 d = this._inject("script", {
60 60 type: "text/javascript",
61 61 charset: "utf-8",
62 62 src: url
63 63 });
64 64 this._map[url] = d;
65 65 }
66 66 try {
67 67 await d;
68 68 trace.log("done {0}", url);
69 69 } catch (e) {
70 70 trace.error("failed {0}: {1}", url, e);
71 throw e;
71 72 }
72 73 }
73 74
74 75 async injectStylesheet(url: string) {
75 76 let d = this._map[url];
76 77 if (!d) {
77 78 trace.log("js {0}", url);
78 79 d = this._inject("link", {
79 80 type: "text/css",
80 81 rel: "stylesheet",
81 82 href: url
82 83 });
83 84 this._map[url] = d;
84 85 }
85 86 try {
86 87 await d;
87 88 trace.log("done {0}", url);
88 89 } catch (e) {
89 90 trace.error("failed {0}: {1}", url, e);
91 throw e;
90 92 }
91 93 }
92 94 };
93 95
94 96 const instance = new DomInject();
95 97 export = instance; No newline at end of file
@@ -1,71 +1,76
1 import { isNull, mixin, argumentNotNull } from "@implab/core-amd/safe";
1 import { isNull, mixin } from "@implab/core-amd/safe";
2 2 import { isPlainObject, isNode, isBuildContext, DojoNodePosition, BuildContext } from "./traits";
3 3
4 4 import dom = require("dojo/dom-construct");
5 5
6 6 export abstract class BuildContextBase implements BuildContext {
7 7 _attrs = {};
8 8
9 9 _children = new Array();
10 10
11 11 _created: boolean = false;
12 12
13 13 visitNext(v: any) {
14 14 if (isNull(v))
15 15 return;
16 16
17 17 if (isPlainObject(v)) {
18 18
19 19 if (this._created)
20 20 this._setAttrs(v);
21 21 else
22 22 mixin(this._attrs, v);
23 23 } else if (v instanceof Array) {
24 24 v.forEach(x => this._addChild(x));
25 25 } else {
26 26 if (this._created)
27 27 this._addChild(v);
28 28 else
29 29 this._children.push(v);
30 30 }
31 31 }
32 32
33 33 getChildDom(v: any) {
34 34 const tv = typeof v;
35 35 if (tv === "string" || tv === "number" || tv === "boolean" || v instanceof RegExp || v instanceof Date) {
36 36 return document.createTextNode(v.toString());
37 37 } else if (isNode(v)) {
38 38 return v;
39 39 } else if (isBuildContext(v)) {
40 return v.getDomElement();
40 return v.getDomNode();
41 41 } else {
42 42 throw new Error("Invalid parameter");
43 43 }
44 44 }
45 45
46 abstract _getDomElement(): HTMLElement;
46 abstract _getDomNode(): Node;
47 47
48 48 ensureCreated() {
49 49 if (!this._created) {
50 50 this._create(this._attrs, this._children);
51 51 this._children = [];
52 52 this._attrs = {};
53 53 this._created = true;
54 54 }
55 55 }
56 56
57 /** @deprecated use getDomNode() */
57 58 getDomElement() {
59 return this.getDomNode();
60 }
61
62 getDomNode() {
58 63 this.ensureCreated();
59 return this._getDomElement();
64 return this._getDomNode();
60 65 }
61 66
62 67 placeAt(refNode: string | Node, position?: DojoNodePosition) {
63 dom.place(this.getDomElement(), refNode, position);
68 dom.place(this.getDomNode(), refNode, position);
64 69 }
65 70
66 71 abstract _addChild(child: any): void;
67 72
68 73 abstract _setAttrs(attrs: object): void;
69 74
70 75 abstract _create(attrs: object, children: any[]): void;
71 76 }
@@ -1,52 +1,52
1 1 import { djbase, djclass } from "../declare";
2 2 import _WidgetBase = require("dijit/_WidgetBase");
3 3 import _AttachMixin = require("dijit/_AttachMixin");
4 4 import { BuildContext, isNode } from "./traits";
5 5 import registry = require("dijit/registry");
6 6 import { Handle } from "dojo/interfaces";
7 7
8 8 // type Handle = dojo.Handle;
9 9
10 10 @djclass
11 11 export abstract class DjxWidgetBase extends djbase(_WidgetBase, _AttachMixin) {
12 12
13 13 buildRendering() {
14 this.domNode = this.render().getDomElement();
14 this.domNode = this.render().getDomNode();
15 15 super.buildRendering();
16 16 }
17 17
18 18 abstract render(): BuildContext;
19 19
20 20 _processTemplateNode<T extends (Element | Node | _WidgetBase)>(
21 21 baseNode: T,
22 22 getAttrFunc: (baseNode: T, attr: string) => string,
23 23 // tslint:disable-next-line: ban-types
24 24 attachFunc: (node: T, type: string, func?: Function) => Handle
25 25 ): boolean {
26 26 if (isNode(baseNode)) {
27 27 const w = registry.byNode(baseNode);
28 28 if (w) {
29 29 // from dijit/_WidgetsInTemplateMixin
30 30 this._processTemplateNode(w,
31 31 (n, p) => n.get(p), // callback to get a property of a widget
32 32 (widget, type, callback) => {
33 33 if (!callback)
34 34 throw new Error("The callback must be specified");
35 35
36 36 // callback to do data-dojo-attach-event to a widget
37 37 if (type in widget) {
38 38 // back-compat, remove for 2.0
39 39 return widget.connect(widget, type, callback as EventListener);
40 40 } else {
41 41 // 1.x may never hit this branch, but it's the default for 2.0
42 42 return widget.on(type, callback);
43 43 }
44 44
45 45 });
46 46 // don't process widgets internals
47 47 return false;
48 48 }
49 49 }
50 50 return super._processTemplateNode(baseNode, getAttrFunc, attachFunc);
51 51 }
52 52 }
@@ -1,45 +1,45
1 1 import dom = require("dojo/dom-construct");
2 2 import attr = require("dojo/dom-attr");
3 3 import { argumentNotEmptyString } from "@implab/core-amd/safe";
4 4 import { BuildContextBase } from "./BuildContextBase";
5 5
6 6 export class HtmlElementContext extends BuildContextBase {
7 7 elementType: string;
8 8
9 9 _element: HTMLElement | undefined;
10 10
11 11 constructor(elementType: string) {
12 12 argumentNotEmptyString(elementType, "elementType");
13 13 super();
14 14
15 15 this.elementType = elementType;
16 16 }
17 17
18 18 _addChild(child: any): void {
19 19 if (!this._element)
20 20 throw new Error("The HTML element isn't created");
21 21 dom.place(this.getChildDom(child), this._element);
22 22 }
23 23
24 24 _setAttrs(attrs: object): void {
25 25 if (!this._element)
26 26 throw new Error("The HTML element isn't created");
27 27
28 28 attr.set(this._element, attrs);
29 29 }
30 30
31 31 _create(attrs: object, children: any[]) {
32 32 this._element = dom.create(this.elementType, attrs);
33 33
34 34 if (children)
35 35 children.forEach(v => this._addChild(v));
36 36 }
37 37
38 _getDomElement() {
38 _getDomNode() {
39 39 if (!this._element)
40 40 throw new Error("The HTML element isn't created");
41 41
42 42 return this._element;
43 43 }
44 44
45 45 }
@@ -1,43 +1,55
1 1 import dom = require("dojo/dom-construct");
2 2 import { argumentNotNull } from "@implab/core-amd/safe";
3 import _WidgetBase = require("dijit/_WidgetBase");
4 3 import { BuildContextBase } from "./BuildContextBase";
4 import { MapOf } from "@implab/core-amd/interfaces";
5 5
6 type _WidgetBaseConstructor = typeof _WidgetBase;
6 // tslint:disable-next-line: class-name
7 export interface _Widget {
8 domNode: Node;
9
10 get(attr: string): any;
11
12 set(attr: string, value: any): void;
13 set(attrs: MapOf<any>): void;
14
15 containerNode?: Node
16 }
17
18 export type _WidgetCtor = new (attrs: any, srcNode?: string | Node) => _Widget;
7 19
8 20 export class WidgetContext extends BuildContextBase {
9 widgetClass: _WidgetBaseConstructor;
21 widgetClass: _WidgetCtor;
10 22
11 _instance: _WidgetBase | undefined;
23 _instance: _Widget | undefined;
12 24
13 constructor(widgetClass: _WidgetBaseConstructor) {
25 constructor(widgetClass: _WidgetCtor) {
14 26 super();
15 27 argumentNotNull(widgetClass, "widgetClass");
16 28
17 29 this.widgetClass = widgetClass;
18 30 }
19 31
20 32 _addChild(child: any): void {
21 33 if (!this._instance || !this._instance.containerNode)
22 34 throw new Error("Widget doesn't support adding children");
23 35
24 36 dom.place(this.getChildDom(child), this._instance.containerNode);
25 37 }
26 38
27 39 _setAttrs(attrs: object): void {
28 40 this._instance?.set(attrs);
29 41 }
30 42
31 43 _create(attrs: object, children: any[]) {
32 44 this._instance = new this.widgetClass(this._attrs);
33 45 if (children)
34 46 children.forEach(x => this._addChild(x));
35 47 }
36 48
37 _getDomElement() {
49 _getDomNode() {
38 50 if (!this._instance)
39 51 throw new Error("The instance of the widget isn't created");
40 52 return this._instance.domNode;
41 53 }
42 54
43 55 }
@@ -1,35 +1,63
1 1 import _WidgetBase = require("dijit/_WidgetBase");
2 2
3 3 type _WidgetBaseConstructor = typeof _WidgetBase;
4 4
5 5 export type DojoNodePosition = "first" | "after" | "before" | "last" | "replace" | "only" | number;
6 6
7 7 export interface BuildContext {
8 getDomElement(): HTMLElement;
8 getDomNode(): Node;
9 9
10 10 placeAt(refNode: string | Node, position?: DojoNodePosition): void;
11 11 }
12 12
13 export function isNode(el: any): el is HTMLElement {
13 export function isNode(el: any): el is Node {
14 14 return el && el.nodeName && el.nodeType;
15 15 }
16 16
17 export function isElementNode(el: any): el is Element {
18 return isNode(el) && el.nodeType === 1;
19 }
20
21 export function isTextNode(el: any): el is Text {
22 return isNode(el) && el.nodeType === 3;
23 }
24
25 export function isProcessingInstructionNode(el: any): el is ProcessingInstruction {
26 return isNode(el) && el.nodeType === 7;
27 }
28
29 export function isCommentNode(el: any): el is Comment {
30 return isNode(el) && el.nodeType === 8;
31 }
32
33 export function isDocumentNode(el: any): el is Document {
34 return isNode(el) && el.nodeType === 9;
35 }
36
37 export function isDocumentTypeNode(el: any): el is DocumentType {
38 return isNode(el) && el.nodeType === 10;
39 }
40
41 export function isDocumentFragmentNode(el: any): el is DocumentFragment {
42 return isNode(el) && el.nodeType === 11;
43 }
44
17 45 export function isWidget(v: any): v is _WidgetBase {
18 46 return v && "domNode" in v;
19 47 }
20 48
21 49 export function isBuildContext(v: any): v is BuildContext {
22 50 return typeof v === "object" && typeof v.getDomElement === "function";
23 51 }
24 52
25 53 export function isPlainObject(v: object) {
26 54 if (typeof v !== "object")
27 55 return false;
28 56
29 57 const vp = Object.getPrototypeOf(v);
30 58 return !vp || vp === Object.prototype;
31 59 }
32 60
33 61 export function isWidgetConstructor(v: any): v is _WidgetBaseConstructor {
34 62 return typeof v === "function" && v.prototype && "domNode" in v.prototype;
35 63 }
General Comments 0
You need to be logged in to leave comments. Login now