Skip to content

Commit bdb9510

Browse files
author
Michael Mrowetz
committed
#188 additional cleanup
1 parent 76488e2 commit bdb9510

File tree

4 files changed

+74
-185
lines changed

4 files changed

+74
-185
lines changed

Diff for: src/ts/helpers/dom.ts

+15-15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ export function removeClass<T extends Element>(el: T, className: string): T {
3131
return el;
3232
}
3333

34+
/**
35+
* Helper to recursively find parent with the `className` class
36+
* @param base `Element` to start from
37+
* @param className class that the parent should have
38+
*/
39+
export function getParentByClassName(base: Element, className: string) {
40+
if (base.parentElement === undefined) {
41+
return undefined;
42+
}
43+
if (base.parentElement.classList.contains(className)) {
44+
return base.parentElement;
45+
}
46+
return getParentByClassName(base.parentElement, className);
47+
};
48+
3449
/**
3550
* Removes all child DOM nodes from `el`
3651
* @param {Element} el
@@ -66,18 +81,3 @@ export function forEachNodeList<T extends Node>(list: NodeListOf<T>, fn: {(el: T
6681
fn(list.item(i), i);
6782
}
6883
}
69-
70-
/**
71-
* Helper to recousivly find parent with `className`
72-
* @param base `Element` to start from
73-
* @param className class that the parent should have
74-
*/
75-
export function findParentByClassName(base: Element, className: string) {
76-
if (base.parentElement === undefined) {
77-
return undefined;
78-
}
79-
if (base.parentElement.classList.contains(className)) {
80-
return base.parentElement;
81-
}
82-
return findParentByClassName(base.parentElement, className);
83-
};

Diff for: src/ts/helpers/misc.ts

-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ export function findIndex<T>(arr: T[], predicate: {(el: T, index: number): Boole
4545
}
4646
i++;
4747
}
48-
49-
// 7. Return undefined.
5048
return undefined;
5149
}
5250

Diff for: src/ts/waterfall/details-overlay/overlay-manager.ts

+51-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,55 @@
1-
import { forEachNodeList, removeChildren } from "../../helpers/dom";
2-
import { find } from "../../helpers/misc";
1+
import {
2+
forEachNodeList,
3+
getLastItemOfNodeList,
4+
getParentByClassName,
5+
removeChildren,
6+
} from "../../helpers/dom";
7+
import {
8+
find,
9+
isTabDown,
10+
isTabUp,
11+
} from "../../helpers/misc";
312
import { Context, OverlayManagerClass } from "../../typing/context";
413
import { OpenOverlay, OverlayChangeEvent } from "../../typing/open-overlay";
514
import { WaterfallEntry } from "../../typing/waterfall";
615
import { createRowInfoOverlay } from "./svg-details-overlay";
716

