Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5cec65b

Browse files
committedJan 10, 2022
:Improve type-safety for Grecha tags
1 parent f653e6a commit 5cec65b

File tree

8 files changed

+164
-135
lines changed

8 files changed

+164
-135
lines changed
 

‎js/eval.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function parse_primary(lexer) {
8181
var expr = parse_expr(lexer);
8282
token = lexer.next();
8383
if (token !== ')') {
84-
throw new Error("Expected ')' but got '" + token + "'");
84+
throw new Error("Expected ')' but got '".concat(token, "'"));
8585
}
8686
return expr;
8787
}
@@ -113,7 +113,7 @@ function parse_primary(lexer) {
113113
next_token = lexer.next();
114114
}
115115
if (next_token !== ')') {
116-
throw Error("Expected ')' but got '" + next_token + "'");
116+
throw Error("Expected ')' but got '".concat(next_token, "'"));
117117
}
118118
return {
119119
"kind": "funcall",
@@ -172,7 +172,7 @@ function compile_expr(src) {
172172
if (token !== null) {
173173
console.log(typeof (token));
174174
console.log(token);
175-
throw new Error("Unexpected token '" + token + "'");
175+
throw new Error("Unexpected token '".concat(token, "'"));
176176
}
177177
return result;
178178
}
@@ -189,7 +189,7 @@ function run_expr(expr, user_context) {
189189
if (user_context.vars && value in user_context.vars) {
190190
return user_context.vars[value];
191191
}
192-
throw new Error("Unknown variable '" + value + "'");
192+
throw new Error("Unknown variable '".concat(value, "'"));
193193
}
194194
else {
195195
return number;
@@ -200,24 +200,24 @@ function run_expr(expr, user_context) {
200200
if (unary_op.op in UNARY_OPS) {
201201
return UNARY_OPS[unary_op.op](run_expr(unary_op.operand, user_context));
202202
}
203-
throw new Error("Unknown unary operator '" + unary_op.op + "'");
203+
throw new Error("Unknown unary operator '".concat(unary_op.op, "'"));
204204
}
205205
case 'binary_op': {
206206
var binary_op = expr.payload;
207207
if (binary_op.op in BINARY_OPS) {
208208
return BINARY_OPS[binary_op.op].func(run_expr(binary_op.lhs, user_context), run_expr(binary_op.rhs, user_context));
209209
}
210-
throw new Error("Unknown binary operator '" + binary_op.op + "'");
210+
throw new Error("Unknown binary operator '".concat(binary_op.op, "'"));
211211
}
212212
case 'funcall': {
213213
var funcall = expr.payload;
214214
if (user_context.funcs && funcall.name in user_context.funcs) {
215215
return (_a = user_context.funcs)[funcall.name].apply(_a, funcall.args.map(function (arg) { return run_expr(arg, user_context); }));
216216
}
217-
throw new Error("Unknown function '" + funcall.name + "'");
217+
throw new Error("Unknown function '".concat(funcall.name, "'"));
218218
}
219219
default: {
220-
throw new Error("Unexpected AST node '" + expr.kind + "'");
220+
throw new Error("Unexpected AST node '".concat(expr.kind, "'"));
221221
}
222222
}
223223
}

‎js/grecha.js

