-
Notifications
You must be signed in to change notification settings - Fork 0
/
Element.ts
147 lines (120 loc) · 3.98 KB
/
Element.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { Attr } from "./Attr.ts";
import { DOMTokenList } from "./DOMTokenList.ts";
import { HTMLCollection } from "./HTMLCollection.ts";
import { NamedNodeMap } from "./NamedNodeMap.ts";
import { Node } from "./Node.ts";
import { findChildrenByClassName, findChildrenByTag } from "./utils.ts";
export interface ParentNode {
/** Returns the number of children of this ParentNode which are elements. */
childElementCount: number;
/** Returns a live HTMLCollection containing all of the Element objects that are children of this ParentNode, omitting all of its non-element nodes. */
children: HTMLCollection;
}
export class Element extends Node implements ParentNode {
readonly #attributes = new NamedNodeMap();
readonly #children: Element[] = [];
readonly #childrenCollection = new HTMLCollection(this.#children);
readonly #classList = new DOMTokenList();
#parentElement: Element | null;
public get attributes(): NamedNodeMap {
return this.#attributes;
}
public get childElementCount(): number {
return this.#children.length;
}
public get children(): HTMLCollection {
return this.#childrenCollection;
}
public get classList(): DOMTokenList {
return this.#classList;
}
public get className(): string {
return this.#classList.value;
}
public set className(value: string) {
this.setAttribute("class", value);
this.#classList.value = value;
}
public get clientHeight(): number {
return 0;
}
public get clientLeft(): number {
return 0;
}
public get clientTop(): number {
return 0;
}
public get clientWidth(): number {
return 0;
}
public get id(): string {
return this.getAttribute("id") ?? "";
}
public set id(value: string) {
this.setAttribute("id", value);
}
public get parentElement() {
return this.#parentElement;
}
public constructor(
public readonly tagName: string,
parentElement: Element | null,
) {
super(tagName, parentElement);
this.#parentElement = parentElement;
}
public appendChild(element: Element): void {
super.appendChild(element);
this.#children.push(element);
element.#parentElement = this;
}
public getAttribute(name: string): string | null {
return this.attributes.getNamedItem(name)?.value ?? null;
}
public getAttributeNames(): string[] {
return Array.from(
{ length: this.attributes.length },
(_, i) => this.attributes.item(i)!.name,
);
}
/**
* Returns a list of elements with the given class name.
* @param className is a string representing the class name(s) to match; multiple class names are separated by whitespace.
* @returns is a live HTMLCollection of found elements.
*/
public getElementsByClassName(className: string): HTMLCollection {
const elements = Array.from(findChildrenByClassName(this, className));
return new HTMLCollection(elements);
}
/**
* Returns a list of elements with the given tag name.
* @param name is a string representing the name of the elements. The special string "*" represents all elements.
* @returns a live HTMLCollection (but see the note below) of found elements in the order they appear in the tree.
*/
public getElementsByTagName(name: string): HTMLCollection {
const elements = Array.from(findChildrenByTag(this, name));
return new HTMLCollection(elements);
}
public hasAttribute(name: string): boolean {
return this.attributes.getNamedItem(name) !== null;
}
public hasAttributes(): boolean {
return this.attributes.length > 0;
}
public removeAttribute(name: string): void {
this.attributes.removeNamedItem(name);
}
public setAttribute(name: string, value: string): void {
const node = new Attr(this, name, value);
this.attributes.setNamedItem(node);
}
public toggleAttribute(name: string, force?: boolean): boolean {
const value = force ?? !this.hasAttribute(name);
if (value) {
this.setAttribute(name, "");
} else {
this.removeAttribute(name);
}
return value;
}
}