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