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