copy Daniel's conversion of html.js to TypeScript from microui

This commit is contained in:
Bruno Windels 2021-09-16 10:45:06 +02:00
parent cce8207870
commit 69672dd99c
10 changed files with 33 additions and 27 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {tag, text, classNames, setAttribute} from "./general/html.js";
import {tag, text, classNames, setAttribute} from "./general/html";
/**
* @param {Object} vm view model with {avatarUrl, avatarColorNumber, avatarTitle, avatarLetter}
* @param {Number} size

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {el} from "./html.js";
import {el} from "./html";
import {mountView} from "./utils";
import {ListView} from "./ListView";
import {insertAt} from "./utils";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {el} from "./html.js";
import {el} from "./html";
import {mountView, insertAt} from "./utils";
import {BaseObservableList as ObservableList} from "../../../../observable/list/BaseObservableList.js";
import {UIView, IMountArgs} from "./types";
@ -79,7 +79,7 @@ export class ListView<T, V extends UIView> implements UIView {
if (this._className) {
attr.className = this._className;
}
this._root = el(this._tagName, attr);
this._root = el(this._tagName, attr) as HTMLElement;
this.loadList();
if (this._onItemClick) {
this._root!.addEventListener("click", this);

View file

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {tag} from "../general/html.js";
import {tag} from "../general/html";
export class StaticView {
constructor(value, render = undefined) {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS } from "./html.js";
import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS } from "./html";
import {mountView} from "./utils";
import {BaseUpdateView} from "./BaseUpdateView.js";

View file

@ -1,5 +1,6 @@
/*
Copyright 2020 Bruno Windels <bruno@windels.cloud>
Copyright 2021 Daniel Fedorin <danila.fedorin@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,12 +17,16 @@ limitations under the License.
// DOM helper functions
export function isChildren(children) {
export type ClassNames<T> = { [className: string]: boolean | ((value?: T) => boolean) }
export type BasicAttributes<T> = { [attribute: string]: ClassNames<T> | boolean | string }
export type Child = string | Text | Element
export function isChildren(children: object | Child | Child[]): children is Child | Child[] {
// children should be an not-object (that's the attributes), or a domnode, or an array
return typeof children !== "object" || !!children.nodeType || Array.isArray(children);
return typeof children !== "object" || "nodeType" in children || Array.isArray(children);
}
export function classNames(obj, value) {
export function classNames<T>(obj: ClassNames<T>, value?: T): string {
return Object.entries(obj).reduce((cn, [name, enabled]) => {
if (typeof enabled === "function") {
enabled = enabled(value);
@ -34,7 +39,7 @@ export function classNames(obj, value) {
}, "");
}
export function setAttribute(el, name, value) {
export function setAttribute(el: Element, name: string, value: string | boolean): void {
if (name === "className") {
name = "class";
}
@ -48,22 +53,24 @@ export function setAttribute(el, name, value) {
}
}
export function el(elementName, attributes, children) {
export function el(elementName: string, attributes?: BasicAttributes<never> | Child | Child[], children?: Child | Child[]): Element {
return elNS(HTML_NS, elementName, attributes, children);
}
export function elNS(ns, elementName, attributes, children) {
export function elNS(ns: string, elementName: string, attributes?: BasicAttributes<never> | Child | Child[], children?: Child | Child[]): Element {
if (attributes && isChildren(attributes)) {
children = attributes;
attributes = null;
attributes = undefined;
}
const e = document.createElementNS(ns, elementName);
if (attributes) {
for (let [name, value] of Object.entries(attributes)) {
if (name === "className" && typeof value === "object" && value !== null) {
value = classNames(value);
if (typeof value === "object") {
// Only className should ever be an object; be careful
// here anyway and ignore object-valued non-className attributes.
value = (value !== null && name === "className") ? classNames(value) : false;
}
setAttribute(e, name, value);
}
@ -74,7 +81,7 @@ export function elNS(ns, elementName, attributes, children) {
children = [children];
}
for (let c of children) {
if (!c.nodeType) {
if (typeof c === "string") {
c = text(c);
}
e.appendChild(c);
@ -83,12 +90,12 @@ export function elNS(ns, elementName, attributes, children) {
return e;
}
export function text(str) {
export function text(str: string): Text {
return document.createTextNode(str);
}
export const HTML_NS = "http://www.w3.org/1999/xhtml";
export const SVG_NS = "http://www.w3.org/2000/svg";
export const HTML_NS: string = "http://www.w3.org/1999/xhtml";
export const SVG_NS: string = "http://www.w3.org/2000/svg";
export const TAG_NAMES = {
[HTML_NS]: [
@ -97,10 +104,9 @@ export const TAG_NAMES = {
"table", "thead", "tbody", "tr", "th", "td", "hr",
"pre", "code", "button", "time", "input", "textarea", "label", "form", "progress", "output", "video"],
[SVG_NS]: ["svg", "circle"]
};
export const tag = {};
} as const;
export const tag: { [tagName in typeof TAG_NAMES[string][number]]: (attributes?: BasicAttributes<never> | Child | Child[], children?: Child | Child[]) => Element } = {} as any;
for (const [ns, tags] of Object.entries(TAG_NAMES)) {
for (const tagName of tags) {

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import {UIView, IMountArgs} from "./types";
import {tag} from "./html.js";
import {tag} from "./html";
export function mountView(view: UIView, mountArgs: IMountArgs): HTMLElement {
let node;
@ -38,7 +38,7 @@ export function errorToDOM(error: Error): HTMLElement {
tag.h3(error.message),
tag.p(`This occurred while running ${callee}.`),
tag.pre(error.stack),
]);
]) as HTMLElement;
}
export function insertAt(parentNode: HTMLElement, idx: number, childNode: HTMLElement): void {

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import {TemplateView} from "../../general/TemplateView.js";
import {classNames, tag} from "../../general/html.js";
import {classNames, tag} from "../../general/html";
import {AvatarView} from "../../AvatarView.js";
export class RoomDetailsView extends TemplateView {

View file

@ -16,7 +16,7 @@ limitations under the License.
*/
import {renderStaticAvatar} from "../../../avatar.js";
import {tag} from "../../../general/html.js";
import {tag} from "../../../general/html";
import {mountView} from "../../../general/utils";
import {TemplateView} from "../../../general/TemplateView.js";
import {Popup} from "../../../general/Popup.js";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {tag, text} from "../../../general/html.js";
import {tag, text} from "../../../general/html";
import {BaseMessageView} from "./BaseMessageView.js";
export class TextMessageView extends BaseMessageView {