+19-16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
"use strict";
2-
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
3-
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
4-
to[j] = from[i];
5-
return to;
2+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4+
if (ar || !(i in from)) {
5+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6+
ar[i] = from[i];
7+
}
8+
}
9+
return to.concat(ar || Array.prototype.slice.call(from));
610
};
711
var LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
812
function tag(name) {
@@ -13,7 +17,7 @@ function tag(name) {
1317
var result = document.createElement(name);
1418
for (var _a = 0, children_1 = children; _a < children_1.length; _a++) {
1519
var child = children_1[_a];
16-
if (typeof (child) === 'string') {
20+
if (typeof child === 'string') {
1721
result.appendChild(document.createTextNode(child));
1822
}
1923
else {
@@ -35,63 +39,63 @@ function canvas() {
3539
for (var _i = 0; _i < arguments.length; _i++) {
3640
children[_i] = arguments[_i];
3741
}
38-
return tag.apply(void 0, __spreadArray(["canvas"], children));
42+
return tag.apply(void 0, __spreadArray(["canvas"], children, false));
3943
}
4044
function h1() {
4145
var children = [];
4246
for (var _i = 0; _i < arguments.length; _i++) {
4347
children[_i] = arguments[_i];
4448
}
45-
return tag.apply(void 0, __spreadArray(["h1"], children));
49+
return tag.apply(void 0, __spreadArray(["h1"], children, false));
4650
}
4751
function h2() {
4852
var children = [];
4953
for (var _i = 0; _i < arguments.length; _i++) {
5054
children[_i] = arguments[_i];
5155
}
52-
return tag.apply(void 0, __spreadArray(["h2"], children));
56+
return tag.apply(void 0, __spreadArray(["h2"], children, false));
5357
}
5458
function h3() {
5559
var children = [];
5660
for (var _i = 0; _i < arguments.length; _i++) {
5761
children[_i] = arguments[_i];
5862
}
59-
return tag.apply(void 0, __spreadArray(["h3"], children));
63+
return tag.apply(void 0, __spreadArray(["h3"], children, false));
6064
}
6165
function p() {
6266
var children = [];
6367
for (var _i = 0; _i < arguments.length; _i++) {
6468
children[_i] = arguments[_i];
6569
}
66-
return tag.apply(void 0, __spreadArray(["p"], children));
70+
return tag.apply(void 0, __spreadArray(["p"], children, false));
6771
}
6872
function a() {
6973
var children = [];
7074
for (var _i = 0; _i < arguments.length; _i++) {
7175
children[_i] = arguments[_i];
7276
}
73-
return tag.apply(void 0, __spreadArray(["a"], children));
77+
return tag.apply(void 0, __spreadArray(["a"], children, false));
7478
}
7579
function div() {
7680
var children = [];
7781
for (var _i = 0; _i < arguments.length; _i++) {
7882
children[_i] = arguments[_i];
7983
}
80-
return tag.apply(void 0, __spreadArray(["div"], children));
84+
return tag.apply(void 0, __spreadArray(["div"], children, false));
8185
}
8286
function span() {
8387
var children = [];
8488
for (var _i = 0; _i < arguments.length; _i++) {
8589
children[_i] = arguments[_i];
8690
}
87-
return tag.apply(void 0, __spreadArray(["span"], children));
91+
return tag.apply(void 0, __spreadArray(["span"], children, false));
8892
}
8993
function select() {
9094
var children = [];
9195
for (var _i = 0; _i < arguments.length; _i++) {
9296
children[_i] = arguments[_i];
9397
}
94-
return tag.apply(void 0, __spreadArray(["select"], children));
98+
return tag.apply(void 0, __spreadArray(["select"], children, false));
9599
}
96100
function img(src) {
97101
return tag("img").att$("src", src);
@@ -117,8 +121,7 @@ function router(routes) {
117121
result.appendChild(routes[hashLocation]);
118122
return result;
119123
}
120-
;
121124
syncHash();
122-
window.addEventListener("hashchange", syncHash);
125+
window.addEventListener('hashchange', syncHash);
123126
return result;
124127
}

‎js/index.js

+21-21
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function compileShaderSource(gl, source, shaderType) {
2525
gl.shaderSource(shader, source);
2626
gl.compileShader(shader);
2727
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
28-
throw new Error("Could not compile " + shaderTypeToString() + " shader: " + gl.getShaderInfoLog(shader));
28+
throw new Error("Could not compile ".concat(shaderTypeToString(), " shader: ").concat(gl.getShaderInfoLog(shader)));
2929
}
3030
return shader;
3131
}
@@ -43,7 +43,7 @@ function linkShaderProgram(gl, shaders, vertexAttribs) {
4343
}
4444
gl.linkProgram(program);
4545
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
46-
throw new Error("Could not link shader program: " + gl.getProgramInfoLog(program));
46+
throw new Error("Could not link shader program: ".concat(gl.getProgramInfoLog(program)));
4747
}
4848
return program;
4949
}
@@ -77,36 +77,36 @@ function loadFilterProgram(gl, filter, vertexAttribs) {
7777
var paramsInputs = {};
7878
var _loop_1 = function (paramName) {
7979
if (paramName in uniforms) {
80-
throw new Error("Redefinition of existing uniform parameter " + paramName);
80+
throw new Error("Redefinition of existing uniform parameter ".concat(paramName));
8181
}
8282
switch (filter.params[paramName].type) {
8383
case "float":
8484
{
8585
var valuePreview_1 = span(filter.params[paramName].init.toString());
8686
var valueInput = input("range");
8787
if (filter.params[paramName].min !== undefined) {
88-
valueInput.att$("min", filter.params[paramName].min);
88+
valueInput.att$("min", filter.params[paramName].min.toString());
8989
}
9090
if (filter.params[paramName].max !== undefined) {
91-
valueInput.att$("max", filter.params[paramName].max);
91+
valueInput.att$("max", filter.params[paramName].max.toString());
9292
}
9393
if (filter.params[paramName].step !== undefined) {
94-
valueInput.att$("step", filter.params[paramName].step);
94+
valueInput.att$("step", filter.params[paramName].step.toString());
9595
}
9696
if (filter.params[paramName].init !== undefined) {
97-
valueInput.att$("value", filter.params[paramName].init);
97+
valueInput.att$("value", filter.params[paramName].init.toString());
9898
}
9999
paramsInputs[paramName] = valueInput;
100-
valueInput.oninput = function () {
101-
valuePreview_1.innerText = this.value;
100+
valueInput.oninput = function (e) {
101+
valuePreview_1.innerText = e.currentTarget.value;
102102
paramsPanel.dispatchEvent(new CustomEvent("paramsChanged"));
103103
};
104104
var label = (_a = filter.params[paramName].label) !== null && _a !== void 0 ? _a : paramName;
105-
paramsPanel.appendChild(div(span(label + ": "), valuePreview_1, div(valueInput)));
105+
paramsPanel.appendChild(div(span("".concat(label, ": ")), valuePreview_1, div(valueInput)));
106106
}
107107
break;
108108
default: {
109-
throw new Error("Filter parameters do not support type " + filter.params[paramName].type);
109+
throw new Error("Filter parameters do not support type ".concat(filter.params[paramName].type));
110110
}
111111
}
112112
uniforms[paramName] = gl.getUniformLocation(id, paramName);
@@ -136,7 +136,7 @@ function ImageSelector() {
136136
var imageInput = input("file");
137137
var imagePreview = img("img/tsodinClown.png")
138138
.att$("class", "widget-element")
139-
.att$("width", CANVAS_WIDTH);
139+
.att$("width", String(CANVAS_WIDTH));
140140
var root = div(div(imageInput).att$("class", "widget-element"), imagePreview).att$("class", "widget");
141141
root.selectedImage$ = function () {
142142
return imagePreview;
@@ -155,7 +155,7 @@ function ImageSelector() {
155155
};
156156
root.updateFiles$ = function (files) {
157157
imageInput.files = files;
158-
imageInput.onchange();
158+
imageInput.dispatchEvent(new UIEvent("change", { view: window, bubbles: true }));
159159
};
160160
imagePreview.addEventListener('load', function () {
161161
root.dispatchEvent(new CustomEvent("imageSelected", {
@@ -168,8 +168,8 @@ function ImageSelector() {
168168
imageInput.value = '';
169169
this.src = 'img/error.png';
170170
});
171-
imageInput.onchange = function () {
172-
imagePreview.src = URL.createObjectURL(this.files[0]);
171+
imageInput.onchange = function (e) {
172+
imagePreview.src = URL.createObjectURL(e.currentTarget.files[0]);
173173
};
174174
return root;
175175
}
@@ -196,15 +196,15 @@ function FilterList() {
196196
if (e.deltaY > 0) {
197197
root.selectedIndex = Math.min(root.selectedIndex + 1, root.length - 1);
198198
}
199-
root.onchange();
199+
root.dispatchEvent(new UIEvent("change", { view: window, bubbles: true }));
200200
});
201201
return root;
202202
}
203203
function FilterSelector() {
204204
var filterList_ = FilterList();
205205
var filterPreview = canvas()
206-
.att$("width", CANVAS_WIDTH)
207-
.att$("height", CANVAS_HEIGHT);
206+
.att$("width", String(CANVAS_WIDTH))
207+
.att$("height", String(CANVAS_HEIGHT));
208208
var root = div(div("Filter: ", filterList_)
209209
.att$("class", "widget-element"), filterPreview.att$("class", "widget-element")).att$("class", "widget");
210210
var gl = filterPreview.getContext("webgl", { antialias: false, alpha: false });
@@ -348,7 +348,7 @@ function FilterSelector() {
348348
delay: dt * 1000,
349349
dispose: 2,
350350
});
351-
renderProgress.style.width = (t / duration) * 50 + "%";
351+
renderProgress.style.width = "".concat((t / duration) * 50, "%");
352352
t += dt;
353353
}
354354
gif.on('finished', function (blob) {
@@ -360,7 +360,7 @@ function FilterSelector() {
360360
renderSpinner.style.display = "none";
361361
});
362362
gif.on('progress', function (p) {
363-
renderProgress.style.width = 50 + p * 50 + "%";
363+
renderProgress.style.width = "".concat(50 + p * 50, "%");
364364
});
365365
gif.render();
366366
return gif;
@@ -416,6 +416,6 @@ window.onload = function () {
416416
gif.abort();
417417
}
418418
var fileName = imageSelector.selectedFileName$();
419-
gif = filterSelector.render$(fileName + ".gif");
419+
gif = filterSelector.render$("".concat(fileName, ".gif"));
420420
};
421421
};

‎package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
"homepage": "https://github.com/tsoding/emoteJAM#readme",
2828
"devDependencies": {
2929
"@types/gif.js": "^0.2.1",
30-
"typescript": "^4.3.2"
30+
"typescript": "^4.5.4"
3131
}
3232
}

‎ts/eval.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,4 @@ function run_expr(expr: Expr, user_context: UserContext = {}): number {
289289
throw new Error(`Unexpected AST node '${expr.kind}'`);
290290
}
291291
}
292-
}
292+
}

‎ts/grecha.ts

+93-67
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,134 @@
11
const LOREM: string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
22

3+
interface IntrinsicElements {
4+
canvas: HTMLCanvasElement,
5+
h1: HTMLHeadingElement,
6+
h2: HTMLHeadingElement,
7+
h3: HTMLHeadingElement,
8+
p: HTMLParagraphElement,
9+
a: HTMLAnchorElement,
10+
div: HTMLDivElement,
11+
span: HTMLSpanElement,
12+
img: HTMLImageElement,
13+
input: HTMLInputElement,
14+
select: HTMLSelectElement,
15+
}
16+
17+
type ElementType<P = any> = {
18+
[K in keyof IntrinsicElements]: P extends IntrinsicElements[K] ? K : never;
19+
}[keyof IntrinsicElements];
20+
321
type Child = string | HTMLElement;
4-
// TODO(#73): make tag more typesafe
5-
// Essentially get rid of the `any`
6-
type Tag = any;
7-
8-
function tag(name: string, ...children: Child[]): Tag {
9-
const result: Tag = document.createElement(name);
10-
for (const child of children) {
11-
if (typeof(child) === 'string') {
12-
result.appendChild(document.createTextNode(child));
13-
} else {
14-
result.appendChild(child);
15-
}
22+
type Tag<TElement extends Element = HTMLElement> = TElement & {
23+
att$(this: Tag<TElement>, name: string, value: string): Tag<TElement>,
24+
onclick$(
25+
this: Tag<TElement>,
26+
callback: (this: GlobalEventHandlers, ev: MouseEvent) => Tag<TElement>
27+
): Tag,
28+
[handler: `${string}$`]: (...args: any[]) => any;
29+
};
30+
31+
function tag<T extends keyof IntrinsicElements>(
32+
name: T,
33+
...children: Child[]
34+
): Tag<IntrinsicElements[T]> {
35+
const result = document.createElement(name as string) as Tag<IntrinsicElements[T]>;
36+
for (const child of children) {
37+
if (typeof child === 'string') {
38+
result.appendChild(document.createTextNode(child));
39+
} else {
40+
result.appendChild(child);
1641
}
42+
}
1743

18-
result.att$ = function(name: string, value: string) {
19-
this.setAttribute(name, value);
20-
return this;
21-
};
44+
result.att$ = function (name, value) {
45+
this.setAttribute(name, value);
46+
return this;
47+
};
2248

49+
result.onclick$ = function (callback) {
50+
this.onclick = callback;
51+
return this;
52+
};
2353

24-
result.onclick$ = function(callback: (this: GlobalEventHandlers, ev: MouseEvent) => Tag) {
25-
this.onclick = callback;
26-
return this;
27-
};
28-
29-
return result;
54+
return result;
3055
}
3156

32-
function canvas(...children: Child[]): Tag {
33-
return tag("canvas", ...children);
57+
function canvas(...children: Child[]) {
58+
return tag("canvas", ...children);
3459
}
3560

36-
function h1(...children: Child[]): Tag {
37-
return tag("h1", ...children);
61+
function h1(...children: Child[]) {
62+
return tag("h1", ...children);
3863
}
3964

40-
function h2(...children: Child[]): Tag {
41-
return tag("h2", ...children);
65+
function h2(...children: Child[]) {
66+
return tag("h2", ...children);
4267
}
4368

44-
function h3(...children: Child[]): Tag {
45-
return tag("h3", ...children);
69+
function h3(...children: Child[]) {
70+
return tag("h3", ...children);
4671
}
4772

48-
function p(...children: Child[]): Tag {
49-
return tag("p", ...children);
73+
function p(...children: Child[]) {
74+
return tag("p", ...children);
5075
}
5176

52-
function a(...children: Child[]): Tag {
53-
return tag("a", ...children);
77+
function a(...children: Child[]) {
78+
return tag("a", ...children);
5479
}
5580

56-
function div(...children: Child[]): Tag {
57-
return tag("div", ...children);
81+
function div(...children: Child[]) {
82+
return tag("div", ...children);
5883
}
5984

60-
function span(...children: Child[]): Tag {
61-
return tag("span", ...children);
85+
function span(...children: Child[]) {
86+
return tag("span", ...children);
6287
}
6388

64-
function select(...children: Child[]): Tag {
65-
return tag("select", ...children);
89+
function select(...children: Child[]) {
90+
return tag("select", ...children);
6691
}
6792

68-
69-
function img(src: string): Tag {
70-
return tag("img").att$("src", src);
93+
function img(src: string) {
94+
return tag("img").att$("src", src);
7195
}
7296

73-
function input(type: string): Tag {
74-
return tag("input").att$("type", type);
97+
function input(type: string) {
98+
return tag("input").att$("type", type);
7599
}
76100

77101
interface Routes {
78-
[route: string]: Tag
102+
[route: string]: Tag<HTMLDivElement>
79103
}
80104

81-
function router(routes: Routes): Tag {
82-
let result = div();
105+
function router(routes: Routes) {
106+
let result = div();
83107

84-
function syncHash() {
85-
let hashLocation = document.location.hash.split('#')[1];
86-
if (!hashLocation) {
87-
hashLocation = '/';
88-
}
108+
function syncHash() {
109+
let hashLocation = document.location.hash.split('#')[1];
110+
if (!hashLocation) {
111+
hashLocation = '/';
112+
}
89113

90-
if (!(hashLocation in routes)) {
91-
const route404 = '/404';
92-
console.assert(route404 in routes);
93-
hashLocation = route404;
94-
}
114+
if (!(hashLocation in routes)) {
115+
const route404 = '/404';
116+
console.assert(route404 in routes);
117+
hashLocation = route404;
118+
}
95119

96-
while (result.firstChild) {
97-
result.removeChild(result.lastChild);
98-
}
99-
result.appendChild(routes[hashLocation]);
120+
while (result.firstChild) {
121+
// Type-safety: `lastChild` can never be `null` if `firstChild` is present,
122+
// since it will only be `null` if `result` has no child elements.
123+
result.removeChild(result.lastChild!);
124+
}
125+
result.appendChild(routes[hashLocation]);
100126

101-
return result;
102-
};
127+
return result;
128+
}
103129

104-
syncHash();
105-
window.addEventListener("hashchange", syncHash);
130+
syncHash();
131+
window.addEventListener('hashchange', syncHash);
106132

107-
return result;
133+
return result;
108134
}

‎ts/index.ts

+18-18
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ function loadFilterProgram(gl: WebGLRenderingContext, filter: Filter, vertexAttr
118118

119119
// TODO(#55): there no "reset to default" button in the params panel of a filter
120120
let paramsPanel = div().att$("class", "widget-element");
121-
let paramsInputs: {[name: string]: Tag} = {};
121+
let paramsInputs: {[name: string]: Tag<HTMLInputElement>} = {};
122122

123123
for (let paramName in filter.params) {
124124
if (paramName in uniforms) {
@@ -131,25 +131,25 @@ function loadFilterProgram(gl: WebGLRenderingContext, filter: Filter, vertexAttr
131131
const valueInput = input("range");
132132

133133
if (filter.params[paramName].min !== undefined) {
134-
valueInput.att$("min", filter.params[paramName].min);
134+
valueInput.att$("min", filter.params[paramName].min!.toString());
135135
}
136136

137137
if (filter.params[paramName].max !== undefined) {
138-
valueInput.att$("max", filter.params[paramName].max);
138+
valueInput.att$("max", filter.params[paramName].max!.toString());
139139
}
140140

141141
if (filter.params[paramName].step !== undefined) {
142-
valueInput.att$("step", filter.params[paramName].step);
142+
valueInput.att$("step", filter.params[paramName].step!.toString());
143143
}
144144

145145
if (filter.params[paramName].init !== undefined) {
146-
valueInput.att$("value", filter.params[paramName].init);
146+
valueInput.att$("value", filter.params[paramName].init!.toString());
147147
}
148148

149149
paramsInputs[paramName] = valueInput;
150150

151-
valueInput.oninput = function () {
152-
valuePreview.innerText = this.value;
151+
valueInput.oninput = function (e) {
152+
valuePreview.innerText = (e.currentTarget as HTMLInputElement).value;
153153
paramsPanel.dispatchEvent(new CustomEvent("paramsChanged"));
154154
};
155155

@@ -194,7 +194,7 @@ function ImageSelector() {
194194
const imageInput = input("file");
195195
const imagePreview = img("img/tsodinClown.png")
196196
.att$("class", "widget-element")
197-
.att$("width", CANVAS_WIDTH);
197+
.att$("width", String(CANVAS_WIDTH));
198198
const root = div(
199199
div(imageInput).att$("class", "widget-element"),
200200
imagePreview
@@ -213,13 +213,13 @@ function ImageSelector() {
213213
}
214214
}
215215

216-
const file = imageInput.files[0];
216+
const file = imageInput.files![0];
217217
return file ? removeFileNameExt(file.name) : 'result';
218218
};
219219

220220
root.updateFiles$ = function(files: FileList) {
221221
imageInput.files = files;
222-
imageInput.onchange();
222+
imageInput.dispatchEvent(new UIEvent("change", { view: window, bubbles: true }));
223223
}
224224

225225
imagePreview.addEventListener('load', function(this: HTMLImageElement) {
@@ -235,8 +235,8 @@ function ImageSelector() {
235235
this.src = 'img/error.png';
236236
});
237237

238-
imageInput.onchange = function() {
239-
imagePreview.src = URL.createObjectURL(this.files[0]);
238+
imageInput.onchange = function(e) {
239+
imagePreview.src = URL.createObjectURL((e.currentTarget as HTMLInputElement).files![0]);
240240
};
241241

242242
return root;
@@ -270,7 +270,7 @@ function FilterList() {
270270
if (e.deltaY > 0) {
271271
root.selectedIndex = Math.min(root.selectedIndex + 1, root.length - 1);
272272
}
273-
root.onchange();
273+
root.dispatchEvent(new UIEvent("change", { view: window, bubbles: true }));
274274
});
275275

276276
return root;
@@ -279,8 +279,8 @@ function FilterList() {
279279
function FilterSelector() {
280280
const filterList_ = FilterList();
281281
const filterPreview = canvas()
282-
.att$("width", CANVAS_WIDTH)
283-
.att$("height", CANVAS_HEIGHT);
282+
.att$("width", String(CANVAS_WIDTH))
283+
.att$("height", String(CANVAS_HEIGHT));
284284
const root = div(
285285
div("Filter: ", filterList_)
286286
.att$("class", "widget-element"),
@@ -337,7 +337,7 @@ function FilterSelector() {
337337
if (program) {
338338
const snapshot = program.paramsPanel.paramsSnapshot$();
339339
for (let paramName in snapshot) {
340-
gl.uniform1f(snapshot[paramName].uniform, snapshot[paramName].value);
340+
gl!.uniform1f(snapshot[paramName].uniform, snapshot[paramName].value);
341341
}
342342
}
343343
}
@@ -527,7 +527,7 @@ window.onload = () => {
527527
const filterSelector = FilterSelector();
528528
imageSelector.addEventListener('imageSelected', function(e: CustomEvent) {
529529
filterSelector.updateImage$(e.detail.imageData);
530-
});
530+
} as EventListener);
531531
filterSelectorEntry.appendChild(filterSelector);
532532
imageSelectorEntry.appendChild(imageSelector);
533533

@@ -556,4 +556,4 @@ window.onload = () => {
556556
gif = filterSelector.render$(`${fileName}.gif`);
557557
};
558558
}
559-
// TODO(#75): run typescript compiler on CI
559+
// TODO(#75): run typescript compiler on CI

0 commit comments

Comments
 (0)
Please sign in to comment.