817
/** Overlay (popup) instance manager */
918
class OverlayManager implements OverlayManagerClass {
19+
private static showFullName = (el: Element) => {
20+
el.getElementsByClassName("row-fixed").item(0)
21+
.dispatchEvent(new MouseEvent("mouseenter"));
22+
}
23+
/**
24+
* Keypress Event handler for fist el in Overlay,
25+
* to manage highlighting of the element above
26+
*/
27+
private static firstElKeypress = (evt: KeyboardEvent) => {
28+
if (isTabUp(evt)) {
29+
const par = getParentByClassName(evt.target as Element, "row-overlay-holder") as SVGGElement;
30+
if (par && par.previousElementSibling) {
31+
OverlayManager.showFullName(par.previousElementSibling);
32+
}
33+
}
34+
}
35+
36+
/**
37+
* Keypress Event handler for last el in Overlay,
38+
* to manage highlighting of the element below
39+
*/
40+
private static lastElKeypress = (evt: KeyboardEvent) => {
41+
if (isTabDown(evt)) {
42+
const par = getParentByClassName(evt.target as Element, "row-overlay-holder") as SVGGElement;
43+
if (par && par.nextElementSibling) {
44+
OverlayManager.showFullName(par.nextElementSibling);
45+
}
46+
}
47+
}
48+
1049
/** Collection of currely open overlays */
1150
private openOverlays: OpenOverlay[] = [];
1251

1352
constructor(private context: Context, private rowHolder: SVGGElement) {
14-
1553
}
1654

1755
/** all open overlays height combined */
@@ -138,10 +176,8 @@ class OverlayManager implements OverlayManagerClass {
138176
* @param {SVGGElement} overlayHolder
139177
*/
140178
private renderOverlays(detailsHeight: number) {
141-
// removeChildren(this.rowHolder);
142-
179+
/** shared variable to keep track of heigth */
143180
let currY = 0;
144-
145181
let updateHeight = (overlay, y, currHeight) => {
146182
currY += currHeight;
147183
overlay.actualY = y;
@@ -156,17 +192,25 @@ class OverlayManager implements OverlayManagerClass {
156192
if (previewImg && !previewImg.src) {
157193
previewImg.setAttribute("src", previewImg.attributes.getNamedItem("data-src").value);
158194
}
195+
infoOverlay.querySelector("a")
196+
.addEventListener("keydown", OverlayManager.firstElKeypress);
197+
getLastItemOfNodeList(infoOverlay.querySelectorAll("button"))
198+
.addEventListener("keydown", OverlayManager.lastElKeypress);
159199
overlayHolder.appendChild(infoOverlay);
160200
updateHeight(overlay, y, infoOverlay.getBoundingClientRect().height);
161201
};
162202

163203
const rowItems = this.rowHolder.getElementsByClassName("row-item") as NodeListOf<SVGAElement>;
164204
forEachNodeList(rowItems, (rowItem, index) => {
165205
const overlay = find(this.openOverlays, (o) => o.index === index);
166-
let overlayEl = rowItem.nextElementSibling.firstElementChild as SVGGElement;
206+
const overlayEl = rowItem.nextElementSibling.firstElementChild as SVGGElement;
167207
if (overlay === undefined) {
168208
if (overlayEl) {
169209
// remove closed overlay
210+
rowItem.nextElementSibling.querySelector("a")
211+
.removeEventListener("keydown", OverlayManager.firstElKeypress);
212+
getLastItemOfNodeList(rowItem.nextElementSibling.querySelectorAll("button"))
213+
.removeEventListener("keydown", OverlayManager.lastElKeypress);
170214
removeChildren(rowItem.nextElementSibling);
171215
}
172216
return; // not open

Diff for: src/ts/waterfall/row/svg-row.ts

+8-161
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
} from "../../helpers/misc";
88
import * as svg from "../../helpers/svg";
99
import { Context } from "../../typing/context";
10-
import { OpenOverlay } from "../../typing/open-overlay";
1110
import { RectData } from "../../typing/rect-data";
1211
import { WaterfallEntry } from "../../typing/waterfall";
1312
import { getIndicatorIcons } from "./svg-indicators";
@@ -80,196 +79,44 @@ export function createRow(context: Context, index: number,
8079

8180
rowSubComponents.appendRequestLabels(rowName, requestNumberLabel, shortLabel, fullLabel);
8281

83-
// const onOpenOverlayFocusOut = (evt: KeyboardEvent) => {
84-
// if (evt.which !== 9) {
85-
// return; // only handle tabs
86-
// }
87-
// const isUpward = evt.shiftKey;
88-
// console.log("onActiveFocusOut", isUpward);
89-
// };
90-
91-
// accordeon a11y guide
92-
// https://www.w3.org/TR/wai-aria-practices-1.1/#accordion
9382
context.pubSub.subscribeToSpecificOverlayChanges(index, (change) => {
94-
openOverlay = (change.type === "open") ? change.changedOverlay : undefined;
83+
hasOpenOverlay = (change.type === "open");
9584
});
9685
if (index > 0) {
9786
context.pubSub.subscribeToSpecificOverlayChanges(index - 1, (change) => {
98-
prevOpenOverlay = (change.type === "open") ? change.changedOverlay : undefined;
87+
hasPrevOpenOverlay = (change.type === "open");
9988
});
10089
}
10190

102-
let isPoinerClick = false;
103-
let openOverlay: OpenOverlay;
104-
/** Poiter to the previous open Oberlay (if exist) */
105-
let prevOpenOverlay: OpenOverlay;
106-
// let showDetailsTimeout: number;
107-
108-
109-
110-
// const enterOverlaySetup = (isDownwards: boolean, openOverlay: OpenOverlay) => {
111-
// const overlayEl = context.overlayManager.getOpenOverlayDomEl(openOverlay);
112-
// /** Top header el */
113-
// const firstFocusEl = overlayEl.getElementsByTagName("a")[0];
114-
// /** All focusable elements */
115-
// const allFocusEl = overlayEl.querySelectorAll(":scope a, :scope button");
116-
// const lastTab = getLastItemOfNodeList(allFocusEl);
117-
// for (let i = allFocusEl.length - 1; i <= 0 i--) {
118-
// const el = allFocusEl.item(i);
119-
// el.setAttribute("tabindex", "0");
120-
// }
121-
// console.log(allFocusEl)
122-
123-
// const onOverlayExit = () => {
124-
// console.log("Implement me");
125-
// for (let i = allFocusEl.length - 1; i <= 0 i--) {
126-
// const el = allFocusEl.item(i);
127-
// el.setAttribute("tabindex", "-1");
128-
// }
129-
// lastTab.removeEventListener("keypress", onLastElKeypress);
130-
// };
131-
132-
// const onLastElKeypress = (evt: KeyboardEvent) => {
133-
// if (isTabDown(evt)) {
134-
// evt.preventDefault();
135-
// onOverlayExit();
136-
// }
137-
// };
138-
// lastTab.addEventListener("keypress", onLastElKeypress)
139-
// firstFocusEl.focus();
140-
// };
91+
let hasOpenOverlay: boolean;
92+
let hasPrevOpenOverlay: boolean;
14193

142-
143-
144-
145-
// triggered before click by touch and mouse devices
146-
rowItem.addEventListener("mouseup", () => {
147-
isPoinerClick = true;
148-
});
14994
rowItem.addEventListener("click", (evt: MouseEvent) => {
150-
isPoinerClick = false;
15195
onDetailsOverlayShow(evt);
15296
});
15397
rowItem.addEventListener("keydown", (evt: KeyboardEvent) => {
15498
// on enter
15599
if (evt.which === 32) {
156-
evt.preventDefault();
157-
onDetailsOverlayShow(evt);
158-
return;
100+
return onDetailsOverlayShow(evt);
159101
}
160102

161-
// // moving down into overlay
162-
// if (isTabDown(evt) && openOverlay) {
163-
// console.log("moving down into overlay");
164-
// evt.preventDefault();
165-
// const overlayEl = context.overlayManager.getOpenOverlayDomEl(openOverlay);
166-
// /** Top header el */
167-
// const firstFocusEl = overlayEl.getElementsByTagName("a")[0];
168-
// const lastTab = getLastItemOfNodeList(overlayEl.getElementsByClassName("tab-button") as
169-
// NodeListOf<HTMLButtonElement>);
170-
171-
// // Move out up the the top, to the node el
172-
// firstFocusEl.addEventListener("keydown", (inOverlayEvt: KeyboardEvent) => {
173-
// // IE & Edge do not support `focus()` in SVG
174-
// if (isTabUp(inOverlayEvt) && typeof (rowItem as any).focus === "function") {
175-
// console.log("Move out up the the top, to the node el");
176-
// inOverlayEvt.preventDefault();
177-
// console.log("rowItem in `nextFocusEl.on keydown with tab+shift`", rowItem);
178-
// (rowItem as any).focus();
179-
// }
180-
// });
181-
182-
// console.log("lastTab", lastTab);
183-
// // Move out down at the end
184-
// lastTab.addEventListener("keydown", (inOverlayEvt: KeyboardEvent) => {
185-
// // IE & Edge do not support `focus()` in SVG
186-
// if (isTabDown(inOverlayEvt) && typeof (rowItem as any).focus === "function") {
187-
// console.log("Move out down at the end");
188-
// if (rowItem.nextSibling) {
189-
// inOverlayEvt.preventDefault();
190-
// // not last in chart
191-
// (rowItem.nextSibling as any).focus();
192-
// } else {
193-
// //last in chart
194-
// console.log("last in chart")
195-
// inOverlayEvt.preventDefault();
196-
// }
197-
// } else if (isTabDown(inOverlayEvt)) {
198-
// console.log(">>>");
199-
// }
200-
// });
201-
// firstFocusEl.focus();
202-
// return;
203-
// // evt.cancelBubble = true;
204-
// }
205-
206-
// // moving up into overlay
207-
// if (isTabUp(evt) && prevOpenOverlay) {
208-
// console.log("moving up into overlay");
209-
// evt.preventDefault();
210-
// const prevOverlayEl = context.overlayManager.getOpenOverlayDomEl(prevOpenOverlay);
211-
// const lastTab = getLastItemOfNodeList(prevOverlayEl.getElementsByClassName("tab-button") as
212-
// NodeListOf<HTMLButtonElement>);
213-
// lastTab.focus();
214-
// return;
215-
// }
216-
217-
// // tab without open overlays around
218-
if (isTabUp(evt) && !prevOpenOverlay && index > 0) {
103+
// tab without open overlays around
104+
if (isTabUp(evt) && !hasPrevOpenOverlay && index > 0) {
219105
rowItem.previousSibling.previousSibling.lastChild.lastChild.dispatchEvent(new MouseEvent("mouseenter"));
220106
return;
221107
}
222-
if (isTabDown(evt) && !openOverlay) {
108+
if (isTabDown(evt) && !hasOpenOverlay) {
223109
if (rowItem.nextSibling && rowItem.nextSibling.nextSibling) {
224110
rowItem.nextSibling.nextSibling.lastChild.lastChild.dispatchEvent(new MouseEvent("mouseenter"));
225111
}
226-
// else {
227-
// console.log("Sort this out > tab without open overlays around");
228-
// if (context.overlayManager.hasOpenOverlays()) {
229-
// const lastTab = getLastItemOfNodeList(context.overlayManager.getLastOpenOverlayDomEl()
230-
// .getElementsByClassName("tab-button") as NodeListOf<HTMLButtonElement>);
231-
// console.log("END", lastTab);
232-
// lastTab.focus();
233-
// }
234-
// // prev
235-
// // do not prevent default, so the focus moves on
236-
// }
237112
return;
238113
}
239-
// // Not handled
240-
// if (evt.which === 9) {
241-
// console.log("go to next/prev thing");
242-
// }
243114
});
244115

245-
// rowItem.addEventListener("keyup", (evt: KeyboardEvent) => {
246-
// if (evt.which === 9) {
247-
// //document.activeElement === rowItem
248-
// console.log("keydown");
249-
// rowName.dispatchEvent(new MouseEvent("mouseenter"));
250-
// window["eventsStore"]["key"].push(evt);
251-
// }
252-
// });
253-
254-
255-
// rowItem.addEventListener("focusin", (evt: FocusEvent) => {
256-
// console.log("in", isPoinerClick);
257-
// // const test = new MouseEvent("mouseenter");
258-
// rowName.dispatchEvent(new MouseEvent("mouseenter"));
259-
// window["eventsStore"]["mouse"].push(evt);
260-
// });
261-
262-
263116
rowItem.addEventListener("focusout", () => {
264117
rowName.dispatchEvent(new MouseEvent("mouseleave"));
265118
});
266119

267-
// rowItem.addEventListener("click", (evt) => {
268-
// console.log("click", evt);
269-
// onDetailsOverlayShow(evt);
270-
// });
271-
272-
273120
flexScaleHolder.appendChild(rowBar);
274121
leftFixedHolder.appendChild(clipPathElProto.cloneNode(true));
275122
leftFixedHolder.appendChild(rowName);

0 commit comments

Comments
 (0)