/
Signature.ts
169 lines (146 loc) · 4.51 KB
/
Signature.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import { Component, IComponentOptions } from "../Component";
import { Viewport } from "../services/Viewport";
/**
* Holds a signature and its description.
*/
class SignatureGroup {
/**
* The target signature.
*/
signature: Element;
/**
* The description for the signature.
*/
description: Element;
/**
* Create a new SignatureGroup instance.
*
* @param signature The target signature.
* @param description The description for the signature.
*/
constructor(signature: Element, description: Element) {
this.signature = signature;
this.description = description;
}
/**
* Add the given class to all elements of the group.
*
* @param className The class name to add.
*/
addClass(className: string) {
this.signature.classList.add(className);
this.description.classList.add(className);
}
/**
* Remove the given class from all elements of the group.
*
* @param className The class name to remove.
*/
removeClass(className: string) {
this.signature.classList.remove(className);
this.description.classList.remove(className);
}
}
/**
* Controls the tab like behavior of methods and functions with multiple signatures.
*/
export class Signature extends Component {
/**
* List of found signature groups.
*/
private groups: SignatureGroup[] = [];
/**
* The container holding all the descriptions.
*/
private container?: HTMLElement;
/**
* The index of the currently displayed signature.
*/
private index: number = -1;
/**
* Create a new Signature instance.
*
* @param options Backbone view constructor options.
*/
constructor(options: IComponentOptions) {
super(options);
this.createGroups();
if (this.container) {
this.el.classList.add("active");
Array.from(this.el.children).forEach((signature) => {
signature.addEventListener("touchstart", (event) =>
this.onClick(event)
);
signature.addEventListener("click", (event) =>
this.onClick(event)
);
});
this.container.classList.add("active");
this.setIndex(this.inferIndexFromHash());
}
}
/**
* Set the index of the active signature.
*
* @param index The index of the signature to activate.
*/
private setIndex(index: number) {
if (index < 0) index = 0;
if (index > this.groups.length - 1) index = this.groups.length - 1;
if (this.index == index) return;
const to = this.groups[index];
if (this.index > -1) {
const from = this.groups[this.index];
from.removeClass("current");
from.addClass("fade-out");
to.addClass("current");
to.addClass("fade-in");
if (to.signature.id) {
const target = new URL(location.href);
target.hash = to.signature.id;
history.replaceState({}, "", target);
}
Viewport.instance.triggerResize();
setTimeout(() => {
from.removeClass("fade-out");
to.removeClass("fade-in");
}, 300);
} else {
to.addClass("current");
Viewport.instance.triggerResize();
}
this.index = index;
}
/**
* Find all signature/description groups.
*/
private createGroups() {
const signatures = this.el.children;
if (signatures.length < 2) return;
this.container = this.el.nextElementSibling as HTMLElement;
const descriptions = this.container.children;
this.groups = [];
for (let index = 0; index < signatures.length; index++) {
this.groups.push(
new SignatureGroup(signatures[index], descriptions[index])
);
}
}
/**
* Triggered when the user clicks onto a signature header.
*
* @param e The related event object.
*/
private onClick(e: Event) {
this.groups.forEach((group, index) => {
if (group.signature === e.currentTarget) {
this.setIndex(index);
}
});
}
private inferIndexFromHash() {
const hash = location.hash.substring(1);
const index = this.groups.findIndex((s) => s.signature.id === hash);
return Math.max(0, index);
}
}