@@ -0,0 +1,1 | |||
|
1 | .eslintrc.js No newline at end of file |
@@ -0,0 +1,39 | |||
|
1 | module.exports = { | |
|
2 | root: true, | |
|
3 | extends: [ | |
|
4 | "plugin:react/recommended", | |
|
5 | "eslint:recommended", | |
|
6 | "plugin:@typescript-eslint/eslint-recommended", | |
|
7 | "plugin:@typescript-eslint/recommended", | |
|
8 | "plugin:@typescript-eslint/recommended-requiring-type-checking" | |
|
9 | ], | |
|
10 | parser: "@typescript-eslint/parser", | |
|
11 | parserOptions: { | |
|
12 | ecmaFeatures: { | |
|
13 | jsx: true | |
|
14 | }, | |
|
15 | ecmaVersion: 5, | |
|
16 | tsconfigRootDir: __dirname + "/src", | |
|
17 | project: [ | |
|
18 | "tsconfig.eslint.json", | |
|
19 | "*/tsconfig.json" | |
|
20 | ] | |
|
21 | }, | |
|
22 | plugins: [ | |
|
23 | "react", | |
|
24 | "@typescript-eslint" | |
|
25 | ], | |
|
26 | rules: { | |
|
27 | "react/react-in-jsx-scope": "off", | |
|
28 | "react/no-unknown-property": "off", | |
|
29 | "@typescript-eslint/no-empty-function": "off", | |
|
30 | "max-classes-per-file": [ | |
|
31 | "error", | |
|
32 | { "ignoreExpressions": true, "max": 1 } | |
|
33 | ], | |
|
34 | "@typescript-eslint/prefer-readonly": ["error"], | |
|
35 | "semi": "off", | |
|
36 | "@typescript-eslint/semi": ["error"] | |
|
37 | ||
|
38 | } | |
|
39 | } |
@@ -0,0 +1,39 | |||
|
1 | module.exports = { | |
|
2 | root: true, | |
|
3 | extends: [ | |
|
4 | "plugin:react/recommended", | |
|
5 | "eslint:recommended", | |
|
6 | "plugin:@typescript-eslint/eslint-recommended", | |
|
7 | "plugin:@typescript-eslint/recommended", | |
|
8 | "plugin:@typescript-eslint/recommended-requiring-type-checking" | |
|
9 | ], | |
|
10 | parser: "@typescript-eslint/parser", | |
|
11 | parserOptions: { | |
|
12 | ecmaFeatures: { | |
|
13 | jsx: true | |
|
14 | }, | |
|
15 | ecmaVersion: 5, | |
|
16 | tsconfigRootDir: __dirname + "/src", | |
|
17 | project: [ | |
|
18 | "tsconfig.eslint.json", | |
|
19 | "*/tsconfig.json" | |
|
20 | ] | |
|
21 | }, | |
|
22 | plugins: [ | |
|
23 | "react", | |
|
24 | "@typescript-eslint" | |
|
25 | ], | |
|
26 | rules: { | |
|
27 | "react/react-in-jsx-scope": "off", | |
|
28 | "react/no-unknown-property": "off", | |
|
29 | "@typescript-eslint/no-empty-function": "off", | |
|
30 | "max-classes-per-file": [ | |
|
31 | "error", | |
|
32 | { "ignoreExpressions": true, "max": 1 } | |
|
33 | ], | |
|
34 | "@typescript-eslint/prefer-readonly": ["error"], | |
|
35 | "semi": "off", | |
|
36 | "@typescript-eslint/semi": ["error"], | |
|
37 | "react/jsx-key": "off" | |
|
38 | } | |
|
39 | } |
@@ -10,7 +10,7 | |||
|
10 | 10 | "license": "BSD-2-Clause", |
|
11 | 11 | "devDependencies": { |
|
12 | 12 | "@implab/core-amd": "^1.4.0", |
|
13 |
"@implab/dojo-typings": "1.0. |
|
|
13 | "@implab/dojo-typings": "1.0.3", | |
|
14 | 14 | "@types/chai": "4.1.3", |
|
15 | 15 | "@types/requirejs": "2.1.31", |
|
16 | 16 | "@types/tap": "15.0.7", |
@@ -458,9 +458,9 | |||
|
458 | 458 | "dev": true |
|
459 | 459 | }, |
|
460 | 460 | "node_modules/@implab/dojo-typings": { |
|
461 |
"version": "1.0. |
|
|
462 |
"resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0. |
|
|
463 | "integrity": "sha512-B2kvlKJgvyIQAl/k1pVyNmtp4ADvBDCs4Lw/qfBC+Sz/ft4c7EuRXmN/+2dhWrd6A5SMjEgex5oeq6Ja2ntrig==", | |
|
461 | "version": "1.0.3", | |
|
462 | "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.3.tgz", | |
|
463 | "integrity": "sha512-oyCiuU5ay9MfvdQtZNJSeV30jKufdiLBAcq6rn360pww2hzdqvWEeoU9/New8fMzyNiaEumOlgbcS11EVIH+Jg==", | |
|
464 | 464 | "dev": true |
|
465 | 465 | }, |
|
466 | 466 | "node_modules/@istanbuljs/load-nyc-config": { |
@@ -7030,9 +7030,9 | |||
|
7030 | 7030 | "dev": true |
|
7031 | 7031 | }, |
|
7032 | 7032 | "@implab/dojo-typings": { |
|
7033 |
"version": "1.0. |
|
|
7034 |
"resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0. |
|
|
7035 | "integrity": "sha512-B2kvlKJgvyIQAl/k1pVyNmtp4ADvBDCs4Lw/qfBC+Sz/ft4c7EuRXmN/+2dhWrd6A5SMjEgex5oeq6Ja2ntrig==", | |
|
7033 | "version": "1.0.3", | |
|
7034 | "resolved": "https://registry.npmjs.org/@implab/dojo-typings/-/dojo-typings-1.0.3.tgz", | |
|
7035 | "integrity": "sha512-oyCiuU5ay9MfvdQtZNJSeV30jKufdiLBAcq6rn360pww2hzdqvWEeoU9/New8fMzyNiaEumOlgbcS11EVIH+Jg==", | |
|
7036 | 7036 | "dev": true |
|
7037 | 7037 | }, |
|
7038 | 7038 | "@istanbuljs/load-nyc-config": { |
@@ -25,7 +25,7 | |||
|
25 | 25 | "@types/yaml": "1.2.0", |
|
26 | 26 | "@types/tap": "15.0.7", |
|
27 | 27 | "dojo": "1.16.0", |
|
28 |
"@implab/dojo-typings": "1.0. |
|
|
28 | "@implab/dojo-typings": "1.0.3", | |
|
29 | 29 | "@typescript-eslint/eslint-plugin": "^5.23.0", |
|
30 | 30 | "@typescript-eslint/parser": "^5.23.0", |
|
31 | 31 | "eslint": "^8.23.0", |
@@ -3,31 +3,18 import { argumentNotEmptyString, isPromi | |||
|
3 | 3 | |
|
4 | 4 | export type LocaleProvider<T> = () => PromiseOrValue<T | { default: T }>; |
|
5 | 5 | |
|
6 | type ResolveCallback<T> = () => PromiseOrValue<T>; | |
|
7 | ||
|
8 | 6 | function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> { |
|
9 | 7 | return isPromise(value) ? |
|
10 | 8 | value.then(cb) : |
|
11 | 9 | cb(value); |
|
12 | 10 | } |
|
13 | 11 | |
|
14 | function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> { | |
|
15 | return typeof v === "function"; | |
|
16 | } | |
|
12 | const chainObjects = <T extends object, T2 extends object>(o1: T, o2: T2) => | |
|
13 | mixin(Object.create(o1) as T, o2); | |
|
14 | export class NlsBundle<T extends object> { | |
|
15 | private readonly _locales: MapOf<LocaleProvider<Partial<T>>>; | |
|
17 | 16 | |
|
18 | function chainObjects<T extends object>(o1: T, o2: T) { | |
|
19 | if (!o1) | |
|
20 | return o2; | |
|
21 | if (!o2) | |
|
22 | return o1; | |
|
23 | ||
|
24 | return mixin(Object.create(o1) as T, o2); | |
|
25 | } | |
|
26 | ||
|
27 | export class NlsBundle<T extends object> { | |
|
28 | private _locales: MapOf<LocaleProvider<Partial<T>>>; | |
|
29 | ||
|
30 | private _default: T; | |
|
17 | private readonly _default: T; | |
|
31 | 18 | |
|
32 | 19 | private _cache: MapOf<PromiseOrValue<T>>; |
|
33 | 20 | |
@@ -65,9 +52,7 export class NlsBundle<T extends object> | |||
|
65 | 52 | }); |
|
66 | 53 | } |
|
67 | 54 | |
|
68 |
_loadPackage(localeData: |
|
|
69 | if (isCallback(localeData)) | |
|
55 | _loadPackage(localeData: LocaleProvider<Partial<T>>) { | |
|
70 | 56 |
|
|
71 | return localeData; | |
|
72 | 57 | } |
|
73 | 58 | } |
@@ -1,8 +1,8 | |||
|
1 | 1 | import inject from "./dom-inject"; |
|
2 | 2 | |
|
3 | 3 | interface OnLoad { |
|
4 |
(result?: |
|
|
5 |
error(err: |
|
|
4 | (result?: unknown): void; | |
|
5 | error(err: unknown): void; | |
|
6 | 6 | } |
|
7 | 7 | |
|
8 | 8 | const plugin = { |
@@ -137,9 +137,10 export function djclass<T extends Abstra | |||
|
137 | 137 | |
|
138 | 138 | // proxy - фабрика для создания прокси-методов, которые внутри |
|
139 | 139 | // себя вызовут this.inherited с правильными параметрами. |
|
140 |
const proxy = (m: (...args: unknown[]) => unknown) => function (this: dojo._base.DeclareCreatedObject |
|
|
141 |
const f = this.getInherited({ callee: m |
|
|
142 | return f ? f.apply(this, args) as unknown : undefined; | |
|
140 | const proxy = (m: (...args: unknown[]) => unknown) => function (this: dojo._base.DeclareCreatedObject) { | |
|
141 | const f = this.getInherited({ callee: m } as unknown as IArguments); | |
|
142 | // eslint-disable-next-line prefer-rest-params | |
|
143 | return f ? f.apply(this, arguments) as unknown : undefined; | |
|
143 | 144 | |
|
144 | 145 | // так сделать можно только dojo 1.15+ |
|
145 | 146 | // return this.inherited(m, arguments); |
@@ -153,7 +154,7 export function djclass<T extends Abstra | |||
|
153 | 154 | each(target.prototype, (m: unknown, p: string) => { |
|
154 | 155 | if (typeof m === "function" && |
|
155 | 156 | p !== "constructor" && |
|
156 | Object.prototype.hasOwnProperty.call(target, p) | |
|
157 | Object.prototype.hasOwnProperty.call(target.prototype, p) | |
|
157 | 158 | ) { |
|
158 | 159 | nbp[p] = proxy(m as (...args: unknown[]) => unknown); |
|
159 | 160 | } |
@@ -224,18 +225,18 export function bind(params: NodeBindSpe | |||
|
224 | 225 | target[makeSetterName(name) as K /** hack to not go insane) */] = params; |
|
225 | 226 | }; |
|
226 | 227 | } else { |
|
227 | return <K extends string, | |
|
228 | T extends { [p in K]: p extends "_set" ? (name: p, v: unknown) => void : unknown; }> (target: T, name: K) => { | |
|
229 | target[name] = undefined as T[K]; | |
|
230 |
target[makeSetterName(name) as K] = function (this: |
|
|
231 | this._set(name, v); | |
|
232 | const inner = this[params.member] as Record<string, unknown>; | |
|
228 | return <K extends string>(target: Record<K | "_set", unknown>, name: K) => { | |
|
229 | target[name] = undefined; | |
|
230 | ||
|
231 | target[makeSetterName(name) as K] = function (this: typeof target, v: unknown) { | |
|
232 | (this._set as (n: K, v: unknown) => void)(name, v); | |
|
233 | const inner = this[params.member as K] as Record<string, unknown>; | |
|
233 | 234 | if (typeof inner.set === "function") |
|
234 | 235 | inner.set(params.property, v); |
|
235 |
} |
|
|
236 | }; | |
|
236 | 237 | if (params.getter) |
|
237 | target[makeGetterName(name)] = function () { | |
|
238 | const inner = this[params.member] as Record<string, unknown>; | |
|
238 | target[makeGetterName(name) as K] = function (this: typeof target) { | |
|
239 | const inner = this[params.member as K] as Record<string, unknown>; | |
|
239 | 240 | if (typeof inner.get === "function") |
|
240 | 241 | return inner.get(params.property) as unknown; |
|
241 | 242 | }; |
@@ -6,7 +6,7 import { mixin } from "@implab/core-amd/ | |||
|
6 | 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]) => |
|
|
9 | function on<T extends keyof HTMLElementEventMap>(node: HTMLElement, eventName: T, handler: (this: HTMLElement, ev: HTMLElementEventMap[T]) => unknown): () => void { | |
|
10 | 10 | // Add an event listener to a DOM node |
|
11 | 11 | node.addEventListener(eventName, handler, false); |
|
12 | 12 | |
@@ -57,7 +57,7 class DomInject { | |||
|
57 | 57 | |
|
58 | 58 | async injectScript(url: string) { |
|
59 | 59 | let d = this._map[url]; |
|
60 |
if ( |
|
|
60 | if (d === undefined) { | |
|
61 | 61 | trace.log("js {0}", url); |
|
62 | 62 | d = this._inject("script", { |
|
63 | 63 | type: "text/javascript", |
@@ -77,7 +77,7 class DomInject { | |||
|
77 | 77 | |
|
78 | 78 | async injectStylesheet(url: string) { |
|
79 | 79 | let d = this._map[url]; |
|
80 |
if ( |
|
|
80 | if (d === undefined) { | |
|
81 | 81 | trace.log("js {0}", url); |
|
82 | 82 | d = this._inject("link", { |
|
83 | 83 | type: "text/css", |
@@ -1,6 +1,6 | |||
|
1 | 1 | import { id as mid} from "module"; |
|
2 | 2 | import { MapOf } from "@implab/core-amd/interfaces"; |
|
3 | import { NlsBundle } from "./NlsBundle"; | |
|
3 | import { LocaleProvider, NlsBundle } from "./NlsBundle"; | |
|
4 | 4 | import { isPromise } from "@implab/core-amd/safe"; |
|
5 | 5 | import { locale as sysLocale } from "dojo/_base/kernel"; |
|
6 | 6 | import { TraceSource } from "@implab/core-amd/log/TraceSource"; |
@@ -10,11 +10,11 const trace = TraceSource.get(mid); | |||
|
10 | 10 | trace.debug("Current sysLocale: {0}", sysLocale); |
|
11 | 11 | |
|
12 | 12 | export interface OnLoad { |
|
13 |
(result?: |
|
|
14 |
error(err: |
|
|
13 | (result?: unknown): void; | |
|
14 | error(err: unknown): void; | |
|
15 | 15 | } |
|
16 | 16 | |
|
17 |
export function bundle<T extends object>(nls: T, locales?: MapOf< |
|
|
17 | export function bundle<T extends object>(nls: T, locales?: MapOf<LocaleProvider<object>>) { | |
|
18 | 18 | const nlsBundle = new NlsBundle(nls, locales); |
|
19 | 19 | |
|
20 | 20 | const fn = (_locale?: string) => { |
@@ -28,7 +28,7 export function bundle<T extends object> | |||
|
28 | 28 | }; |
|
29 | 29 | |
|
30 | 30 | fn.define = (pack: Partial<T>) => pack; |
|
31 |
fn.load = async (id: string, require: Require, cb: OnLoad, config: |
|
|
31 | fn.load = async (id: string, require: Require, cb: OnLoad, config: {isBuild?: boolean}) => { | |
|
32 | 32 | const locale = id || sysLocale; |
|
33 | 33 | if (config && config.isBuild) { |
|
34 | 34 | cb(); |
@@ -74,17 +74,17 const sink = <T>(consumer: Partial<Obser | |||
|
74 | 74 | next: next ? next.bind(consumer) : noop, |
|
75 | 75 | error: error ? error.bind(consumer) : noop, |
|
76 | 76 | complete: complete ? complete.bind(consumer) : noop |
|
77 | } | |
|
77 | }; | |
|
78 | 78 | }; |
|
79 | 79 | |
|
80 | 80 | const fuse = <T>({ next, error, complete }: Sink<T>) => { |
|
81 | 81 | let done = false; |
|
82 | 82 | return { |
|
83 | next: (value: T) => { !done && next(value) }, | |
|
84 | error: (e: unknown) => { !done && (done = true, error(e)) }, | |
|
85 | complete: () => { !done && (done = true, complete()) } | |
|
86 | } | |
|
87 | } | |
|
83 | next: (value: T) => { !done && next(value); }, | |
|
84 | error: (e: unknown) => { !done && (done = true, error(e)); }, | |
|
85 | complete: () => { !done && (done = true, complete()); } | |
|
86 | }; | |
|
87 | }; | |
|
88 | 88 | |
|
89 | 89 | const _observe = <T>(producer: Producer<T>): Observable<T> => ({ |
|
90 | 90 | subscribe: (consumer: Partial<Observer<T>>) => ({ |
@@ -12,7 +12,7 import djAttr = require("dojo/dom-attr") | |||
|
12 | 12 | import djClass = require("dojo/dom-class"); |
|
13 | 13 | import { AnimationAttrs, WatchForRendition } from "./tsx/WatchForRendition"; |
|
14 | 14 | |
|
15 |
export function createElement<T extends Constructor | string | ((props: |
|
|
15 | export function createElement<T extends Constructor | string | ((props: object) => Element)>(elementType: T, ...args: unknown[]): Rendition { | |
|
16 | 16 | if (typeof elementType === "string") { |
|
17 | 17 | const ctx = new HtmlRendition(elementType); |
|
18 | 18 | if (args) |
@@ -26,17 +26,17 export function createElement<T extends | |||
|
26 | 26 | |
|
27 | 27 | return ctx; |
|
28 | 28 | } else if (typeof elementType === "function") { |
|
29 |
const ctx = new FunctionRendition(elementType as (props: |
|
|
29 | const ctx = new FunctionRendition(elementType as (props: unknown) => Element); | |
|
30 | 30 | if (args) |
|
31 | 31 | args.forEach(x => ctx.visitNext(x)); |
|
32 | 32 | |
|
33 | 33 | return ctx; |
|
34 | 34 | } else { |
|
35 | throw new Error(`The element type '${elementType}' is unsupported`); | |
|
35 | throw new Error(`The element type '${String(elementType)}' is unsupported`); | |
|
36 | 36 | } |
|
37 | 37 | } |
|
38 | 38 | |
|
39 |
export interface EventDetails<T = |
|
|
39 | export interface EventDetails<T = unknown> { | |
|
40 | 40 | detail: T; |
|
41 | 41 | } |
|
42 | 42 | |
@@ -56,7 +56,7 export interface QueryResultUpdate<T> { | |||
|
56 | 56 | newIndex: number; |
|
57 | 57 | } |
|
58 | 58 | |
|
59 |
export type DojoMouseEvent<T = |
|
|
59 | export type DojoMouseEvent<T = unknown> = MouseEvent & EventSelector & EventDetails<T>; | |
|
60 | 60 | |
|
61 | 61 | type StatefulProps<T> = T extends Stateful<infer A> ? A : |
|
62 | 62 | T extends _WidgetBase ? T : never; |
@@ -73,7 +73,7 type StatefulProps<T> = T extends Statef | |||
|
73 | 73 | export function watch<W extends _WidgetBase, K extends keyof W>( |
|
74 | 74 | target: W, |
|
75 | 75 | prop: K, |
|
76 |
render: (model: W[K]) => |
|
|
76 | render: (model: W[K]) => unknown | |
|
77 | 77 | ): Rendition; |
|
78 | 78 | /** |
|
79 | 79 | * Observers the property and calls render callback each change. |
@@ -86,7 +86,7 export function watch<W extends _WidgetB | |||
|
86 | 86 | export function watch<T extends Stateful, K extends keyof StatefulProps<T>>( |
|
87 | 87 | target: T, |
|
88 | 88 | prop: K, |
|
89 |
render: (model: StatefulProps<T>[K]) => |
|
|
89 | render: (model: StatefulProps<T>[K]) => unknown | |
|
90 | 90 | ): Rendition; |
|
91 | 91 | export function watch<V>(subj: Subscribable<V>, render: (model: V) => unknown): Rendition; |
|
92 | 92 | export function watch( |
@@ -98,7 +98,7 export function watch( | |||
|
98 | 98 | return new WatchRendition( |
|
99 | 99 | render, |
|
100 | 100 | observe(({next}) => { |
|
101 |
const h = target.watch |
|
|
101 | const h = target.watch( | |
|
102 | 102 | prop, |
|
103 | 103 | (_prop, oldValue, newValue) => oldValue !== newValue && next(newValue) |
|
104 | 104 | ); |
@@ -118,7 +118,7 export const watchFor = <T>(source: T[] | |||
|
118 | 118 | subject: source, |
|
119 | 119 | component: render |
|
120 | 120 | }); |
|
121 | } | |
|
121 | }; | |
|
122 | 122 | |
|
123 | 123 | |
|
124 | 124 | export const prop: { |
@@ -132,7 +132,7 export const prop: { | |||
|
132 | 132 | ); |
|
133 | 133 | next(target.get(name)); |
|
134 | 134 | return () => h.remove(); |
|
135 | }) | |
|
135 | }); | |
|
136 | 136 | }; |
|
137 | 137 | |
|
138 | 138 | export const attach = <W extends DjxWidgetBase, K extends keyof W>(target: W, name: K) => (v: W[K]) => target.set(name, v); |
@@ -140,7 +140,7 export const attach = <W extends DjxWidg | |||
|
140 | 140 | export const bind = <K extends string, T>(attr: K, subj: Subscribable<T>) => { |
|
141 | 141 | let h = { unsubscribe() { } }; |
|
142 | 142 | |
|
143 |
return |
|
|
143 | return (el: Element | { set(name: K, value: T): void; } | undefined) => { | |
|
144 | 144 | if (el) { |
|
145 | 145 | if (isElementNode(el)) { |
|
146 | 146 | h = subj.subscribe({ |
@@ -154,7 +154,7 export const bind = <K extends string, T | |||
|
154 | 154 | } else { |
|
155 | 155 | h.unsubscribe(); |
|
156 | 156 | } |
|
157 | } | |
|
157 | }; | |
|
158 | 158 | }; |
|
159 | 159 | |
|
160 | 160 | export const toggleClass = (className: string, subj: Subscribable<boolean>) => { |
@@ -168,8 +168,8 export const toggleClass = (className: s | |||
|
168 | 168 | } else { |
|
169 | 169 | h.unsubscribe(); |
|
170 | 170 | } |
|
171 | } | |
|
172 | } | |
|
171 | }; | |
|
172 | }; | |
|
173 | 173 | |
|
174 | 174 | export const all = <T, A extends JSX.Ref<T>[]>(...cbs: A): JSX.Ref<T> => (arg: T | undefined) => cbs.forEach(cb => cb(arg)); |
|
175 | 175 | |
@@ -185,13 +185,14 export const all = <T, A extends JSX.Ref | |||
|
185 | 185 | */ |
|
186 | 186 | export const on = <E extends string>(...eventNames: E[]) => |
|
187 | 187 | <K extends string, |
|
188 |
T extends DjxWidgetBase< |
|
|
188 | T extends DjxWidgetBase<object, { [p in E]: EV }>, | |
|
189 | 189 | EV extends Event |
|
190 | 190 | >( |
|
191 | 191 | target: T, |
|
192 | 192 | key: K, |
|
193 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
|
193 | 194 | _descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void> |
|
194 |
) |
|
|
195 | ) => { | |
|
195 | 196 | const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key })); |
|
196 | 197 | target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers; |
|
197 | 198 | }; |
@@ -17,7 +17,8 export interface EventArgs { | |||
|
17 | 17 | composed?: boolean; |
|
18 | 18 | } |
|
19 | 19 | |
|
20 | export interface DjxWidgetBase<Attrs = {}, Events extends { [name in keyof Events]: Event } = {}> extends | |
|
20 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
|
21 | export interface DjxWidgetBase<Attrs = object, Events extends { [name in keyof Events]: Event } = object> extends | |
|
21 | 22 | _WidgetBase<Events> { |
|
22 | 23 | |
|
23 | 24 | /** This property is declared only for type inference to work, it is never assigned |
@@ -32,7 +33,7 export interface DjxWidgetBase<Attrs = { | |||
|
32 | 33 | */ |
|
33 | 34 | _eventHandlers: Array<{ |
|
34 | 35 | eventName: string, |
|
35 |
handlerMethod: |
|
|
36 | handlerMethod: string; | |
|
36 | 37 | }>; |
|
37 | 38 | } |
|
38 | 39 | |
@@ -43,7 +44,8 type _super = { | |||
|
43 | 44 | }; |
|
44 | 45 | |
|
45 | 46 | @djclass |
|
46 | export abstract class DjxWidgetBase<Attrs = {}, Events = {}> extends djbase<_super, _AttachMixin>(_WidgetBase, _AttachMixin) { | |
|
47 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
|
48 | export abstract class DjxWidgetBase<Attrs = object, Events = object> extends djbase<_super, _AttachMixin>(_WidgetBase, _AttachMixin) { | |
|
47 | 49 | private readonly _scope = new Scope(); |
|
48 | 50 | |
|
49 | 51 | buildRendering() { |
@@ -68,29 +70,29 export abstract class DjxWidgetBase<Attr | |||
|
68 | 70 | } |
|
69 | 71 | } |
|
70 | 72 | |
|
71 |
abstract render(): Rendition |
|
|
73 | abstract render(): Rendition; | |
|
72 | 74 | |
|
73 | 75 | private _connectEventHandlers() { |
|
74 | 76 | if (this._eventHandlers) |
|
75 | 77 | this._eventHandlers.forEach(({ eventName, handlerMethod }) => { |
|
76 | 78 | const handler = this[handlerMethod as keyof this]; |
|
77 | 79 | if (typeof handler === "function") |
|
78 | on(this.domNode, eventName, handler.bind(this)); | |
|
80 | on(this.domNode, eventName, handler.bind(this) as (...args: unknown[]) => unknown); | |
|
79 | 81 | }); |
|
80 | 82 | } |
|
81 | 83 | |
|
82 | 84 | _processTemplateNode<T extends (Element | Node | _WidgetBase)>( |
|
83 | 85 | baseNode: T, |
|
84 |
getAttrFunc: (baseNode: T, attr: string) => |
|
|
86 | getAttrFunc: (baseNode: T, attr: string) => string, | |
|
85 | 87 | // tslint:disable-next-line: ban-types |
|
86 |
attachFunc: (node: T, type: string, func?: |
|
|
88 | attachFunc: (node: T, type: string, func?: (...args: unknown[]) => unknown) => dojo.Handle | |
|
87 | 89 | ): boolean { |
|
88 | 90 | if (isNode(baseNode)) { |
|
89 | 91 | const w = registry.byNode(baseNode); |
|
90 | 92 | if (w) { |
|
91 | 93 | // from dijit/_WidgetsInTemplateMixin |
|
92 | 94 | this._processTemplateNode(w, |
|
93 |
(n, p) => n.get(p as |
|
|
95 | (n, p) => String(n.get(p as keyof typeof n)), // callback to get a property of a widget | |
|
94 | 96 | (widget, type, callback) => { |
|
95 | 97 | if (!callback) |
|
96 | 98 | throw new Error("The callback must be specified"); |
@@ -101,7 +103,7 export abstract class DjxWidgetBase<Attr | |||
|
101 | 103 | return widget.connect(widget, type, callback as EventListener); |
|
102 | 104 | } else { |
|
103 | 105 | // 1.x may never hit this branch, but it's the default for 2.0 |
|
104 | return widget.on(type, callback); | |
|
106 | return widget.on(type as keyof GlobalEventHandlersEventMap, callback); | |
|
105 | 107 | } |
|
106 | 108 | |
|
107 | 109 | }); |
@@ -109,7 +111,8 export abstract class DjxWidgetBase<Attr | |||
|
109 | 111 | return false; |
|
110 | 112 | } |
|
111 | 113 | } |
|
112 | return super._processTemplateNode(baseNode, getAttrFunc, attachFunc); | |
|
114 | // eslint-disable-next-line @typescript-eslint/ban-types | |
|
115 | return super._processTemplateNode(baseNode, getAttrFunc, attachFunc as (node: T, type: string, func?: Function) => dojo.Handle); | |
|
113 | 116 | } |
|
114 | 117 | |
|
115 | 118 | /** Starts current widget and all its supporting widgets (placed outside |
@@ -3,19 +3,19 import { getItemDom } from "./render"; | |||
|
3 | 3 | import { RenditionBase } from "./RenditionBase"; |
|
4 | 4 | |
|
5 | 5 | export class FunctionRendition extends RenditionBase<Node> { |
|
6 |
private _component: (...args: |
|
|
6 | private readonly _component: (...args: unknown[]) => unknown; | |
|
7 | 7 | |
|
8 | 8 | private _node: Node | undefined; |
|
9 | 9 | |
|
10 |
constructor(component: (...args: |
|
|
10 | constructor(component: (...args: unknown[]) => unknown) { | |
|
11 | 11 | super(); |
|
12 | 12 | argumentNotNull(component, "component"); |
|
13 | 13 | |
|
14 | 14 | this._component = component; |
|
15 | 15 | } |
|
16 | 16 | |
|
17 |
protected _create(attrs: object, children: |
|
|
18 |
const _attrs |
|
|
17 | protected _create(attrs: object, children: unknown[]) { | |
|
18 | const _attrs = attrs || {}; | |
|
19 | 19 | const _children = children.map(x => getItemDom(x)); |
|
20 | 20 | this._node = getItemDom( |
|
21 | 21 | this._component.call(null, { ..._attrs, children: _children })); |
@@ -3,11 +3,11 import { isPlainObject, DojoNodePosition | |||
|
3 | 3 | export abstract class RenditionBase<TNode extends Node> implements Rendition<TNode> { |
|
4 | 4 | private _attrs = {}; |
|
5 | 5 | |
|
6 |
private _children = |
|
|
6 | private _children: unknown[] = []; | |
|
7 | 7 | |
|
8 |
private _created |
|
|
8 | private _created = false; | |
|
9 | 9 | |
|
10 |
visitNext(v: |
|
|
10 | visitNext(v: unknown) { | |
|
11 | 11 | if (this._created) |
|
12 | 12 | throw new Error("The Element is already created"); |
|
13 | 13 |
@@ -30,7 +30,7 export class Scope implements IDestroyab | |||
|
30 | 30 | } catch { |
|
31 | 31 | // guard |
|
32 | 32 | } |
|
33 | } | |
|
33 | }; | |
|
34 | 34 | |
|
35 | 35 | this._cleanup.forEach(guard); |
|
36 | 36 | this._cleanup.length = 0; |
@@ -49,8 +49,8 export interface WatchForRenditionAttrs< | |||
|
49 | 49 | component: (arg: T, index: number) => unknown; |
|
50 | 50 | } |
|
51 | 51 | |
|
52 |
const isObservable = <T>(v: |
|
|
53 |
v && (typeof (v as |
|
|
52 | const isObservable = <T>(v: ArrayLike<T>): v is ArrayLike<T> & ObservableResults<T> => | |
|
53 | v && (typeof (v as { observe?: unknown; }).observe === "function"); | |
|
54 | 54 | |
|
55 | 55 | const noop = () => {}; |
|
56 | 56 | |
@@ -127,7 +127,7 export class WatchForRendition<T> extend | |||
|
127 | 127 | this._ct = new Cancellation(cancel => scope.own(cancel)); |
|
128 | 128 | } |
|
129 | 129 | |
|
130 | private _onItemUpdated = (item: RenderTask<T>) => { | |
|
130 | private readonly _onItemUpdated = (item: RenderTask<T>) => { | |
|
131 | 131 | if (!this._renderTasks.length) { |
|
132 | 132 | // schedule a new job |
|
133 | 133 | this._renderTasks.push(item); |
@@ -136,7 +136,7 export class WatchForRendition<T> extend | |||
|
136 | 136 | // update existing job |
|
137 | 137 | this._renderTasks.push(item); |
|
138 | 138 | } |
|
139 | } | |
|
139 | }; | |
|
140 | 140 | |
|
141 | 141 | private async _render() { |
|
142 | 142 | // fork |
@@ -149,7 +149,7 export class WatchForRendition<T> extend | |||
|
149 | 149 | this._renderTasks.length = 0; |
|
150 | 150 | } |
|
151 | 151 | |
|
152 | _onRenderItem = ({ item, newIndex, prevIndex, animate: _animate }: RenderTask<T>) => { | |
|
152 | private readonly _onRenderItem = ({ item, newIndex, prevIndex, animate: _animate }: RenderTask<T>) => { | |
|
153 | 153 | const animate = _animate && prevIndex !== newIndex; |
|
154 | 154 | |
|
155 | 155 | if (prevIndex > -1) { |
@@ -205,7 +205,7 export class WatchForRendition<T> extend | |||
|
205 | 205 | if (animate) |
|
206 | 206 | this._animateIn(nodes).catch(e => trace.error(e)); |
|
207 | 207 | } |
|
208 | } | |
|
208 | }; | |
|
209 | 209 | |
|
210 | 210 | protected _getDomNode() { |
|
211 | 211 | if (!this._node) |
@@ -17,7 +17,7 export interface _Widget { | |||
|
17 | 17 | addChild?(widget: unknown, index?: number): void; |
|
18 | 18 | } |
|
19 | 19 | |
|
20 |
export type _WidgetCtor = new (attrs: |
|
|
20 | export type _WidgetCtor = new (attrs: object, srcNode?: string | Node) => _Widget; | |
|
21 | 21 | |
|
22 | 22 | export class WidgetRendition extends RenditionBase<Node> { |
|
23 | 23 | readonly widgetClass: _WidgetCtor; |
@@ -14,11 +14,11 interface Context { | |||
|
14 | 14 | |
|
15 | 15 | let _context: Context = { |
|
16 | 16 | scope: Scope.dummy |
|
17 | } | |
|
17 | }; | |
|
18 | 18 | |
|
19 | 19 | const guard = (cb: () => unknown) => { |
|
20 | 20 | try { |
|
21 | const result = cb() | |
|
21 | const result = cb(); | |
|
22 | 22 | if (isPromise(result)) { |
|
23 | 23 | const warn = (ret: unknown) => trace.error("The callback {0} competed asynchronously. result = {1}", cb, ret); |
|
24 | 24 | result.then(warn, warn); |
@@ -26,7 +26,7 const guard = (cb: () => unknown) => { | |||
|
26 | 26 | } catch (e) { |
|
27 | 27 | trace.error(e); |
|
28 | 28 | } |
|
29 | } | |
|
29 | }; | |
|
30 | 30 | |
|
31 | 31 | export const beginRender = (scope: IScope = getScope()) => { |
|
32 | 32 | const prev = _context; |
@@ -35,7 +35,7 export const beginRender = (scope: IScop | |||
|
35 | 35 | hooks: [] |
|
36 | 36 | }; |
|
37 | 37 | return endRender(prev); |
|
38 | } | |
|
38 | }; | |
|
39 | 39 | |
|
40 | 40 |
|
|
41 | 41 | * Completes render operation |
@@ -46,7 +46,7 const endRender = (prev: Context) => () | |||
|
46 | 46 | hooks.forEach(guard); |
|
47 | 47 | |
|
48 | 48 | _context = prev; |
|
49 | } | |
|
49 | }; | |
|
50 | 50 | |
|
51 | 51 | export const renderHook = (hook: () => void) => { |
|
52 | 52 | const { hooks } = _context; |
@@ -54,7 +54,7 export const renderHook = (hook: () => v | |||
|
54 | 54 | hooks.push(hook); |
|
55 | 55 | else |
|
56 | 56 | guard(hook); |
|
57 | } | |
|
57 | }; | |
|
58 | 58 | |
|
59 | 59 | export const refHook = <T>(value: T, ref: JSX.Ref<T>) => { |
|
60 | 60 | const { hooks, scope } = _context; |
@@ -64,7 +64,7 export const refHook = <T>(value: T, ref | |||
|
64 | 64 | guard(() => ref(value)); |
|
65 | 65 | |
|
66 | 66 | scope.own(() => ref(undefined)); |
|
67 | } | |
|
67 | }; | |
|
68 | 68 | |
|
69 | 69 |
|
|
70 | 70 | export const getScope = () => _context.scope; |
@@ -80,7 +80,7 export const render = (rendition: unknow | |||
|
80 | 80 | } finally { |
|
81 | 81 | complete(); |
|
82 | 82 | } |
|
83 | } | |
|
83 | }; | |
|
84 | 84 | |
|
85 | 85 |
|
|
86 | 86 | export const getItemDom = (v: unknown) => { |
@@ -107,6 +107,6 export const getItemDom = (v: unknown) = | |||
|
107 | 107 | return fragment; |
|
108 | 108 | } else { |
|
109 | 109 | // bug: explicit error otherwise |
|
110 |
throw new Error( |
|
|
110 | throw new Error(`Invalid parameter: ${String(v)}`); | |
|
111 | 111 | } |
|
112 | } | |
|
112 | }; |
@@ -1,31 +1,38 | |||
|
1 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference | |
|
1 | 2 | /// <reference path="./css-plugin.d.ts"/> |
|
2 | 3 | |
|
3 | declare namespace JSX { | |
|
4 | import { Rendition } from "./tsx/traits"; | |
|
5 | ||
|
6 | declare global { | |
|
7 | namespace JSX { | |
|
4 | 8 | |
|
5 | 9 | type Ref<T> = ((value: T | undefined) => void); |
|
6 | 10 | |
|
11 | type Element = Rendition; | |
|
12 | ||
|
7 | 13 | interface DjxIntrinsicAttributes<E> { |
|
8 | 14 | /** alias for className */ |
|
9 | class: string; | |
|
15 | class?: string; | |
|
10 | 16 | |
|
11 | 17 | /** specifies the name of the property in the widget where the the |
|
12 | 18 | * reference to the current object will be stored |
|
13 | 19 | */ |
|
14 | "data-dojo-attach-point": string; | |
|
20 | "data-dojo-attach-point"?: string; | |
|
15 | 21 | |
|
16 | 22 | /** specifies handlers map for the events */ |
|
17 | "data-dojo-attach-event": string; | |
|
23 | "data-dojo-attach-event"?: string; | |
|
18 | 24 | |
|
19 | ref: Ref<E>; | |
|
25 | ref?: Ref<E>; | |
|
20 | 26 | |
|
21 | 27 | /** @deprecated */ |
|
22 |
[attr: string]: |
|
|
28 | [attr: string]: unknown; | |
|
23 | 29 | } |
|
24 | 30 | |
|
31 | // eslint-disable-next-line @typescript-eslint/no-empty-interface | |
|
25 | 32 | interface DjxIntrinsicElements { |
|
26 | 33 | } |
|
27 | 34 | |
|
28 |
type RecursivePartial<T> = T extends string | number | boolean | null | undefined | |
|
|
35 | type RecursivePartial<T> = T extends string | number | boolean | null | undefined | ((...args: unknown[]) => unknown) ? | |
|
29 | 36 | T : |
|
30 | 37 | { [k in keyof T]?: RecursivePartial<T[k]> }; |
|
31 | 38 | |
@@ -40,9 +47,9 declare namespace JSX { | |||
|
40 | 47 | |
|
41 | 48 | type ExcludeMembers<T, U> = Pick<T, NotMatchingMemberKeys<T, U>>; |
|
42 | 49 | |
|
43 |
type ElementAttrNames<E> = NotMatchingMemberKeys<E, (...args: |
|
|
50 | type ElementAttrNames<E> = NotMatchingMemberKeys<E, (...args: unknown[]) => unknown>; | |
|
44 | 51 | |
|
45 |
type ElementAttrType<E, K extends |
|
|
52 | type ElementAttrType<E, K extends string | symbol> = K extends keyof E ? RecursivePartial<E[K]> : string; | |
|
46 | 53 | |
|
47 | 54 | |
|
48 | 55 | type ElementAttrNamesBlacklist = "children" | "getRootNode" | keyof EventTarget; |
@@ -53,13 +60,13 declare namespace JSX { | |||
|
53 | 60 | */ |
|
54 | 61 | type AssignableElementAttrNames<E> = { |
|
55 | 62 | [K in keyof E]: K extends ElementAttrNamesBlacklist ? never : |
|
56 |
((evt: Event) => |
|
|
57 |
E[K] extends ((...args: |
|
|
63 | ((evt: Event) => unknown) extends E[K] ? K : | |
|
64 | E[K] extends ((...args: unknown[]) => unknown) ? never : | |
|
58 | 65 | K; |
|
59 | 66 | }[keyof E]; |
|
60 | 67 | |
|
61 | 68 | type LaxElement<E extends object> = |
|
62 | Pick<E, AssignableElementAttrNames<E>> & | |
|
69 | RecursivePartial<Pick<E, AssignableElementAttrNames<E>>> & | |
|
63 | 70 | DjxIntrinsicAttributes<E>; |
|
64 | 71 | |
|
65 | 72 | type LaxIntrinsicElementsMap = { |
@@ -67,15 +74,16 declare namespace JSX { | |||
|
67 | 74 | } & DjxIntrinsicElements; |
|
68 | 75 | |
|
69 | 76 | type IntrinsicElements = { |
|
70 |
[tag in keyof LaxIntrinsicElementsMap]: |
|
|
71 | } | |
|
77 | [tag in keyof LaxIntrinsicElementsMap]: LaxIntrinsicElementsMap[tag]; | |
|
78 | }; | |
|
72 | 79 | |
|
73 | 80 | interface ElementChildrenAttribute { |
|
74 |
children: |
|
|
81 | children: unknown; | |
|
75 | 82 | } |
|
76 | 83 | |
|
77 | 84 | interface IntrinsicClassAttributes<T> { |
|
78 |
ref? |
|
|
85 | ref?: Ref<T>; | |
|
79 | 86 | children?: unknown; |
|
80 | 87 | } |
|
81 | 88 | } |
|
89 | } No newline at end of file |
@@ -2,6 +2,7 import { djbase, djclass, bind, prototyp | |||
|
2 | 2 | |
|
3 | 3 | import { DjxWidgetBase } from "../tsx/DjxWidgetBase"; |
|
4 | 4 | import { createElement, on } from "../tsx"; |
|
5 | import { argumentNotNull } from "@implab/core-amd/safe"; | |
|
5 | 6 | |
|
6 | 7 | interface MyWidgetAttrs { |
|
7 | 8 | title: string; |
@@ -19,6 +20,12 interface MyWidgetEvents { | |||
|
19 | 20 | }; |
|
20 | 21 | } |
|
21 | 22 | |
|
23 | interface FrameProps { | |
|
24 | ref?: JSX.Ref<HTMLDivElement>; | |
|
25 | children?: unknown[]; | |
|
26 | } | |
|
27 | ||
|
28 | const Frame = ({children, ref}: FrameProps) => <div ref={ref} >{children}</div>; | |
|
22 | 29 | |
|
23 | 30 | @djclass |
|
24 | 31 | export class MyWidget extends djbase(DjxWidgetBase as AbstractConstructor<DjxWidgetBase<MyWidgetAttrs, MyWidgetEvents>>) { |
@@ -29,31 +36,40 export class MyWidget extends djbase(Djx | |||
|
29 | 36 | @prototype(0) |
|
30 | 37 | counter = 0; |
|
31 | 38 | |
|
39 | frameNode?: HTMLDivElement; | |
|
40 | ||
|
32 | 41 | render() { |
|
33 | const Frame = ({children, ref}: {ref: JSX.Ref<HTMLDivElement>, children: unknown[]}) => <div ref={ref} >{children}</div>; | |
|
34 |
|
|
|
42 | ||
|
43 | return <div className="myWidget" onsubmit={this._onSubmit} tabIndex={3} style={{ alignContent: "center", border: "1px solid" }} > | |
|
35 | 44 | <h1 data-dojo-attach-point="titleNode"></h1> |
|
36 |
<Frame ref={ |
|
|
37 |
<span class="up-button" onclick={ |
|
|
45 | <Frame ref={this._setFrameElement}> | |
|
46 | <span class="up-button" onclick={this._onIncClick}>[+]</span> | |
|
38 | 47 | <span class="down-button" onclick={() => this._onDecClick()}>[-]</span> |
|
39 | 48 | </Frame> |
|
40 | 49 | </div>; |
|
41 | 50 | } |
|
42 | 51 | |
|
52 | private readonly _setFrameElement = (node?: HTMLDivElement) => { | |
|
53 | this.frameNode = node; | |
|
54 | }; | |
|
55 | ||
|
43 | 56 | postCreate() { |
|
44 | 57 | super.postCreate(); |
|
45 | 58 | |
|
46 | 59 | this.on("click", () => {}); |
|
47 | 60 | } |
|
48 | 61 | |
|
49 | _onSubmit(e: Event) { | |
|
50 | } | |
|
62 | private readonly _onSubmit = (evt: Event) => { | |
|
63 | argumentNotNull(evt, "evt"); | |
|
64 | }; | |
|
51 | 65 | |
|
52 | _onIncClick(e: MouseEvent) { | |
|
66 | private readonly _onIncClick = (evt: MouseEvent) => { | |
|
67 | argumentNotNull(evt, "evt"); | |
|
68 | ||
|
53 | 69 | this.set("counter", this.counter + 1); |
|
54 | 70 | |
|
55 | 71 | this.emit("count-inc", { bubbles: false }); |
|
56 | } | |
|
72 | }; | |
|
57 | 73 | |
|
58 | 74 | _onDecClick() { |
|
59 | 75 | this.emit("count-dec", { bubbles: false, detail: this.counter }); |
@@ -61,10 +77,11 export class MyWidget extends djbase(Djx | |||
|
61 | 77 | |
|
62 | 78 | @on("count-inc") |
|
63 | 79 | private _onCounterInc(evt: Event & { detail: number; x?: number; }) { |
|
80 | argumentNotNull(evt, "evt"); | |
|
64 | 81 | } |
|
65 | 82 | |
|
66 | 83 | @on("click", "keydown") |
|
67 |
protected _onClick(ev |
|
|
68 | ||
|
84 | protected _onClick(evt: MouseEvent | KeyboardEvent) { | |
|
85 | argumentNotNull(evt, "evt"); | |
|
69 | 86 | } |
|
70 | 87 | } No newline at end of file |
@@ -1,6 +1,7 | |||
|
1 | 1 | { |
|
2 | 2 | "extends": "../tsconfig", |
|
3 | 3 | "compilerOptions": { |
|
4 | "baseUrl": ".", | |
|
4 | 5 | "noUnusedLocals": false, |
|
5 | 6 | //"rootDir": "ts", |
|
6 | 7 | "rootDirs": [ |
@@ -9,6 +10,11 | |||
|
9 | 10 | "../main/ts", |
|
10 | 11 | "../main/typings" |
|
11 | 12 | ], |
|
12 | "types": ["requirejs", "../main/typings", "@implab/dojo-typings"] | |
|
13 | "types": [ | |
|
14 | "requirejs", | |
|
15 | "../main/typings", | |
|
16 | "@implab/dojo-typings", | |
|
17 | "@implab/dojo-typings/dojo/NodeList-fx" | |
|
18 | ] | |
|
13 | 19 | } |
|
14 | 20 | } No newline at end of file |
@@ -1,10 +1,9 | |||
|
1 | 1 | { |
|
2 | "extends": "./tsconfig.json", | |
|
2 | //"extends": "./tsconfig.json", | |
|
3 | 3 | "compilerOptions": { |
|
4 | 4 | // ensure that nobody can accidentally use this config for a build |
|
5 | "noEmit": true | |
|
5 | "noEmit": true, | |
|
6 | 6 | }, |
|
7 | 7 | "include": [ |
|
8 | "ts" | |
|
9 | 8 | ] |
|
10 | 9 | } No newline at end of file |
@@ -1,7 +1,7 | |||
|
1 | 1 | import MainWidget from "./view/MainWidget"; |
|
2 | import "@implab/djx/css!dojo/resources/dojo.css" | |
|
3 | import "@implab/djx/css!dijit/themes/dijit.css" | |
|
4 | import "@implab/djx/css!dijit/themes/tundra/tundra.css" | |
|
2 | import "@implab/djx/css!dojo/resources/dojo.css"; | |
|
3 | import "@implab/djx/css!dijit/themes/dijit.css"; | |
|
4 | import "@implab/djx/css!dijit/themes/tundra/tundra.css"; | |
|
5 | 5 | |
|
6 | 6 | const w = new MainWidget(); |
|
7 | 7 | w.placeAt(document.body); No newline at end of file |
@@ -5,6 +5,7 import { Contact } from "./Contact"; | |||
|
5 | 5 | import { Uuid } from "@implab/core-amd/Uuid"; |
|
6 | 6 | import { Observable as RxjsObservable } from "rxjs"; |
|
7 | 7 | import { QueryResultUpdate } from "@implab/djx/tsx"; |
|
8 | import {isPromise} from "@implab/core-amd/safe"; | |
|
8 | 9 | |
|
9 | 10 | type AppointmentRecord = Omit<Appointment, "getMembers"> & {id: string}; |
|
10 | 11 | |
@@ -22,13 +23,13 export interface ObservableResults<T> { | |||
|
22 | 23 | } |
|
23 | 24 | |
|
24 | 25 | |
|
25 |
export function isObservable<T>(v: |
|
|
26 |
return v && (typeof (v as |
|
|
26 | export function isObservable<T>(v: unknown): v is ObservableResults<T> { | |
|
27 | return !!v && (typeof (v as {observe?: unknown}).observe === "function"); | |
|
27 | 28 | } |
|
28 | 29 | |
|
29 | 30 | export function observe<T>(results: T[], includeObjectUpdates?: boolean): RxjsObservable<QueryResultUpdate<T>>; |
|
30 | 31 | export function observe<T>(results: PromiseLike<T[]>, includeObjectUpdates?: boolean): PromiseLike<RxjsObservable<QueryResultUpdate<T>>>; |
|
31 |
export function observe(results: |
|
|
32 | export function observe(results: unknown[] | PromiseLike<unknown[]>, includeObjectUpdates = true) { | |
|
32 | 33 | // results может быть асинхронным, т.е. до завершения |
|
33 | 34 | // получения результатов store может быть обновлен. В любом |
|
34 | 35 | // случае, если между подключением хотя бы одного наблюдателя |
@@ -41,7 +42,7 export function observe(results: any, in | |||
|
41 | 42 | // о необработанной ошибке в Promise при обращении к методам |
|
42 | 43 | // обновления (add,put,remove) |
|
43 | 44 | |
|
44 |
const _subscribe = (items: |
|
|
45 | const _subscribe = (items: unknown[]) => new RxjsObservable<QueryResultUpdate<unknown>>(subscriber => { | |
|
45 | 46 | items |
|
46 | 47 | .forEach((value, newIndex) => subscriber.next({ item: value, newIndex, prevIndex: -1})); |
|
47 | 48 | |
@@ -72,11 +73,11 export function observe(results: any, in | |||
|
72 | 73 | |
|
73 | 74 | |
|
74 | 75 | export class MainContext { |
|
75 | private _appointments = new Observable(new Memory<AppointmentRecord>()); | |
|
76 | private readonly _appointments = new Observable(new Memory<AppointmentRecord>()); | |
|
76 | 77 | |
|
77 | private _contacts = new Observable(new Memory<ContactRecord>()); | |
|
78 | private readonly _contacts = new Observable(new Memory<ContactRecord>()); | |
|
78 | 79 | |
|
79 | private _members = new Observable(new Memory<MemberRecord>()); | |
|
80 | private readonly _members = new Observable(new Memory<MemberRecord>()); | |
|
80 | 81 | |
|
81 | 82 | createAppointment(title: string, startAt: Date, duration: number, members: Member[]) { |
|
82 | 83 | const id = Uuid(); |
@@ -91,16 +92,16 export class MainContext { | |||
|
91 | 92 | this._members.add({ |
|
92 | 93 | appointmentId: id, |
|
93 | 94 | ...member |
|
94 | }, {id: Uuid()}) | |
|
95 | }, {id: Uuid()}) as void | |
|
95 | 96 | ); |
|
96 | 97 | } |
|
97 | 98 | |
|
98 | 99 | queryAppointments(dateFrom: Date, dateTo: Date) { |
|
99 | this._appointments.query().map() | |
|
100 | //this._appointments.query().map() | |
|
100 | 101 | } |
|
101 | 102 | |
|
102 | private _mapAppointment = ({startAt, title, duration, id}: AppointmentRecord) => ({ | |
|
103 | private readonly _mapAppointment = ({startAt, title, duration, id}: AppointmentRecord) => ({ | |
|
103 | 104 | |
|
104 | }) | |
|
105 | }); | |
|
105 | 106 | |
|
106 | 107 | } |
@@ -5,6 +5,8 import ProgressBar from "./ProgressBar"; | |||
|
5 | 5 | import Button = require("dijit/form/Button"); |
|
6 | 6 | import { interval } from "rxjs"; |
|
7 | 7 | |
|
8 | const Counter = ({ children }: { children: unknown[] }) => <span>Counter: {children}</span>; | |
|
9 | ||
|
8 | 10 | @djclass |
|
9 | 11 | export default class MainWidget extends djbase(DjxWidgetBase) { |
|
10 | 12 | |
@@ -21,7 +23,6 export default class MainWidget extends | |||
|
21 | 23 | paused = false; |
|
22 | 24 | |
|
23 | 25 | render() { |
|
24 | const Counter = ({ children }: { children: unknown[] }) => <span>Counter: {children}</span>; | |
|
25 | 26 |
|
|
26 | 27 | return <div className="tundra"> |
|
27 | 28 | <h2 ref={attach(this, "titleNode")}>Hi!</h2> |
@@ -31,7 +32,6 export default class MainWidget extends | |||
|
31 | 32 | <Counter><input ref={all( |
|
32 | 33 | bind("value", prop(this, "count") |
|
33 | 34 | .map(x => x/10) |
|
34 | .map(String) | |
|
35 | 35 | ), |
|
36 | 36 | attach(this, "counterNode") |
|
37 | 37 | )} /> <span>s</span></Counter>, |
@@ -71,11 +71,11 export default class MainWidget extends | |||
|
71 | 71 | }); |
|
72 | 72 | } |
|
73 | 73 | |
|
74 | private _onPauseClick = () => { | |
|
74 | private readonly _onPauseClick = () => { | |
|
75 | 75 | this.set("paused", !this.paused); |
|
76 | } | |
|
76 | }; | |
|
77 | 77 | |
|
78 | private _onToggleCounterClick = () => { | |
|
78 | private readonly _onToggleCounterClick = () => { | |
|
79 | 79 | this.set("showCounter", !this.showCounter); |
|
80 | }; | |
|
80 | 81 | } |
|
81 | } |
@@ -0,0 +1,1 | |||
|
1 | /* noop */ No newline at end of file |
@@ -5,6 +5,5 | |||
|
5 | 5 | "noEmit": true |
|
6 | 6 | }, |
|
7 | 7 | "include": [ |
|
8 | "ts" | |
|
9 | 8 | ] |
|
10 | 9 | } No newline at end of file |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now