##// END OF EJS Templates
Merge
cin -
r62:141ef477a5ff merge default
parent child
Show More
@@ -1,89 +1,93
1 1 import { isNull, mixin } from "@implab/core-amd/safe";
2 import { isPlainObject, isNode, isBuildContext, DojoNodePosition, BuildContext, isInPage } from "./traits";
2 import { isPlainObject, isNode, isBuildContext, DojoNodePosition, BuildContext, isInPage, isWidget } from "./traits";
3 3
4 4 import dom = require("dojo/dom-construct");
5 5 import registry = require("dijit/registry");
6 6
7 7
8 8 export abstract class BuildContextBase<TNode extends Node> implements BuildContext<TNode> {
9 9 private _attrs = {};
10 10
11 11 private _children = new Array();
12 12
13 13 private _created: boolean = false;
14 14
15 15 visitNext(v: any) {
16 16 if (this._created)
17 17 throw new Error("The Element is already created");
18 18
19 19 if (isNull(v) || typeof v === "boolean")
20 20 // skip null, undefined, booleans ( this will work: {value && <span>{value}</span>} )
21 21 return;
22 22
23 23 if (isPlainObject(v)) {
24 24 mixin(this._attrs, v);
25 25 } else if (v instanceof Array) {
26 26 v.forEach(x => this.visitNext(x));
27 27 } else {
28 28 this._children.push(v);
29 29 }
30 30 }
31 31
32 getChildDom(v: any) {
32 protected getItemDom(v: any) {
33 33 const tv = typeof v;
34 34 if (tv === "string" || tv === "number" || v instanceof RegExp || v instanceof Date) {
35 35 return document.createTextNode(v.toString());
36 36 } else if (isNode(v)) {
37 37 return v;
38 38 } else if (isBuildContext(v)) {
39 39 return v.getDomNode();
40 } else if(isWidget(v)) {
41 return v.domNode;
42 } else if(tv === "boolean" || v === null || v === undefined) {
43 return document.createComment(`[${tv} ${String(v)}]`);
40 44 } else {
41 45 throw new Error("Invalid parameter");
42 46 }
43 47 }
44 48
45 49 ensureCreated() {
46 50 if (!this._created) {
47 51 this._create(this._attrs, this._children);
48 52 this._children = [];
49 53 this._attrs = {};
50 54 this._created = true;
51 55 }
52 56 }
53 57
54 58 /** @deprecated will be removed in 1.0.0, use getDomNode() */
55 59 getDomElement() {
56 60 return this.getDomNode();
57 61 }
58 62
59 63 /** Creates DOM node if not created. No additional actions are taken. */
60 64 getDomNode() {
61 65 this.ensureCreated();
62 66 return this._getDomNode();
63 67 }
64 68
65 69 /** Creates DOM node if not created, places it to the specified position
66 70 * and calls startup() method for all widgets contained by this node.
67 71 *
68 72 * @param {string | Node} refNode The reference node where the created
69 73 * DOM should be placed.
70 74 * @param {DojoNodePosition} position Optional parameter, specifies the
71 75 * position relative to refNode. Default is "last" (i.e. last child).
72 76 */
73 77 placeAt(refNode: string | Node, position?: DojoNodePosition) {
74 78 const domNode = this.getDomNode();
75 79 dom.place(domNode, refNode, position);
76 80 const parentWidget = domNode.parentNode ? registry.getEnclosingWidget(domNode.parentNode) : null;
77 81
78 82 if ((parentWidget && parentWidget._started) || isInPage(domNode))
79 83 this._startup();
80 84 }
81 85
82 86 _startup () {
83 87 registry.findWidgets(this._getDomNode()).forEach(w => w.startup());
84 88 }
85 89
86 90 abstract _create(attrs: object, children: any[]): void;
87 91
88 92 abstract _getDomNode(): TNode;
89 93 }
@@ -1,18 +1,6
1 import { _Widget } from "./WidgetContext";
2 import { MapOf } from "@implab/core-amd/interfaces";
3 import { prototype } from "../declare";
4
5 /** Special widget used to create a document fragment */
6 export class DjxFragment implements _Widget {
7
8 domNode: Node;
9
10 containerNode: Node;
11
12 constructor() {
13 this.domNode = this.containerNode = document.createDocumentFragment();
14 }
15 buildRendering() {
16 // this function marks this class as _Widget
17 }
1 /** Special functional component used to create a document fragment */
2 export function DjxFragment({children}: {children: Node[]}){
3 const fragment = document.createDocumentFragment();
4 if (children)
5 children.forEach(child => fragment.appendChild(child));
18 6 } No newline at end of file
@@ -1,33 +1,33
1 1 import dom = require("dojo/dom-construct");
2 2 import attr = require("dojo/dom-attr");
3 3 import { argumentNotNull } from "@implab/core-amd/safe";
4 4 import { BuildContextBase } from "./BuildContextBase";
5 5 import registry = require("dijit/registry");
6 6
7 7
8 8 export class FunctionComponentContext extends BuildContextBase<Node> {
9 9 private _component: (props: any) => any;
10 10
11 11 private _node: Node | undefined;
12 12
13 13 constructor(component: (props: any) => any) {
14 14 super();
15 15 argumentNotNull(component, "component");
16 16
17 17 this._component = component;
18 18 }
19 19
20 20 _create(attrs: object, children: any[]) {
21 21 const _attrs: any = attrs || {};
22 _attrs.children = children.map(x => this.getChildDom(x));
22 _attrs.children = children.map(x => this.getItemDom(x));
23 23
24 this._node = this.getChildDom(this._component.call(null, _attrs));
24 this._node = this.getItemDom(this._component.call(null, _attrs));
25 25 }
26 26
27 27 _getDomNode() {
28 28 if (!this._node)
29 29 throw new Error("The instance of the widget isn't created");
30 30 return this._node;
31 31 }
32 32
33 33 }
@@ -1,37 +1,37
1 1 import dom = require("dojo/dom-construct");
2 2 import { argumentNotEmptyString } from "@implab/core-amd/safe";
3 3 import { BuildContextBase } from "./BuildContextBase";
4 4
5 5 export class HtmlElementContext extends BuildContextBase<HTMLElement> {
6 6 elementType: string;
7 7
8 8 _element: HTMLElement | undefined;
9 9
10 10 constructor(elementType: string) {
11 11 argumentNotEmptyString(elementType, "elementType");
12 12 super();
13 13
14 14 this.elementType = elementType;
15 15 }
16 16
17 17 _addChild(child: any): void {
18 18 if (!this._element)
19 19 throw new Error("The HTML element isn't created");
20 dom.place(this.getChildDom(child), this._element);
20 dom.place(this.getItemDom(child), this._element);
21 21 }
22 22
23 23 _create(attrs: object, children: any[]) {
24 24 this._element = dom.create(this.elementType, attrs);
25 25
26 26 if (children)
27 27 children.forEach(v => this._addChild(v));
28 28 }
29 29
30 30 _getDomNode() {
31 31 if (!this._element)
32 32 throw new Error("The HTML element isn't created");
33 33
34 34 return this._element;
35 35 }
36 36
37 37 }
@@ -1,128 +1,128
1 1 import dom = require("dojo/dom-construct");
2 2 import { argumentNotNull } from "@implab/core-amd/safe";
3 3 import { BuildContextBase } from "./BuildContextBase";
4 4 import { DojoNodePosition, isInPage, isWidget } from "./traits";
5 5 import registry = require("dijit/registry");
6 6 import ContentPane = require("dijit/layout/ContentPane");
7 7
8 8 // tslint:disable-next-line: class-name
9 9 export interface _Widget {
10 10 domNode: Node;
11 11
12 12 containerNode?: Node;
13 13
14 14 placeAt?(refNode: string | Node, position?: DojoNodePosition): void;
15 15 startup?(): void;
16 16
17 17 addChild?(widget: any, index?: number): void;
18 18 }
19 19
20 20 export type _WidgetCtor = new (attrs: any, srcNode?: string | Node) => _Widget;
21 21
22 22 export class WidgetContext extends BuildContextBase<Node> {
23 23 readonly widgetClass: _WidgetCtor;
24 24
25 25 _instance: _Widget | undefined;
26 26
27 27 constructor(widgetClass: _WidgetCtor) {
28 28 super();
29 29 argumentNotNull(widgetClass, "widgetClass");
30 30
31 31 this.widgetClass = widgetClass;
32 32 }
33 33
34 34 _addChild(child: any): void {
35 35 const instance = this._getInstance();
36 36
37 37 if (instance.addChild) {
38 38 if (child instanceof WidgetContext) {
39 39 // layout containers add custom logic to addChild methods
40 40 instance.addChild(child.getWidgetInstance());
41 41 } else if (isWidget(child)) {
42 42 instance.addChild(child);
43 43 } else {
44 44 if (!instance.containerNode)
45 45 throw new Error("The widget doesn't have neither addChild nor containerNode");
46 46
47 47 // the current widget isn't started, it's children shouldn't start too
48 dom.place(this.getChildDom(child), instance.containerNode);
48 dom.place(this.getItemDom(child), instance.containerNode);
49 49 }
50 50 } else {
51 51 if (!instance.containerNode)
52 52 throw new Error("The widget doesn't have neither addChild nor containerNode");
53 53
54 54 // the current widget isn't started, it's children shouldn't start too
55 dom.place(this.getChildDom(child), instance.containerNode);
55 dom.place(this.getItemDom(child), instance.containerNode);
56 56 }
57 57 }
58 58
59 59 _create(attrs: any, children: any[]) {
60 60 if (this.widgetClass.prototype instanceof ContentPane) {
61 61 // a special case for the ContentPane this is for
62 62 // the compatibility with this heavy widget, all
63 63 // regular containers could be easily manipulated
64 64 // through `containerNode` property or `addChild` method.
65 65
66 66 // render children to the DocumentFragment
67 67 const content = document.createDocumentFragment();
68 children.forEach(child => content.appendChild(this.getChildDom(child)));
68 children.forEach(child => content.appendChild(this.getItemDom(child)));
69 69
70 70 // set the content property to the parameters of the widget
71 71 const _attrs = { ...attrs, content };
72 72 this._instance = new this.widgetClass(_attrs);
73 73 } else {
74 74 this._instance = new this.widgetClass(attrs);
75 75 children.forEach(x => this._addChild(x));
76 76 }
77 77
78 78 }
79 79
80 80 private _getInstance() {
81 81 if (!this._instance)
82 82 throw new Error("The instance of the widget isn't created");
83 83 return this._instance;
84 84 }
85 85
86 86 _getDomNode() {
87 87 if (!this._instance)
88 88 throw new Error("The instance of the widget isn't created");
89 89 return this._instance.domNode;
90 90 }
91 91
92 92 /** Overrides default placeAt implementation. Calls placeAt of the
93 93 * widget and then starts it.
94 94 *
95 95 * @param refNode A node or id of the node where the widget should be placed.
96 96 * @param position A position relative to refNode.
97 97 */
98 98 placeAt(refNode: string | Node, position?: DojoNodePosition) {
99 99 this.ensureCreated();
100 100 const instance = this._getInstance();
101 101 if (typeof instance.placeAt === "function") {
102 102 instance.placeAt(refNode, position);
103 103
104 104 // fix the dojo startup behavior when the widget is placed
105 105 // directly to the document and doesn't have any enclosing widgets
106 106 const parentWidget = instance.domNode.parentNode ?
107 107 registry.getEnclosingWidget(instance.domNode.parentNode) : null
108 108 if (!parentWidget && isInPage(instance.domNode))
109 109 this._startup();
110 110 } else {
111 111 // the widget doesn't have a placeAt method, strange but whatever
112 112 super.placeAt(refNode, position);
113 113 }
114 114 }
115 115
116 116 _startup() {
117 117 const instance = this._getInstance();
118 118
119 119 if (typeof instance.startup === "function")
120 120 instance.startup();
121 121 }
122 122
123 123 getWidgetInstance() {
124 124 this.ensureCreated();
125 125 return this._getInstance();
126 126 }
127 127
128 128 }
General Comments 0
You need to be logged in to leave comments. Login now