@@ -0,0 +1,64 | |||||
|
1 | import { isNull, mixin, argumentNotNull } from "@implab/core-amd/safe"; | |||
|
2 | import { isPlainObject, isNode, isBuildContext } from "./traits"; | |||
|
3 | ||||
|
4 | export abstract class BuildContextBase { | |||
|
5 | _attrs = {}; | |||
|
6 | ||||
|
7 | _children = new Array(); | |||
|
8 | ||||
|
9 | _created: boolean = false; | |||
|
10 | ||||
|
11 | visitNext(v: any) { | |||
|
12 | if (isNull(v)) | |||
|
13 | return; | |||
|
14 | ||||
|
15 | if (isPlainObject(v)) { | |||
|
16 | ||||
|
17 | if (this._created) | |||
|
18 | this._setAttrs(v); | |||
|
19 | else | |||
|
20 | mixin(this._attrs, v); | |||
|
21 | ||||
|
22 | } else { | |||
|
23 | if (this._created) | |||
|
24 | this._addChild(v); | |||
|
25 | else | |||
|
26 | this._children.push(v); | |||
|
27 | } | |||
|
28 | } | |||
|
29 | ||||
|
30 | getChildDom(v: any) { | |||
|
31 | const tv = typeof v; | |||
|
32 | if (tv === "string" || tv === "number" || tv === "boolean" || v instanceof RegExp || v instanceof Date) { | |||
|
33 | return document.createTextNode(v.toString()); | |||
|
34 | } else if (isNode(v)) { | |||
|
35 | return v; | |||
|
36 | } else if (isBuildContext(v)) { | |||
|
37 | return v.getDomElement(); | |||
|
38 | } else { | |||
|
39 | throw new Error("Invalid parameter"); | |||
|
40 | } | |||
|
41 | } | |||
|
42 | ||||
|
43 | abstract _getDomElement(): HTMLElement; | |||
|
44 | ||||
|
45 | ensureCreated() { | |||
|
46 | if (!this._created) { | |||
|
47 | this._create(this._attrs, this._children); | |||
|
48 | this._children = []; | |||
|
49 | this._attrs = {}; | |||
|
50 | this._created = true; | |||
|
51 | } | |||
|
52 | } | |||
|
53 | ||||
|
54 | getDomElement() { | |||
|
55 | this.ensureCreated(); | |||
|
56 | return this._getDomElement(); | |||
|
57 | } | |||
|
58 | ||||
|
59 | abstract _addChild(child: any): void; | |||
|
60 | ||||
|
61 | abstract _setAttrs(attrs: object): void; | |||
|
62 | ||||
|
63 | abstract _create(attrs: object, children: any[]): void; | |||
|
64 | } |
@@ -0,0 +1,51 | |||||
|
1 | import { djbase, djclass } from "../declare"; | |||
|
2 | import _WidgetBase = require("dijit/_WidgetBase"); | |||
|
3 | import _AttachMixin = require("dijit/_AttachMixin"); | |||
|
4 | import { BuildContext, isNode } from "./traits"; | |||
|
5 | import registry = require("dijit/registry"); | |||
|
6 | // import { Handle } from "dojo/interfaces"; | |||
|
7 | type Handle = dojo.Handle; | |||
|
8 | ||||
|
9 | @djclass | |||
|
10 | export abstract class DjxWidgetBase extends djbase(_WidgetBase, _AttachMixin) { | |||
|
11 | ||||
|
12 | buildRendering() { | |||
|
13 | this.domNode = this.render().getDomElement(); | |||
|
14 | super.buildRendering(); | |||
|
15 | } | |||
|
16 | ||||
|
17 | abstract render(): BuildContext; | |||
|
18 | ||||
|
19 | _processTemplateNode<T extends (Element | Node | _WidgetBase)>( | |||
|
20 | baseNode: T, | |||
|
21 | getAttrFunc: (baseNode: T, attr: string) => string, | |||
|
22 | // tslint:disable-next-line: ban-types | |||
|
23 | attachFunc: (node: T, type: string, func?: Function) => Handle | |||
|
24 | ): boolean { | |||
|
25 | if (isNode(baseNode)) { | |||
|
26 | const w = registry.byNode(baseNode); | |||
|
27 | if (w) { | |||
|
28 | // from dijit/_WidgetsInTemplateMixin | |||
|
29 | this._processTemplateNode(w, | |||
|
30 | (n, p) => n.get(p), // callback to get a property of a widget | |||
|
31 | (widget, type, callback) => { | |||
|
32 | if (!callback) | |||
|
33 | throw new Error("The callback must be specified"); | |||
|
34 | ||||
|
35 | // callback to do data-dojo-attach-event to a widget | |||
|
36 | if (type in widget) { | |||
|
37 | // back-compat, remove for 2.0 | |||
|
38 | return widget.connect(widget, type, callback as EventListener); | |||
|
39 | } else { | |||
|
40 | // 1.x may never hit this branch, but it's the default for 2.0 | |||
|
41 | return widget.on(type, callback); | |||
|
42 | } | |||
|
43 | ||||
|
44 | }); | |||
|
45 | // don't process widgets internals | |||
|
46 | return false; | |||
|
47 | } | |||
|
48 | } | |||
|
49 | return super._processTemplateNode(baseNode, getAttrFunc, attachFunc); | |||
|
50 | } | |||
|
51 | } |
@@ -0,0 +1,45 | |||||
|
1 | import dom = require("dojo/dom-construct"); | |||
|
2 | import attr = require("dojo/dom-attr"); | |||
|
3 | import { argumentNotEmptyString } from "@implab/core-amd/safe"; | |||
|
4 | import { BuildContextBase } from "./BuildContextBase"; | |||
|
5 | ||||
|
6 | export class HtmlElementContext extends BuildContextBase { | |||
|
7 | elementType: string; | |||
|
8 | ||||
|
9 | _element: HTMLElement | undefined; | |||
|
10 | ||||
|
11 | constructor(elementType: string) { | |||
|
12 | argumentNotEmptyString(elementType, "elementType"); | |||
|
13 | super(); | |||
|
14 | ||||
|
15 | this.elementType = elementType; | |||
|
16 | } | |||
|
17 | ||||
|
18 | _addChild(child: any): void { | |||
|
19 | if (!this._element) | |||
|
20 | throw new Error("The HTML element isn't created"); | |||
|
21 | dom.place(this.getChildDom(child), this._element); | |||
|
22 | } | |||
|
23 | ||||
|
24 | _setAttrs(attrs: object): void { | |||
|
25 | if (!this._element) | |||
|
26 | throw new Error("The HTML element isn't created"); | |||
|
27 | ||||
|
28 | attr.set(this._element, attrs); | |||
|
29 | } | |||
|
30 | ||||
|
31 | _create(attrs: object, children: any[]) { | |||
|
32 | this._element = dom.create(this.elementType, attrs); | |||
|
33 | ||||
|
34 | if (children) | |||
|
35 | children.forEach(v => this._addChild(v)); | |||
|
36 | } | |||
|
37 | ||||
|
38 | _getDomElement() { | |||
|
39 | if (!this._element) | |||
|
40 | throw new Error("The HTML element isn't created"); | |||
|
41 | ||||
|
42 | return this._element; | |||
|
43 | } | |||
|
44 | ||||
|
45 | } |
@@ -0,0 +1,43 | |||||
|
1 | import dom = require("dojo/dom-construct"); | |||
|
2 | import { argumentNotNull } from "@implab/core-amd/safe"; | |||
|
3 | import _WidgetBase = require("dijit/_WidgetBase"); | |||
|
4 | import { BuildContextBase } from "./BuildContextBase"; | |||
|
5 | ||||
|
6 | type _WidgetBaseConstructor = typeof _WidgetBase; | |||
|
7 | ||||
|
8 | export class WidgetContext extends BuildContextBase { | |||
|
9 | widgetClass: _WidgetBaseConstructor; | |||
|
10 | ||||
|
11 | _instance: _WidgetBase | undefined; | |||
|
12 | ||||
|
13 | constructor(widgetClass: _WidgetBaseConstructor) { | |||
|
14 | super(); | |||
|
15 | argumentNotNull(widgetClass, "widgetClass"); | |||
|
16 | ||||
|
17 | this.widgetClass = widgetClass; | |||
|
18 | } | |||
|
19 | ||||
|
20 | _addChild(child: any): void { | |||
|
21 | if (!this._instance || !this._instance.containerNode) | |||
|
22 | throw new Error("Widget doesn't support adding children"); | |||
|
23 | ||||
|
24 | dom.place(this.getChildDom(child), this._instance.containerNode); | |||
|
25 | } | |||
|
26 | ||||
|
27 | _setAttrs(attrs: object): void { | |||
|
28 | this._instance?.set(attrs); | |||
|
29 | } | |||
|
30 | ||||
|
31 | _create(attrs: object, children: any[]) { | |||
|
32 | this._instance = new this.widgetClass(this._attrs); | |||
|
33 | if (children) | |||
|
34 | children.forEach(x => this._addChild(x)); | |||
|
35 | } | |||
|
36 | ||||
|
37 | _getDomElement() { | |||
|
38 | if (!this._instance) | |||
|
39 | throw new Error("The instance of the widget isn't created"); | |||
|
40 | return this._instance.domNode; | |||
|
41 | } | |||
|
42 | ||||
|
43 | } |
@@ -0,0 +1,32 | |||||
|
1 | import _WidgetBase = require("dijit/_WidgetBase"); | |||
|
2 | ||||
|
3 | type _WidgetBaseConstructor = typeof _WidgetBase; | |||
|
4 | ||||
|
5 | ||||
|
6 | export interface BuildContext { | |||
|
7 | getDomElement(): HTMLElement; | |||
|
8 | } | |||
|
9 | ||||
|
10 | export function isNode(el: any): el is HTMLElement { | |||
|
11 | return el && el.nodeName && el.nodeType; | |||
|
12 | } | |||
|
13 | ||||
|
14 | export function isWidget(v: any): v is _WidgetBase { | |||
|
15 | return v && "domNode" in v; | |||
|
16 | } | |||
|
17 | ||||
|
18 | export function isBuildContext(v: any): v is BuildContext { | |||
|
19 | return typeof v === "object" && typeof v.getDomElement === "function"; | |||
|
20 | } | |||
|
21 | ||||
|
22 | export function isPlainObject(v: object) { | |||
|
23 | if (typeof v !== "object") | |||
|
24 | return false; | |||
|
25 | ||||
|
26 | const vp = Object.getPrototypeOf(v); | |||
|
27 | return !vp || vp === Object.prototype; | |||
|
28 | } | |||
|
29 | ||||
|
30 | export function isWidgetConstructor(v: any): v is _WidgetBaseConstructor { | |||
|
31 | return typeof v === "function" && v.prototype && "domNode" in v.prototype; | |||
|
32 | } |
@@ -0,0 +1,4 | |||||
|
1 | declare module "@implab/djx/css!*" { | |||
|
2 | declare const result: { url: string }; | |||
|
3 | export = result; | |||
|
4 | } |
@@ -1,5 +1,5 | |||||
1 | plugins { |
|
1 | plugins { | |
2 |
id "org.implab.gradle-typescript" version "1.3. |
|
2 | id "org.implab.gradle-typescript" version "1.3.2" | |
3 | id "ivy-publish" |
|
3 | id "ivy-publish" | |
4 | } |
|
4 | } | |
5 |
|
5 | |||
@@ -43,11 +43,11 npmPackMeta { | |||||
43 | } |
|
43 | } | |
44 |
|
44 | |||
45 | task npmPackTypings(type: Copy) { |
|
45 | task npmPackTypings(type: Copy) { | |
46 | dependsOn sources.main.output |
|
46 | dependsOn typings | |
47 |
|
47 | |||
48 | npmPackContents.dependsOn it |
|
48 | npmPackContents.dependsOn it | |
49 |
|
49 | |||
50 |
from |
|
50 | from typescript.typingsDir | |
51 | into npm.packageDir |
|
51 | into npm.packageDir | |
52 | } |
|
52 | } | |
53 |
|
53 |
@@ -1,4 +1,4 | |||||
1 | import inject = require("./inject"); |
|
1 | import inject = require("./dom-inject"); | |
2 | import { id as mid} from "module"; |
|
2 | import { id as mid} from "module"; | |
3 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; |
|
3 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; | |
4 | const log = TraceSource.get(mid); |
|
4 | const log = TraceSource.get(mid); |
@@ -1,7 +1,7 | |||||
1 | import { Constructor } from "@implab/core-amd/interfaces"; |
|
1 | import { Constructor } from "@implab/core-amd/interfaces"; | |
2 |
import { HtmlElementContext } from "./ |
|
2 | import { HtmlElementContext } from "./tsx/HtmlElementContext"; | |
3 |
import { WidgetContext } from "./ |
|
3 | import { WidgetContext } from "./tsx/WidgetContext"; | |
4 |
import { isWidgetConstructor, BuildContext } from "./ |
|
4 | import { isWidgetConstructor, BuildContext } from "./tsx/traits"; | |
5 |
|
5 | |||
6 | export function createElement<T extends Constructor>(elementType: string | T, ...args: any[]): BuildContext { |
|
6 | export function createElement<T extends Constructor>(elementType: string | T, ...args: any[]): BuildContext { | |
7 | if (typeof elementType === "string") { |
|
7 | if (typeof elementType === "string") { |
@@ -1,6 +1,8 | |||||
1 | import { test } from "./TestTraits"; |
|
1 | import { test } from "./TestTraits"; | |
2 | import { delay } from "@implab/core-amd/safe"; |
|
2 | import { delay } from "@implab/core-amd/safe"; | |
3 | import { assert } from "chai"; |
|
3 | import { assert } from "chai"; | |
|
4 | import "@implab/djx"; | |||
|
5 | import css = require("@implab/djx/css!my,css"); | |||
4 |
|
6 | |||
5 | test("simple", (ok, fail, log) => { |
|
7 | test("simple", (ok, fail, log) => { | |
6 | setTimeout(() => { |
|
8 | setTimeout(() => { |
@@ -1,11 +1,18 | |||||
1 | { |
|
1 | { | |
2 | "extends": "../tsconfig", |
|
2 | "extends": "../tsconfig", | |
3 | "compilerOptions": { |
|
3 | "compilerOptions": { | |
|
4 | "baseUrl": ".", | |||
4 | "rootDir": "ts", |
|
5 | "rootDir": "ts", | |
5 | "rootDirs": [ |
|
6 | "rootDirs": [ | |
6 | "ts", |
|
7 | "ts", | |
7 |
" |
|
8 | "typings", | |
|
9 | "../main/ts", | |||
|
10 | "../main/typings" | |||
8 | ], |
|
11 | ], | |
|
12 | "paths": { | |||
|
13 | "@implab/djx" : ["../main/ts", "../main/typings"] | |||
|
14 | //"@implab/djx/*" : ["../main/ts/*", "../main/typings/*" ] | |||
|
15 | }, | |||
9 | "types": ["requirejs"] |
|
16 | "types": ["requirejs"] | |
10 | } |
|
17 | } | |
11 | } No newline at end of file |
|
18 | } |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now