diff --git a/build.gradle b/build.gradle --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id "org.implab.gradle-typescript" version "1.3.1" + id "org.implab.gradle-typescript" version "1.3.2" id "ivy-publish" } @@ -43,11 +43,11 @@ npmPackMeta { } task npmPackTypings(type: Copy) { - dependsOn sources.main.output + dependsOn typings npmPackContents.dependsOn it - from sources.main.output.typingsDir + from typescript.typingsDir into npm.packageDir } diff --git a/src/main/ts/css.ts b/src/main/ts/css.ts --- a/src/main/ts/css.ts +++ b/src/main/ts/css.ts @@ -1,4 +1,4 @@ -import inject = require("./inject"); +import inject = require("./dom-inject"); import { id as mid} from "module"; import { TraceSource } from "@implab/core-amd/log/TraceSource"; const log = TraceSource.get(mid); diff --git a/src/main/ts/djx/BuildContextBase.ts b/src/main/ts/djx/BuildContextBase.ts deleted file mode 100644 --- a/src/main/ts/djx/BuildContextBase.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { isNull, mixin, argumentNotNull } from "@implab/core-amd/safe"; -import { isPlainObject, isNode, isBuildContext } from "./traits"; - -export abstract class BuildContextBase { - _attrs = {}; - - _children = new Array(); - - _created: boolean = false; - - visitNext(v: any) { - if (isNull(v)) - return; - - if (isPlainObject(v)) { - - if (this._created) - this._setAttrs(v); - else - mixin(this._attrs, v); - - } else { - if (this._created) - this._addChild(v); - else - this._children.push(v); - } - } - - getChildDom(v: any) { - const tv = typeof v; - if (tv === "string" || tv === "number" || tv === "boolean" || v instanceof RegExp || v instanceof Date) { - return document.createTextNode(v.toString()); - } else if (isNode(v)) { - return v; - } else if (isBuildContext(v)) { - return v.getDomElement(); - } else { - throw new Error("Invalid parameter"); - } - } - - abstract _getDomElement(): HTMLElement; - - ensureCreated() { - if (!this._created) { - this._create(this._attrs, this._children); - this._children = []; - this._attrs = {}; - this._created = true; - } - } - - getDomElement() { - this.ensureCreated(); - return this._getDomElement(); - } - - abstract _addChild(child: any): void; - - abstract _setAttrs(attrs: object): void; - - abstract _create(attrs: object, children: any[]): void; -} diff --git a/src/main/ts/djx/DjxWidgetBase.ts b/src/main/ts/djx/DjxWidgetBase.ts deleted file mode 100644 --- a/src/main/ts/djx/DjxWidgetBase.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { djbase, djclass } from "../declare"; -import _WidgetBase = require("dijit/_WidgetBase"); -import _AttachMixin = require("dijit/_AttachMixin"); -import { BuildContext, isNode } from "./traits"; -import registry = require("dijit/registry"); -// import { Handle } from "dojo/interfaces"; -type Handle = dojo.Handle; - -@djclass -export abstract class DjxWidgetBase extends djbase(_WidgetBase, _AttachMixin) { - - buildRendering() { - this.domNode = this.render().getDomElement(); - super.buildRendering(); - } - - abstract render(): BuildContext; - - _processTemplateNode( - baseNode: T, - getAttrFunc: (baseNode: T, attr: string) => string, - // tslint:disable-next-line: ban-types - attachFunc: (node: T, type: string, func?: Function) => Handle - ): boolean { - if (isNode(baseNode)) { - const w = registry.byNode(baseNode); - if (w) { - // from dijit/_WidgetsInTemplateMixin - this._processTemplateNode(w, - (n, p) => n.get(p), // callback to get a property of a widget - (widget, type, callback) => { - if (!callback) - throw new Error("The callback must be specified"); - - // callback to do data-dojo-attach-event to a widget - if (type in widget) { - // back-compat, remove for 2.0 - return widget.connect(widget, type, callback as EventListener); - } else { - // 1.x may never hit this branch, but it's the default for 2.0 - return widget.on(type, callback); - } - - }); - // don't process widgets internals - return false; - } - } - return super._processTemplateNode(baseNode, getAttrFunc, attachFunc); - } -} diff --git a/src/main/ts/djx/HtmlElementContext.ts b/src/main/ts/djx/HtmlElementContext.ts deleted file mode 100644 --- a/src/main/ts/djx/HtmlElementContext.ts +++ /dev/null @@ -1,45 +0,0 @@ -import dom = require("dojo/dom-construct"); -import attr = require("dojo/dom-attr"); -import { argumentNotEmptyString } from "@implab/core-amd/safe"; -import { BuildContextBase } from "./BuildContextBase"; - -export class HtmlElementContext extends BuildContextBase { - elementType: string; - - _element: HTMLElement | undefined; - - constructor(elementType: string) { - argumentNotEmptyString(elementType, "elementType"); - super(); - - this.elementType = elementType; - } - - _addChild(child: any): void { - if (!this._element) - throw new Error("The HTML element isn't created"); - dom.place(this.getChildDom(child), this._element); - } - - _setAttrs(attrs: object): void { - if (!this._element) - throw new Error("The HTML element isn't created"); - - attr.set(this._element, attrs); - } - - _create(attrs: object, children: any[]) { - this._element = dom.create(this.elementType, attrs); - - if (children) - children.forEach(v => this._addChild(v)); - } - - _getDomElement() { - if (!this._element) - throw new Error("The HTML element isn't created"); - - return this._element; - } - -} diff --git a/src/main/ts/djx/WidgetContext.ts b/src/main/ts/djx/WidgetContext.ts deleted file mode 100644 --- a/src/main/ts/djx/WidgetContext.ts +++ /dev/null @@ -1,43 +0,0 @@ -import dom = require("dojo/dom-construct"); -import { argumentNotNull } from "@implab/core-amd/safe"; -import _WidgetBase = require("dijit/_WidgetBase"); -import { BuildContextBase } from "./BuildContextBase"; - -type _WidgetBaseConstructor = typeof _WidgetBase; - -export class WidgetContext extends BuildContextBase { - widgetClass: _WidgetBaseConstructor; - - _instance: _WidgetBase | undefined; - - constructor(widgetClass: _WidgetBaseConstructor) { - super(); - argumentNotNull(widgetClass, "widgetClass"); - - this.widgetClass = widgetClass; - } - - _addChild(child: any): void { - if (!this._instance || !this._instance.containerNode) - throw new Error("Widget doesn't support adding children"); - - dom.place(this.getChildDom(child), this._instance.containerNode); - } - - _setAttrs(attrs: object): void { - this._instance?.set(attrs); - } - - _create(attrs: object, children: any[]) { - this._instance = new this.widgetClass(this._attrs); - if (children) - children.forEach(x => this._addChild(x)); - } - - _getDomElement() { - if (!this._instance) - throw new Error("The instance of the widget isn't created"); - return this._instance.domNode; - } - -} diff --git a/src/main/ts/djx/traits.ts b/src/main/ts/djx/traits.ts deleted file mode 100644 --- a/src/main/ts/djx/traits.ts +++ /dev/null @@ -1,32 +0,0 @@ -import _WidgetBase = require("dijit/_WidgetBase"); - -type _WidgetBaseConstructor = typeof _WidgetBase; - - -export interface BuildContext { - getDomElement(): HTMLElement; -} - -export function isNode(el: any): el is HTMLElement { - return el && el.nodeName && el.nodeType; -} - -export function isWidget(v: any): v is _WidgetBase { - return v && "domNode" in v; -} - -export function isBuildContext(v: any): v is BuildContext { - return typeof v === "object" && typeof v.getDomElement === "function"; -} - -export function isPlainObject(v: object) { - if (typeof v !== "object") - return false; - - const vp = Object.getPrototypeOf(v); - return !vp || vp === Object.prototype; -} - -export function isWidgetConstructor(v: any): v is _WidgetBaseConstructor { - return typeof v === "function" && v.prototype && "domNode" in v.prototype; -} diff --git a/src/main/ts/tsx.ts b/src/main/ts/tsx.ts --- a/src/main/ts/tsx.ts +++ b/src/main/ts/tsx.ts @@ -1,7 +1,7 @@ import { Constructor } from "@implab/core-amd/interfaces"; -import { HtmlElementContext } from "./djx/HtmlElementContext"; -import { WidgetContext } from "./djx/WidgetContext"; -import { isWidgetConstructor, BuildContext } from "./djx/traits"; +import { HtmlElementContext } from "./tsx/HtmlElementContext"; +import { WidgetContext } from "./tsx/WidgetContext"; +import { isWidgetConstructor, BuildContext } from "./tsx/traits"; export function createElement(elementType: string | T, ...args: any[]): BuildContext { if (typeof elementType === "string") { diff --git a/src/main/ts/tsx/BuildContextBase.ts b/src/main/ts/tsx/BuildContextBase.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/tsx/BuildContextBase.ts @@ -0,0 +1,64 @@ +import { isNull, mixin, argumentNotNull } from "@implab/core-amd/safe"; +import { isPlainObject, isNode, isBuildContext } from "./traits"; + +export abstract class BuildContextBase { + _attrs = {}; + + _children = new Array(); + + _created: boolean = false; + + visitNext(v: any) { + if (isNull(v)) + return; + + if (isPlainObject(v)) { + + if (this._created) + this._setAttrs(v); + else + mixin(this._attrs, v); + + } else { + if (this._created) + this._addChild(v); + else + this._children.push(v); + } + } + + getChildDom(v: any) { + const tv = typeof v; + if (tv === "string" || tv === "number" || tv === "boolean" || v instanceof RegExp || v instanceof Date) { + return document.createTextNode(v.toString()); + } else if (isNode(v)) { + return v; + } else if (isBuildContext(v)) { + return v.getDomElement(); + } else { + throw new Error("Invalid parameter"); + } + } + + abstract _getDomElement(): HTMLElement; + + ensureCreated() { + if (!this._created) { + this._create(this._attrs, this._children); + this._children = []; + this._attrs = {}; + this._created = true; + } + } + + getDomElement() { + this.ensureCreated(); + return this._getDomElement(); + } + + abstract _addChild(child: any): void; + + abstract _setAttrs(attrs: object): void; + + abstract _create(attrs: object, children: any[]): void; +} diff --git a/src/main/ts/tsx/DjxWidgetBase.ts b/src/main/ts/tsx/DjxWidgetBase.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/tsx/DjxWidgetBase.ts @@ -0,0 +1,51 @@ +import { djbase, djclass } from "../declare"; +import _WidgetBase = require("dijit/_WidgetBase"); +import _AttachMixin = require("dijit/_AttachMixin"); +import { BuildContext, isNode } from "./traits"; +import registry = require("dijit/registry"); +// import { Handle } from "dojo/interfaces"; +type Handle = dojo.Handle; + +@djclass +export abstract class DjxWidgetBase extends djbase(_WidgetBase, _AttachMixin) { + + buildRendering() { + this.domNode = this.render().getDomElement(); + super.buildRendering(); + } + + abstract render(): BuildContext; + + _processTemplateNode( + baseNode: T, + getAttrFunc: (baseNode: T, attr: string) => string, + // tslint:disable-next-line: ban-types + attachFunc: (node: T, type: string, func?: Function) => Handle + ): boolean { + if (isNode(baseNode)) { + const w = registry.byNode(baseNode); + if (w) { + // from dijit/_WidgetsInTemplateMixin + this._processTemplateNode(w, + (n, p) => n.get(p), // callback to get a property of a widget + (widget, type, callback) => { + if (!callback) + throw new Error("The callback must be specified"); + + // callback to do data-dojo-attach-event to a widget + if (type in widget) { + // back-compat, remove for 2.0 + return widget.connect(widget, type, callback as EventListener); + } else { + // 1.x may never hit this branch, but it's the default for 2.0 + return widget.on(type, callback); + } + + }); + // don't process widgets internals + return false; + } + } + return super._processTemplateNode(baseNode, getAttrFunc, attachFunc); + } +} diff --git a/src/main/ts/tsx/HtmlElementContext.ts b/src/main/ts/tsx/HtmlElementContext.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/tsx/HtmlElementContext.ts @@ -0,0 +1,45 @@ +import dom = require("dojo/dom-construct"); +import attr = require("dojo/dom-attr"); +import { argumentNotEmptyString } from "@implab/core-amd/safe"; +import { BuildContextBase } from "./BuildContextBase"; + +export class HtmlElementContext extends BuildContextBase { + elementType: string; + + _element: HTMLElement | undefined; + + constructor(elementType: string) { + argumentNotEmptyString(elementType, "elementType"); + super(); + + this.elementType = elementType; + } + + _addChild(child: any): void { + if (!this._element) + throw new Error("The HTML element isn't created"); + dom.place(this.getChildDom(child), this._element); + } + + _setAttrs(attrs: object): void { + if (!this._element) + throw new Error("The HTML element isn't created"); + + attr.set(this._element, attrs); + } + + _create(attrs: object, children: any[]) { + this._element = dom.create(this.elementType, attrs); + + if (children) + children.forEach(v => this._addChild(v)); + } + + _getDomElement() { + if (!this._element) + throw new Error("The HTML element isn't created"); + + return this._element; + } + +} diff --git a/src/main/ts/tsx/WidgetContext.ts b/src/main/ts/tsx/WidgetContext.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/tsx/WidgetContext.ts @@ -0,0 +1,43 @@ +import dom = require("dojo/dom-construct"); +import { argumentNotNull } from "@implab/core-amd/safe"; +import _WidgetBase = require("dijit/_WidgetBase"); +import { BuildContextBase } from "./BuildContextBase"; + +type _WidgetBaseConstructor = typeof _WidgetBase; + +export class WidgetContext extends BuildContextBase { + widgetClass: _WidgetBaseConstructor; + + _instance: _WidgetBase | undefined; + + constructor(widgetClass: _WidgetBaseConstructor) { + super(); + argumentNotNull(widgetClass, "widgetClass"); + + this.widgetClass = widgetClass; + } + + _addChild(child: any): void { + if (!this._instance || !this._instance.containerNode) + throw new Error("Widget doesn't support adding children"); + + dom.place(this.getChildDom(child), this._instance.containerNode); + } + + _setAttrs(attrs: object): void { + this._instance?.set(attrs); + } + + _create(attrs: object, children: any[]) { + this._instance = new this.widgetClass(this._attrs); + if (children) + children.forEach(x => this._addChild(x)); + } + + _getDomElement() { + if (!this._instance) + throw new Error("The instance of the widget isn't created"); + return this._instance.domNode; + } + +} diff --git a/src/main/ts/tsx/traits.ts b/src/main/ts/tsx/traits.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/tsx/traits.ts @@ -0,0 +1,32 @@ +import _WidgetBase = require("dijit/_WidgetBase"); + +type _WidgetBaseConstructor = typeof _WidgetBase; + + +export interface BuildContext { + getDomElement(): HTMLElement; +} + +export function isNode(el: any): el is HTMLElement { + return el && el.nodeName && el.nodeType; +} + +export function isWidget(v: any): v is _WidgetBase { + return v && "domNode" in v; +} + +export function isBuildContext(v: any): v is BuildContext { + return typeof v === "object" && typeof v.getDomElement === "function"; +} + +export function isPlainObject(v: object) { + if (typeof v !== "object") + return false; + + const vp = Object.getPrototypeOf(v); + return !vp || vp === Object.prototype; +} + +export function isWidgetConstructor(v: any): v is _WidgetBaseConstructor { + return typeof v === "function" && v.prototype && "domNode" in v.prototype; +} diff --git a/src/main/typings/index.d.ts b/src/main/typings/index.d.ts new file mode 100644 --- /dev/null +++ b/src/main/typings/index.d.ts @@ -0,0 +1,4 @@ +declare module "@implab/djx/css!*" { + declare const result: { url: string }; + export = result; +} diff --git a/src/test/ts/dummy.ts b/src/test/ts/dummy.ts --- a/src/test/ts/dummy.ts +++ b/src/test/ts/dummy.ts @@ -1,6 +1,8 @@ import { test } from "./TestTraits"; import { delay } from "@implab/core-amd/safe"; import { assert } from "chai"; +import "@implab/djx"; +import css = require("@implab/djx/css!my,css"); test("simple", (ok, fail, log) => { setTimeout(() => { diff --git a/src/test/tsconfig.json b/src/test/tsconfig.json --- a/src/test/tsconfig.json +++ b/src/test/tsconfig.json @@ -1,11 +1,18 @@ { "extends": "../tsconfig", "compilerOptions": { + "baseUrl": ".", "rootDir": "ts", "rootDirs": [ "ts", - "../main/ts" + "typings", + "../main/ts", + "../main/typings" ], + "paths": { + "@implab/djx" : ["../main/ts", "../main/typings"] + //"@implab/djx/*" : ["../main/ts/*", "../main/typings/*" ] + }, "types": ["requirejs"] } } \ No newline at end of file