##// END OF EJS Templates
corrected i18n, css modules to support requirejs optimizer...
cin -
r53:deb0ed6fb680 v1.0.7 default
parent child
Show More
@@ -0,0 +1,8
1 import { bundle } from "../i18n";
2
3 export default bundle({
4 greeting: (name: string) => `Hello, ${name}!`,
5 goodbye: (name: string) => `Bye, ${name}!`
6 }, {
7 ru: () => import("./ru/foo")
8 });
@@ -0,0 +1,6
1 import foo from "../foo";
2
3 export default foo.define({
4 greeting: (name: string) => `ΠŸΡ€ΠΈΠ²Π΅Ρ‚, ${name}`,
5 goodbye: (name: string) => `Пока, ${name}`
6 });
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -1,198 +1,198
1 # @implab/djx
1 # @implab/djx
2
2
3 ## SYNOPSIS
3 ## SYNOPSIS
4
4
5 ```tsx
5 ```tsx
6 import { djbase, djclass, bind, prototype, AbstractConstructor } from "@implab/djx/declare";
6 import { djbase, djclass, bind, prototype, AbstractConstructor } from "@implab/djx/declare";
7
7
8 import { DjxWidgetBase } from "@implab/djx/tsx/DjxWidgetBase";
8 import { DjxWidgetBase } from "@implab/djx/tsx/DjxWidgetBase";
9 import { createElement } from "@implab/djx/tsx";
9 import { createElement } from "@implab/djx/tsx";
10
10
11 interface MyWidgetAttrs {
11 interface MyWidgetAttrs {
12 title: string;
12 title: string;
13
13
14 counter: number;
14 counter: number;
15 }
15 }
16
16
17 interface MyWidgetEvents {
17 interface MyWidgetEvents {
18 "count-inc": Event;
18 "count-inc": Event;
19
19
20 "count-dec": Event;
20 "count-dec": Event;
21 }
21 }
22
22
23
23
24 @djclass
24 @djclass
25 export class MyWidget extends djbase(
25 export class MyWidget extends djbase(
26 DjxWidgetBase as AbstractConstructor<DjxWidgetBase<MyWidgetAttrs, MyWidgetEvents>>
26 DjxWidgetBase as AbstractConstructor<DjxWidgetBase<MyWidgetAttrs, MyWidgetEvents>>
27 ) {
27 ) {
28
28
29 @bind({ node: "titleNode", type: "innerHTML" })
29 @bind({ node: "titleNode", type: "innerHTML" })
30 title = "";
30 title = "";
31
31
32 @prototype()
32 @prototype()
33 counter = 0;
33 counter = 0;
34
34
35 render() {
35 render() {
36 const Frame = (props: any) => <div>{props.children}</div>;
36 const Frame = (props: any) => <div>{props.children}</div>;
37 return <div
37 return <div
38 className="myWidget"
38 className="myWidget"
39 tabIndex={3}
39 tabIndex={3}
40 style={ alignContent: "center", border: "1px solid" }
40 style={ alignContent: "center", border: "1px solid" }
41 >
41 >
42 <h1 data-dojo-attach-point="titleNode"></h1>
42 <h1 data-dojo-attach-point="titleNode"></h1>
43 <Frame>
43 <Frame>
44 <span class="up-button" onclick={e => this._onIncClick(e)}>[+]</span>
44 <span class="up-button" onclick={e => this._onIncClick(e)}>[+]</span>
45 <span class="down-button" onclick={() => this._onDecClick()}>[-]</span>
45 <span class="down-button" onclick={() => this._onDecClick()}>[-]</span>
46 </Frame>
46 </Frame>
47 </div>;
47 </div>;
48 }
48 }
49
49
50 _onIncClick(e: MouseEvent) {
50 _onIncClick(e: MouseEvent) {
51 this.emit("count-inc", { bubbles: false });
51 this.emit("count-inc", { bubbles: false });
52 }
52 }
53
53
54 _onDecClick() {
54 _onDecClick() {
55 this.emit("count-dec", { bubbles: false });
55 this.emit("count-dec", { bubbles: false });
56 }
56 }
57 }
57 }
58
58
59 ```
59 ```
60
60
61 ## DESCRIPTION
61 ## DESCRIPTION
62
62
63 This package provides you with tools to glue your good-fellow dojo with modern
63 This package provides you with the tools to glue your good-fellow dojo with modern
64 techniques of building the webapp. The core concept is built around widgets and
64 techniques of building the webapp. The core concept is to built around widgets and
65 using .tsx to write it. Here some features:
65 using .tsx to write it. Here are some features:
66
66
67 * `djbase()`, `@djaclass` - traits to declare your classes with `dojo/_base/declare`
67 * `djbase()`, `@djaclass` - traits to declare your classes with `dojo/_base/declare`
68 * `@implab/djx/tsx` - traits to build the rendering of your widgets with tsx
68 * `@implab/djx/tsx` - traits to build the rendering of your widgets with tsx
69 * `DjxWidgetBase` - abstract class which supports tsx markup and
69 * `DjxWidgetBase` - abstract class which supports tsx markup and
70 `data-dojo-attach-*` attributes.
70 `data-dojo-attach-*` attributes.
71 * `@bind(...)` - annotations provides an easy way of using standard dojo widget
71 * `@bind(...)` - annotations provide an easy way of using standard dojo widget
72 attribute bindings.
72 attribute bindings.
73
73
74 ### djbase, @djclass
74 ### djbase, @djclass
75
75
76 These two traits provides convenient way of using `dojo/_base/declare` in Typescript
76 These two traits provide convenient way of using `dojo/_base/declare` in Typescript
77 for declaring your classes.
77 for declaring your classes.
78
78
79 `djbase(...constructors)` - this method accepts a list of constructors in its
79 `djbase(...constructors)` - this method accepts a list of constructors in its
80 parameters and returns the **fake** base type which then can be used to derive
80 parameters and returns the **fake** base type which then can be used to derive
81 your own class. This allows you to provide the Typescript with the correct
81 your own class. This allows you to provide the Typescript with the correct
82 information about the base type and even use `super`!. The only one caveat of
82 information about the base type and even use `super`!. The only caveat of
83 this approach is that you **MUST** decorate your class with `@djclass` annotation.
83 this approach is that you **MUST** decorate your class with `@djclass` annotation.
84
84
85 Consider the following example:
85 Consider the following example:
86
86
87 ```ts
87 ```ts
88 import { djbase, djclass } from "@implab/djx/declare";
88 import { djbase, djclass } from "@implab/djx/declare";
89 import { FooMixin } from "./FooMixin";
89 import { FooMixin } from "./FooMixin";
90 import { BarMixin } from "./BarMixin";
90 import { BarMixin } from "./BarMixin";
91 import { BoxMixin } from "./BoxMixin";
91 import { BoxMixin } from "./BoxMixin";
92
92
93 @djclass
93 @djclass
94 export class Baz extends djbase(FooMixin, BarMixin, BoxMixin) {
94 export class Baz extends djbase(FooMixin, BarMixin, BoxMixin) {
95 writeHello(out: string[]) {
95 writeHello(out: string[]) {
96 out.push("-> Baz");
96 out.push("-> Baz");
97
97
98 super.writeHello(out);
98 super.writeHello(out);
99
99
100 out.push("<- Baz");
100 out.push("<- Baz");
101 }
101 }
102 }
102 }
103
103
104 ```
104 ```
105
105
106 All mixins are declared like the one below:
106 All mixins are declared like the one below:
107
107
108 ```ts
108 ```ts
109 import { djclass, djbase } from "@implab/djx/declare";
109 import { djclass, djbase } from "@implab/djx/declare";
110
110
111 interface Super {
111 interface Super {
112 writeHello(out: string[]): void;
112 writeHello(out: string[]): void;
113
113
114 }
114 }
115
115
116 @djclass
116 @djclass
117 export class BarMixin extends djbase<Super>() {
117 export class BarMixin extends djbase<Super>() {
118 writeHello(out: string[]) {
118 writeHello(out: string[]) {
119 out.push("-> Bar");
119 out.push("-> Bar");
120
120
121 super.writeHello(out);
121 super.writeHello(out);
122
122
123 out.push("<- Bar");
123 out.push("<- Bar");
124 }
124 }
125 }
125 }
126 ```
126 ```
127
127
128 finally create an instance and call the `writeHello` method
128 finally create an instance and call the `writeHello` method
129
129
130 ```ts
130 ```ts
131 const baz = new Baz();
131 const baz = new Baz();
132
132
133 const data: string[] = [];
133 const data: string[] = [];
134 baz.writeHello(data);
134 baz.writeHello(data);
135
135
136 console.log(data.join("\n"));
136 console.log(data.join("\n"));
137
137
138 ```
138 ```
139
139
140 you will get the following output:
140 you will get the following output:
141
141
142 ```text
142 ```text
143 -> Baz
143 -> Baz
144 -> Box
144 -> Box
145 -> Bar
145 -> Bar
146 -> Foo
146 -> Foo
147 <- Foo
147 <- Foo
148 <- Bar
148 <- Bar
149 <- Box
149 <- Box
150 <- Baz
150 <- Baz
151 ```
151 ```
152
152
153 Let's take a closer look to the `Baz` declaration it uses `djbase` to derive
153 Let's take a closer look at the `Baz` declaration it uses `djbase` to derive
154 from three mixins and the class is decorated with `@djclass` to accomplish the
154 from three mixins and the class is decorated with `@djclass` to accomplish the
155 declaration and make a real constructor.
155 declaration and make a real constructor.
156
156
157 To allow an access to the next sibling method (in terms of multiple inheritance)
157 To allow access to the next sibling method (in terms of multiple inheritance)
158 Dojo provides `this.inherited(arguments)` method but this approach leads to the
158 Dojo provides `this.inherited(arguments)` method but this approach leads to the
159 problem with 'strict' mode of ES5 and eliminates the type information about a
159 problem with 'strict' mode of ES5 and eliminates the type information about a
160 calling method. This library solves the problem calling inherited/next method by
160 calling method. This library solves the problem calling inherited/next method by
161 utilizing `super` keyword. Under the hood there are proxy methods generated in
161 utilizing `super` keyword. Under the hood there are proxy methods generated in
162 the prototype of the declared class which make calls to `this.inherited(...)`
162 the prototype of the declared class which make calls to `this.inherited(...)`
163 method. This technique is compatible with 'strict' mode.
163 method. This technique is compatible with 'strict' mode.
164
164
165 Mixins are declared the similar, they are also may have the base types although
165 Mixins are declared similar, they also may have the base types although
166 the most common case is declaring the mixin without any base classes. To allow
166 the most common case is declaring the mixin without any base classes. To allow
167 the mixin to access the next method you should declare the interface with
167 the mixin to access the next method declare the interface with
168 desired methods and use the special form of `djbase<Super>()` without arguments.
168 desired methods and use the special form of `djbase<Super>()` without arguments.
169
169
170 ### DjxWidgetBase<Attrs, Events>
170 ### DjxWidgetBase<Attrs, Events>
171
171
172 TODO
172 TODO
173
173
174 ### Markup (.tsx)
174 ### Markup (.tsx)
175
175
176 Add to your `tsconfig.json` the following options
176 Add to your `tsconfig.json` the following options
177
177
178 ```json
178 ```json
179 {
179 {
180 "compilerOptions": {
180 "compilerOptions": {
181 "types": ["@implab/djx"],
181 "types": ["@implab/djx"],
182 "experimentalDecorators": true,
182 "experimentalDecorators": true,
183 "jsxFactory": "createElement",
183 "jsxFactory": "createElement",
184 "jsx": "react",
184 "jsx": "react",
185 }
185 }
186 }
186 }
187
187
188 ```
188 ```
189
189
190 Import `createElement` into your `.tsx` file
190 Import `createElement` into your `.tsx` file
191
191
192 ```ts
192 ```ts
193 import { createElement } from "@implab/djx/tsx";
193 import { createElement } from "@implab/djx/tsx";
194 ```
194 ```
195
195
196 You are ready to go!
196 You are ready to go!
197
197
198 TODO
198 TODO
@@ -1,81 +1,82
1 import { MapOf } from "@implab/core-amd/interfaces";
1 import { MapOf } from "@implab/core-amd/interfaces";
2 import { isPromise, mixin } from "@implab/core-amd/safe";
2 import { isPromise, mixin } from "@implab/core-amd/safe";
3 import { locale as sysLocale } from "dojo/_base/kernel";
3 import { locale as sysLocale } from "dojo/_base/kernel";
4 import { id as mid } from "module";
4 import { id as mid } from "module";
5 import { TraceSource } from "@implab/core-amd/log/TraceSource";
5 import { TraceSource } from "@implab/core-amd/log/TraceSource";
6
6
7 const trace = TraceSource.get(mid);
7 const trace = TraceSource.get(mid);
8
8
9 type PromiseOrValue<T> = PromiseLike<T> | T;
9 type PromiseOrValue<T> = PromiseLike<T> | T;
10 type ResolveCallback<T> = () => PromiseOrValue<T>;
10 type ResolveCallback<T> = () => PromiseOrValue<T>;
11
11
12 trace.debug("Current sysLocale: {0}", sysLocale);
12 trace.debug("Current sysLocale: {0}", sysLocale);
13
13
14 function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> {
14 function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> {
15 return isPromise(value) ?
15 return isPromise(value) ?
16 value.then(cb) :
16 value.then(cb) :
17 cb(value);
17 cb(value);
18 }
18 }
19
19
20 function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> {
20 function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> {
21 return typeof v === "function";
21 return typeof v === "function";
22 }
22 }
23
23
24 function defaultResolver(module: string) {
25 return import(module).then(x => x && x.default ? x.default : x);
26 }
27
24 function chainObjects<T extends object>(o1: T, o2: T) {
28 function chainObjects<T extends object>(o1: T, o2: T) {
25 if (!o1)
29 if (!o1)
26 return o2;
30 return o2;
27 if (!o2)
31 if (!o2)
28 return o1;
32 return o1;
29
33
30 return mixin(Object.create(o1) as T, o2);
34 return mixin(Object.create(o1) as T, o2);
31 }
35 }
32
36
33 export class NlsBundle<T extends object> {
37 export class NlsBundle<T extends object> {
34 _locales: MapOf<ResolveCallback<T> | PromiseOrValue<T>>;
38 private _locales: MapOf<ResolveCallback<T> | PromiseOrValue<T>>;
35 default: T;
36
39
37 _cache: MapOf<PromiseOrValue<T>>;
40 private _default: T;
41
42 private _cache: MapOf<PromiseOrValue<T>>;
38
43
39 constructor(defNls: T, locales?: MapOf<any>) {
44 constructor(defNls: T, locales?: MapOf<any>) {
40 this.default = defNls;
45 this._default = defNls;
41 this._locales = locales || {};
46 this._locales = locales || {};
42 this._cache = {};
47 this._cache = {};
43 }
48 }
44
49
45 getLocale(locale: string) {
50 getLocale(locale?: string) {
46 const _loc = locale || sysLocale;
51 const _loc = locale ?? sysLocale;
47
48 const locales = new Array<string>();
49
52
50 _loc.split("-").reduce((a, x) => {
53 // en-US => ["en", "en-US"]
51 a.push(x);
54 const locales = _loc.split(/-|_/).map((x, i, a) => a.slice(0, i + 1).join("-"));
52 locales.unshift(a.join("-"));
53 return a;
54 }, new Array<string>());
55
56 return this._resolveLocale(locales);
55 return this._resolveLocale(locales);
57 }
56 }
58
57
59 _resolveLocale(locales: string[]): PromiseOrValue<T> {
58 _resolveLocale(locales: string[]): PromiseOrValue<T> {
60 if (!locales.length)
59 if (!locales.length)
61 return this.default;
60 return this._default;
62
61
63 const locale = locales.shift();
62 const locale = locales.pop();
64
65 if (!locale)
63 if (!locale)
66 return this._resolveLocale(locales);
64 throw new Error("The locale can't be empty");
67
65
68 if (this._cache[locale])
66 if (this._cache[locale])
69 return this._cache[locale];
67 return this._cache[locale];
70
68
71 let data = this._locales[locale];
69 const data = this._loadPackage(this._locales[locale]);
72 if (isCallback(data))
73 data = data();
74
75 const parent = this._resolveLocale(locales);
70 const parent = this._resolveLocale(locales);
76
71
77 return this._cache[locale] = when(data, x => {
72 return this._cache[locale] = when(data, x => {
78 return when(parent, y => this._cache[locale] = chainObjects(y, x));
73 return when(parent, y => this._cache[locale] = chainObjects(y, x));
79 });
74 });
80 }
75 }
76
77 _loadPackage(localeData: any) {
78 if (isCallback(localeData))
79 return when(localeData(), data => data && "default" in data ? data.default : data);
80 return localeData;
81 }
81 }
82 }
@@ -1,18 +1,18
1 import inject from "./dom-inject";
1 import inject from "./dom-inject";
2
2
3 interface OnLoad {
3 interface OnLoad {
4 (result?: any): void;
4 (result?: any): void;
5 error(err: any): void;
5 error(err: any): void;
6 }
6 }
7
7
8 const plugin = {
8 const plugin = {
9 load: (id: string, require: Require, cb: OnLoad, config: { isBuild?: boolean }) => {
9 load: (id: string, require: Require, cb: OnLoad, config: { isBuild?: boolean }) => {
10 if (config.isBuild) {
10 if (config && config.isBuild) {
11 cb();
11 cb();
12 } else {
12 } else {
13 const url = require.toUrl(id);
13 const url = require.toUrl(id);
14 inject.injectStylesheet(url).then(() => cb({ url }), e => cb.error(e));
14 inject.injectStylesheet(url).then(() => cb({ url }), e => cb.error(e));
15 }
15 }
16 }
16 }
17 };
17 };
18 export = plugin;
18 export = plugin;
@@ -1,38 +1,38
1 import { MapOf } from "@implab/core-amd/interfaces";
1 import { MapOf } from "@implab/core-amd/interfaces";
2 import { NlsBundle } from "./NlsBundle";
2 import { NlsBundle } from "./NlsBundle";
3 import { isPromise } from "@implab/core-amd/safe";
3 import { isPromise } from "@implab/core-amd/safe";
4
4
5 export interface OnLoad {
5 export interface OnLoad {
6 (result?: any): void;
6 (result?: any): void;
7 error(err: any): void;
7 error(err: any): void;
8 }
8 }
9
9
10 export function bundle<T extends object>(nls: T, locales?: MapOf<any>) {
10 export function bundle<T extends object>(nls: T, locales?: MapOf<any>) {
11 const nlsBundle = new NlsBundle(nls, locales);
11 const nlsBundle = new NlsBundle(nls, locales);
12
12
13 const fn = (locale?: string) => {
13 const fn = (locale?: string) => {
14 const result = locale ? nlsBundle.getLocale(locale) : nlsBundle.default;
14 const result = nlsBundle.getLocale(locale);
15
15
16 if (isPromise(result))
16 if (isPromise(result))
17 throw new Error(`The bundle '${locale}' isn't loaded`);
17 throw new Error(`The bundle '${locale}' isn't loaded`);
18 else
18 else
19 return result;
19 return result;
20 };
20 };
21
21
22 fn.define = (pack: Partial<T>) => pack;
22 fn.define = (pack: Partial<T>) => pack;
23 fn.default = nlsBundle.default;
24 fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => {
23 fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => {
25 if (config && config.isBuild) {
24 if (config && config.isBuild) {
26 cb();
25 cb();
27 } else {
26 } else {
28 try {
27 try {
29 await nlsBundle.getLocale(id);
28 await nlsBundle.getLocale(id);
30 cb();
29 cb();
31 } catch (e) {
30 } catch (e) {
32 cb.error(e);
31 if(cb.error)
32 cb.error(e);
33 }
33 }
34 }
34 }
35 };
35 };
36
36
37 return fn;
37 return fn;
38 }
38 }
General Comments 0
You need to be logged in to leave comments. Login now