##// END OF EJS Templates
type fixes for i18n, store
cin -
r120:bc1b4dd8ca1a v1.6.2 default
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,8
1 import { bundle } from "../i18n";
2
3 export const { i18n, load, define } = bundle({
4 foo: "foo",
5 bar: "bar"
6 }, {
7 ru: () => import("./ru/nls-test")
8 }); No newline at end of file
@@ -0,0 +1,5
1 import { define } from "../nls-test";
2
3 export default define({
4 foo: "Фу"
5 }); No newline at end of file
@@ -1,60 +1,60
1 1 import { MapOf, PromiseOrValue } from "@implab/core-amd/interfaces";
2 2 import { argumentNotEmptyString, isPromise, mixin } from "@implab/core-amd/safe";
3 3
4 export type LocaleProvider<T> = () => PromiseOrValue<T | { default: T }>;
4 export type LocaleProvider<T> = () => PromiseOrValue<T | {default: T}>;
5 5
6 6 function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> {
7 7 return isPromise(value) ?
8 8 value.then(cb) :
9 9 cb(value);
10 10 }
11 11
12 12 const loadPackage = <T extends object>(localeData: LocaleProvider<Partial<T>> | undefined) =>
13 13 localeData ?
14 14 when(localeData(), data => data && "default" in data ? data.default : data) :
15 15 undefined;
16 16
17 17 const chainObjects = <T extends object>(o1: T, o2: Partial<T> | undefined): T =>
18 18 o2 ? mixin(Object.create(o1) as T, o2) : o1;
19 19
20 20 export class NlsBundle<T extends object> {
21 21 private readonly _locales: MapOf<LocaleProvider<Partial<T>>>;
22 22
23 23 private readonly _default: T;
24 24
25 25 private _cache: MapOf<PromiseOrValue<T>>;
26 26
27 27 constructor(defNls: T, locales?: MapOf<LocaleProvider<Partial<T>>>) {
28 28 this._default = defNls;
29 29 this._locales = locales || {};
30 30 this._cache = {};
31 31 }
32 32
33 33 getLocale(locale: string) {
34 34 argumentNotEmptyString(locale, "locale");
35 35 const _loc = locale;
36 36
37 37 // en-US => ["en", "en-US"]
38 38 const locales = _loc.split(/-|_/).map((x, i, a) => a.slice(0, i + 1).join("-"));
39 39 return this._resolveLocale(locales);
40 40 }
41 41
42 42 _resolveLocale(locales: string[]): PromiseOrValue<T> {
43 43 if (!locales.length)
44 44 return this._default;
45 45
46 46 const locale = locales.pop();
47 47 if (!locale)
48 48 throw new Error("The locale can't be empty");
49 49
50 50 if (this._cache[locale])
51 51 return this._cache[locale];
52 52
53 53 const data = loadPackage(this._locales[locale]);
54 54 const parent = this._resolveLocale(locales);
55 55
56 56 return this._cache[locale] = when(data, x => {
57 57 return when(parent, y => this._cache[locale] = chainObjects(y, x));
58 58 });
59 59 }
60 60 }
@@ -1,51 +1,56
1 1 import { id as mid} from "module";
2 import { MapOf } from "@implab/core-amd/interfaces";
3 import { LocaleProvider, NlsBundle } from "./NlsBundle";
2 import { PromiseOrValue } from "@implab/core-amd/interfaces";
3 import { 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";
7 7
8 8 const trace = TraceSource.get(mid);
9 9
10 10 trace.debug("Current sysLocale: {0}", sysLocale);
11 11
12 12 export interface OnLoad {
13 13 (result?: unknown): void;
14 14 error(err: unknown): void;
15 15 }
16 16
17 export function bundle<T extends object>(nls: T, locales?: MapOf<LocaleProvider<object>>) {
17 export const bundle = <T extends object>(nls: T, locales?: Record<string, () => PromiseOrValue<object>>) : {
18 i18n: (locale?: string) => T;
19 define: (pack: Partial<T>) => object;
20 load: (id: string, require: Require, cb: OnLoad, config: {isBuild?: boolean}) => void;
21 } => {
18 22 const nlsBundle = new NlsBundle(nls, locales);
19 23
20 24 const fn = (_locale?: string) => {
21 25 const locale = _locale || sysLocale;
22 26 const result = nlsBundle.getLocale(locale);
23 27
24 28 if (isPromise(result))
25 29 throw new Error(`The bundle '${locale}' isn't loaded`);
26 30 else
27 31 return result;
28 32 };
29 33
30 fn.define = (pack: Partial<T>) => pack;
34 fn.i18n = fn;
35 fn.define = (pack: Partial<T>): object => pack;
31 36 fn.load = async (id: string, require: Require, cb: OnLoad, config: {isBuild?: boolean}) => {
32 37 const locale = id || sysLocale;
33 38 if (config && config.isBuild) {
34 39 cb();
35 40 } else {
36 41 try {
37 42 await nlsBundle.getLocale(locale);
38 43 cb();
39 44 } catch (e) {
40 45 if(cb.error) {
41 46 cb.error(e);
42 47 } else {
43 48 // in case the loader doesn't support error reporting
44 49 trace.error("Error loading {0}: {1}", locale, e);
45 50 }
46 51 }
47 52 }
48 53 };
49 54
50 55 return fn;
51 }
56 };
@@ -1,58 +1,58
1 1 import { PromiseOrValue } from "@implab/core-amd/interfaces";
2 2 import { isPromise } from "@implab/core-amd/safe";
3 3 import { observe, Observable } from "./observable";
4 4
5 5 export interface OrderedUpdate<T> {
6 6 /** The item is being updated */
7 7 readonly item: T;
8 8
9 9 /** The previous index of the item, -1 in case it is inserted */
10 10 readonly prevIndex: number;
11 11
12 12 /** The new index of the item, -1 in case it is deleted */
13 13 readonly newIndex: number;
14 14
15 15 }
16 16
17 17 export type QueryResults<T> = Observable<OrderedUpdate<T>>;
18 18
19 19 interface DjObservableResults<T> {
20 20 /**
21 21 * Allows observation of results
22 22 */
23 23 observe(listener: (object: T, previousIndex: number, newIndex: number) => void, includeUpdates?: boolean): {
24 24 remove(): void;
25 25 };
26 26 }
27 27
28 28 interface Queryable<T, Q, O> {
29 29 query(query?: Q, options?: O): PromiseOrValue<T[]>;
30 30 }
31 31
32 32 export const isDjObservableResults = <T>(v: object): v is DjObservableResults<T> =>
33 33 v && (typeof (v as { observe?: unknown; }).observe === "function");
34 34
35 35 export const query = <T, Q, O>(store: Queryable<T, Q, O>, includeUpdates = true) =>
36 (query?: Q, options?: O & { observe: boolean }) => {
36 (query?: Q, options?: O & { observe?: boolean }) => {
37 37 return observe<OrderedUpdate<T>>(({ next, complete, error, isClosed }) => {
38 38 try {
39 39 const results = store.query(query, options);
40 40 if (isPromise(results)) {
41 41 results.then(items => items.forEach((item, newIndex) => next({ item, newIndex, prevIndex: -1 })))
42 42 .then(undefined, error);
43 43 } else {
44 44 results.forEach((item, newIndex) => next({ item, newIndex, prevIndex: -1 }));
45 45 }
46 46
47 47 if (!isClosed() && (options?.observe !== false) && isDjObservableResults<T>(results)) {
48 48 const h = results.observe((item, prevIndex, newIndex) => next({ item, prevIndex, newIndex }), includeUpdates);
49 49 return () => h.remove();
50 50 } else {
51 51 complete();
52 52 }
53 53 } catch (err) {
54 54 error(err);
55 55 }
56 56 });
57 57
58 58 };
@@ -1,188 +1,196
1 1 import { Constructor } from "@implab/core-amd/interfaces";
2 2 import { HtmlRendition } from "./tsx/HtmlRendition";
3 3 import { WidgetRendition } from "./tsx/WidgetRendition";
4 4 import { isElementNode, isWidget, isWidgetConstructor, Rendition } from "./tsx/traits";
5 5 import { FunctionRendition } from "./tsx/FunctionRendition";
6 6 import Stateful = require("dojo/Stateful");
7 7 import _WidgetBase = require("dijit/_WidgetBase");
8 8 import { DjxWidgetBase } from "./tsx/DjxWidgetBase";
9 9 import { WatchRendition } from "./tsx/WatchRendition";
10 10 import { Observable, observe, Subscribable } from "./observable";
11 11 import djAttr = require("dojo/dom-attr");
12 12 import djClass = require("dojo/dom-class");
13 13 import { AnimationAttrs, WatchForRendition } from "./tsx/WatchForRendition";
14 14 import { OrderedUpdate } from "./store";
15 15
16 16 export function createElement<T extends Constructor | string | ((props: object) => Element)>(elementType: T, ...args: unknown[]): Rendition {
17 17 if (typeof elementType === "string") {
18 18 const ctx = new HtmlRendition(elementType);
19 19 if (args)
20 20 args.forEach(x => ctx.visitNext(x));
21 21
22 22 return ctx;
23 23 } else if (isWidgetConstructor(elementType)) {
24 24 const ctx = new WidgetRendition(elementType);
25 25 if (args)
26 26 args.forEach(x => ctx.visitNext(x));
27 27
28 28 return ctx;
29 29 } else if (typeof elementType === "function") {
30 30 const ctx = new FunctionRendition(elementType as (props: unknown) => Element);
31 31 if (args)
32 32 args.forEach(x => ctx.visitNext(x));
33 33
34 34 return ctx;
35 35 } else {
36 36 throw new Error(`The element type '${String(elementType)}' is unsupported`);
37 37 }
38 38 }
39 39
40 40 export interface EventDetails<T = unknown> {
41 41 detail: T;
42 42 }
43 43
44 44 export interface EventSelector {
45 45 selectorTarget: HTMLElement;
46 46 target: HTMLElement;
47 47 }
48 48
49 49 export type DojoMouseEvent<T = unknown> = MouseEvent & EventSelector & EventDetails<T>;
50 50
51 51 type StatefulProps<T> = T extends Stateful<infer A> ? A :
52 52 T extends _WidgetBase ? T : never;
53 53
54 54
55 55 /**
56 56 * Observers the property and calls render callback each change.
57 57 *
58 58 * @param target The target object which property will be observed.
59 59 * @param prop The name of the property.
60 60 * @param render The callback which will be called every time the value is changed
61 61 * @returns Rendition which is created instantly
62 62 */
63 63 export function watch<W extends _WidgetBase, K extends keyof W>(
64 64 target: W,
65 65 prop: K,
66 66 render: (model: W[K]) => unknown
67 67 ): Rendition;
68 68 /**
69 69 * Observers the property and calls render callback each change.
70 70 *
71 71 * @param target The target object which property will be observed.
72 72 * @param prop The name of the property.
73 73 * @param render The callback which will be called every time the value is changed
74 74 * @returns Rendition which is created instantly
75 75 */
76 76 export function watch<T extends Stateful, K extends keyof StatefulProps<T>>(
77 77 target: T,
78 78 prop: K,
79 79 render: (model: StatefulProps<T>[K]) => unknown
80 80 ): Rendition;
81 81 export function watch<V>(subj: Subscribable<V>, render: (model: V) => unknown): Rendition;
82 82 export function watch(
83 83 ...args: [Stateful, string, (model: unknown) => unknown] |
84 84 [Subscribable<unknown>, (model: unknown) => unknown]
85 85 ) {
86 86 if (args.length === 3) {
87 87 const [target, prop, render] = args;
88 88 return new WatchRendition(
89 89 render,
90 90 observe(({next}) => {
91 91 const h = target.watch(
92 92 prop,
93 93 (_prop, oldValue, newValue) => oldValue !== newValue && next(newValue)
94 94 );
95 95 next(target.get(prop));
96 96 return () => h.remove();
97 97 })
98 98 );
99 99 } else {
100 100 const [subj, render] = args;
101 101 return new WatchRendition(render, subj);
102 102 }
103 103 }
104 104
105 105 export const watchFor = <T>(source: T[] | Subscribable<OrderedUpdate<T>> | null | undefined, render: (item: T, index: number) => unknown, opts: AnimationAttrs = {}) => {
106 106 return new WatchForRendition({
107 107 ...opts,
108 108 subject: source,
109 109 component: render
110 110 });
111 111 };
112 112
113 113
114 114 export const prop: {
115 115 <T extends Stateful, K extends string & keyof StatefulProps<T>>(target: T, name: K): Observable<StatefulProps<T>[K]>;
116 116 <T extends _WidgetBase, K extends keyof T>(target: T, name: K): Observable<T[K]>;
117 117 } = (target: Stateful, name: string) => {
118 118 return observe(({next}) => {
119 119 const h = target.watch(
120 120 name,
121 121 (_prop, oldValue, newValue) => oldValue !== newValue && next(newValue)
122 122 );
123 123 next(target.get(name));
124 124 return () => h.remove();
125 125 });
126 126 };
127 127
128 128 export const attach = <W extends DjxWidgetBase, K extends keyof W>(target: W, name: K) => (v: W[K]) => target.set(name, v);
129 129
130 130 export const bind = <K extends string, T>(attr: K, subj: Subscribable<T>) => {
131 131 let h = { unsubscribe() { } };
132 132
133 133 return (el: Element | { set(name: K, value: T): void; } | undefined) => {
134 134 if (el) {
135 135 if (isElementNode(el)) {
136 136 h = subj.subscribe({
137 137 next: value => djAttr.set(el, attr, value)
138 138 });
139 139 } else {
140 140 h = subj.subscribe({
141 141 next: value => el.set(attr, value)
142 142 });
143 143 }
144 144 } else {
145 145 h.unsubscribe();
146 146 }
147 147 };
148 148 };
149 149
150 /** Creates refHook to toggle the specified css class on the target element
151 *
152 * @param className
153 * @param subj a boolean observable value. When the value is false the className
154 * is removed, when the value is true, the className is added to the target element
155 * @returns refHook
156 */
150 157 export const toggleClass = (className: string, subj: Subscribable<boolean>) => {
151 158 let h = { unsubscribe() { } };
152 159 return (elOrWidget: HTMLElement | _WidgetBase | undefined) => {
153 160 const el = isWidget(elOrWidget) ? elOrWidget.domNode : elOrWidget;
154 161 if (el) {
155 162 h = subj.subscribe({
156 next: v => djClass.toggle(el, className, v)
163 next: v => djClass.toggle(el, className, v || false)
157 164 });
158 165 } else {
159 166 h.unsubscribe();
160 167 }
161 168 };
162 169 };
163 170
171 /** Combines multiple hooks to the single one */
164 172 export const all = <T, A extends JSX.Ref<T>[]>(...cbs: A): JSX.Ref<T> => (arg: T | undefined) => cbs.forEach(cb => cb(arg));
165 173
166 174 /** Decorates the method which will be registered as the handle for the specified event.
167 175 * This decorator can be applied to DjxWidgetBase subclass methods.
168 176 *
169 177 * ```
170 178 * @on("click")
171 179 * _onClick(eventObj: MouseEvent) {
172 180 * // ...
173 181 * }
174 182 * ```
175 183 */
176 184 export const on = <E extends string>(...eventNames: E[]) =>
177 185 <K extends string,
178 186 T extends DjxWidgetBase<object, { [p in E]: EV }>,
179 187 EV extends Event
180 188 >(
181 189 target: T,
182 190 key: K,
183 191 // eslint-disable-next-line @typescript-eslint/no-unused-vars
184 192 _descriptor: TypedPropertyDescriptor<(eventObj: EV) => void> | TypedPropertyDescriptor<() => void>
185 193 ) => {
186 194 const handlers = eventNames.map(eventName => ({ eventName, handlerMethod: key }));
187 195 target._eventHandlers = target._eventHandlers ? target._eventHandlers.concat(handlers) : handlers;
188 196 };
@@ -1,195 +1,197
1 1 import { TraceSource } from "@implab/core-amd/log/TraceSource";
2 2 import { isPromise } from "@implab/core-amd/safe";
3 3 import { id as mid } from "module";
4 4 import { IScope, Scope } from "./Scope";
5 5 import { isNode, isRendition, isWidget } from "./traits";
6 6
7 7 const trace = TraceSource.get(mid);
8 8
9 9 interface Context {
10 10 readonly scope: IScope;
11 11
12 12 readonly hooks?: (() => void)[];
13 13 }
14 14
15 15 let _context: Context = {
16 16 scope: Scope.dummy
17 17 };
18 18
19 19 let _renderCount = 0;
20 20 let _renderId = 1;
21 21 let _renderedHooks: (() => void)[] = [];
22 22
23 23
24 24 const guard = (cb: () => unknown) => {
25 25 try {
26 26 const result = cb();
27 27 if (isPromise(result)) {
28 28 const warn = (ret: unknown) => trace.error("The callback {0} competed asynchronously. result = {1}", cb, ret);
29 29 result.then(warn, warn);
30 30 }
31 31 } catch (e) {
32 32 trace.error(e);
33 33 }
34 34 };
35 35
36 36 /**
37 37 *
38 38 * @param scope
39 39 * @returns
40 40 */
41 41 export const beginRender = (scope = getScope()) => {
42 42 const prev = _context;
43 43 _renderCount++;
44 44 const renderId = _renderId++;
45 45 trace.debug("beginRender [{0}], pending = {1}", renderId, _renderCount);
46 46 if (_renderCount === 1)
47 47 onRendering();
48 48
49 49 _context = {
50 50 scope,
51 51 hooks: []
52 52 };
53 53 return endRender(prev, _context, renderId);
54 54 };
55 55
56 56 /**
57 57 * Method for a deferred rendering. Returns a promise with `beginRender()` function.
58 58 * Call to `scheduleRender` will save the current context, and will increment pending
59 59 * operations counter.
60 60 *
61 61 * @example
62 62 *
63 63 * const begin = await scheduleRender();
64 64 * const end = begin();
65 65 * try {
66 66 * // do some DOM manipulations
67 67 * } finally {
68 68 * end();
69 69 * }
70 70 *
71 71 * @param scope
72 72 * @returns
73 73 */
74 74 export const scheduleRender = async (scope = getScope()) => {
75 75 const prev = _context;
76 76 _renderCount++;
77 77 const renderId = _renderId ++;
78 78 trace.debug("scheduleRender [{0}], pending = {1}", renderId, _renderCount);
79 79 if (_renderCount === 1)
80 80 onRendering();
81 81
82 82 await Promise.resolve();
83 83
84 84 return () => {
85 85 trace.debug("beginRender [{0}], pending = {1}", renderId, _renderCount);
86 86 _context = {
87 87 scope,
88 88 hooks: []
89 89 };
90 90 return endRender(prev, _context, renderId);
91 91 };
92 92 };
93 93
94 94 /**
95 95 * Completes render operation
96 96 */
97 97 const endRender = (prev: Context, current: Context, renderId: number) => () => {
98 98 if (_context !== current)
99 99 trace.error("endRender mismatched beginRender call");
100 100
101 101 const { hooks } = _context;
102 102 if (hooks)
103 103 hooks.forEach(guard);
104 104
105 105 _renderCount--;
106 106 _context = prev;
107 107
108 108 trace.debug("endRender [{0}], pending = {1}", renderId, _renderCount);
109 109 if (_renderCount === 0)
110 110 onRendered();
111 111 };
112 112
113 113 // called when the first beginRender is called for this iteration
114 114 const onRendering = () => {
115 115 setTimeout(() => {
116 116 if (_renderCount !== 0)
117 117 trace.error("Rendering tasks aren't finished, currently running = {0}", _renderCount);
118 118 });
119 119 };
120 120
121 121 // called when all render operations are complete
122 122 const onRendered = () => {
123 123 _renderedHooks.forEach(guard);
124 124 _renderedHooks = [];
125 125 };
126 126
127 127 export const whenRendered = () => new Promise<void>((resolve) => {
128 128 if (_renderCount)
129 129 _renderedHooks.push(resolve);
130 130 else
131 131 resolve();
132 132 });
133 133
134 134 export const renderHook = (hook: () => void) => {
135 135 const { hooks } = _context;
136 136 if (hooks)
137 137 hooks.push(hook);
138 138 else
139 139 guard(hook);
140 140 };
141 141
142 142 export const refHook = <T>(value: T, ref: JSX.Ref<T>) => {
143 143 const { hooks, scope } = _context;
144 144 if (hooks)
145 145 hooks.push(() => ref(value));
146 146 else
147 147 guard(() => ref(value));
148 148
149 149 scope.own(() => ref(undefined));
150 150 };
151 151
152 152 /** Returns the current scope */
153 153 export const getScope = () => _context.scope;
154 154
155 155 /** Schedules the rendition to be rendered to the DOM Node
156 156 * @param rendition The rendition to be rendered
157 157 * @param scope The scope
158 158 */
159 159 export const render = (rendition: unknown, scope = Scope.dummy) => {
160 160 const complete = beginRender(scope);
161 161 try {
162 162 return getItemDom(rendition);
163 163 } finally {
164 164 complete();
165 165 }
166 166 };
167 167
168 const emptyFragment = document.createDocumentFragment();
169
168 170 /** Renders DOM element for different types of the argument. */
169 171 export const getItemDom = (v: unknown) => {
170 172 if (typeof v === "string" || typeof v === "number" || v instanceof RegExp || v instanceof Date) {
171 173 // primitive types converted to the text nodes
172 174 return document.createTextNode(v.toString());
173 175 } else if (isNode(v)) {
174 176 // nodes are kept as is
175 177 return v;
176 178 } else if (isRendition(v)) {
177 179 // renditions are instantiated
178 180 return v.getDomNode();
179 181 } else if (isWidget(v)) {
180 182 // widgets are converted to it's markup
181 183 return v.domNode;
182 184 } else if (typeof v === "boolean" || v === null || v === undefined) {
183 185 // null | undefined | boolean are removed
184 return document.createDocumentFragment();
186 return emptyFragment;
185 187 } else if (v instanceof Array) {
186 188 // arrays will be translated to document fragments
187 189 const fragment = document.createDocumentFragment();
188 190 v.map(item => getItemDom(item))
189 191 .forEach(node => fragment.appendChild(node));
190 192 return fragment;
191 193 } else {
192 194 // bug: explicit error otherwise
193 195 throw new Error(`Invalid parameter: ${String(v)}`);
194 196 }
195 197 };
@@ -1,87 +1,87
1 1 import { djbase, djclass, bind, prototype, AbstractConstructor } from "../declare";
2 2
3 3 import { DjxWidgetBase } from "../tsx/DjxWidgetBase";
4 4 import { createElement, on } from "../tsx";
5 5 import { argumentNotNull } from "@implab/core-amd/safe";
6 6
7 7 interface MyWidgetAttrs {
8 8 title: string;
9 9
10 10 counter: number;
11 11 }
12 12
13 13 interface MyWidgetEvents {
14 14 "count-inc": Event & {
15 15 detail: number;
16 16 };
17 17
18 18 "count-dec": Event & {
19 19 detail: number;
20 20 };
21 21 }
22 22
23 23 interface FrameProps {
24 24 ref?: JSX.Ref<HTMLDivElement>;
25 25 children?: unknown[];
26 26 }
27 27
28 28 const Frame = ({children, ref}: FrameProps) => <div ref={ref} >{children}</div>;
29 29
30 30 @djclass
31 31 export class MyWidget extends djbase(DjxWidgetBase as AbstractConstructor<DjxWidgetBase<MyWidgetAttrs, MyWidgetEvents>>) {
32 32
33 33 @bind({ node: "titleNode", type: "innerHTML" })
34 34 title = "";
35 35
36 36 @prototype(0)
37 37 counter = 0;
38 38
39 39 frameNode?: HTMLDivElement;
40 40
41 41 render() {
42 42
43 43 return <div className="myWidget" onsubmit={this._onSubmit} tabIndex={3} style={{ alignContent: "center", border: "1px solid" }} >
44 44 <h1 data-dojo-attach-point="titleNode"></h1>
45 45 <Frame ref={this._setFrameElement}>
46 46 <span class="up-button" onclick={this._onIncClick}>[+]</span>
47 47 <span class="down-button" onclick={() => this._onDecClick()}>[-]</span>
48 48 </Frame>
49 49 </div>;
50 50 }
51 51
52 52 private readonly _setFrameElement = (node?: HTMLDivElement) => {
53 53 this.frameNode = node;
54 54 };
55 55
56 56 postCreate() {
57 57 super.postCreate();
58 58
59 59 this.on("click", () => {});
60 60 }
61 61
62 62 private readonly _onSubmit = (evt: Event) => {
63 63 argumentNotNull(evt, "evt");
64 64 };
65 65
66 66 private readonly _onIncClick = (evt: MouseEvent) => {
67 67 argumentNotNull(evt, "evt");
68 68
69 69 this.set("counter", this.counter + 1);
70 70
71 71 this.emit("count-inc", { bubbles: false });
72 72 };
73 73
74 74 _onDecClick() {
75 75 this.emit("count-dec", { bubbles: false, detail: this.counter });
76 76 }
77 77
78 78 @on("count-inc")
79 private _onCounterInc(evt: Event & { detail: number; x?: number; }) {
79 protected _onCounterInc(evt: Event & { detail: number; x?: number; }) {
80 80 argumentNotNull(evt, "evt");
81 81 }
82 82
83 83 @on("click", "keydown")
84 84 protected _onClick(evt: MouseEvent | KeyboardEvent) {
85 85 argumentNotNull(evt, "evt");
86 86 }
87 87 } No newline at end of file
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now