From 5b643bf81c2e9c28293d0f84994090f951f560cf Mon Sep 17 00:00:00 2001 From: Michael Mrowetz Date: Sat, 22 Apr 2017 23:52:09 +0900 Subject: [PATCH] #188 basic outer tabing working --- src/ts/typing/context.ts | 14 +-- src/ts/typing/open-overlay.ts | 3 + .../details-overlay/overlay-manager.ts | 19 +++- src/ts/waterfall/details-overlay/pub-sub.ts | 12 ++- src/ts/waterfall/row/svg-row-subcomponents.ts | 9 +- src/ts/waterfall/row/svg-row.ts | 88 ++++++++++++++++++- 6 files changed, 122 insertions(+), 23 deletions(-) diff --git a/src/ts/typing/context.ts b/src/ts/typing/context.ts index 70243033..49a6d6b1 100644 --- a/src/ts/typing/context.ts +++ b/src/ts/typing/context.ts @@ -1,6 +1,7 @@ -import {OverlayChangeEvent, OverlayChangeSubscriber} from "./open-overlay"; -import {ChartRenderOption} from "./options"; -import {WaterfallEntry} from "./waterfall"; +import { OverlayManager } from "../waterfall/details-overlay/overlay-manager"; +import { OverlayChangeEvent, OverlayChangeSubscriber } from "./open-overlay"; +import { ChartRenderOption } from "./options"; +import { WaterfallEntry } from "./waterfall"; /** * Context object that is passed to (usually stateless) child-functions @@ -10,7 +11,7 @@ export interface Context { /** Publish and Subscribe instance for overlay updates */ pubSub: PubSubClass; /** Overlay (popup) instance manager */ - overlayManager: OverlayManagerClass; + overlayManager: OverlayManager; /** horizontal unit (duration in ms of 1%) */ unit: number; /** height of the requests part of the diagram in px */ @@ -21,6 +22,7 @@ export interface Context { export interface PubSubClass { subscribeToOverlayChanges: (fn: OverlayChangeSubscriber) => void; + subscribeToSpecificOverlayChanges: (index: number, fn: OverlayChangeSubscriber) => void; publishToOverlayChanges: (change: OverlayChangeEvent) => void; } @@ -30,10 +32,10 @@ export interface OverlayManagerClass { /** Opens an overlay - rerenders others */ openOverlay: (index: number, y: number, detailsHeight: number, entry: WaterfallEntry, - barEls: SVGGElement[]) => void; + barEls: SVGGElement[]) => void; /** toggles an overlay - rerenders others */ toggleOverlay: (index: number, y: number, detailsHeight: number, entry: WaterfallEntry, - barEls: SVGGElement[]) => void; + barEls: SVGGElement[]) => void; /** closes on overlay - rerenders others internally */ closeOverlay: (index: number, detailsHeight: number, barEls: SVGGElement[]) => void; diff --git a/src/ts/typing/open-overlay.ts b/src/ts/typing/open-overlay.ts index 053a8acd..343e364c 100644 --- a/src/ts/typing/open-overlay.ts +++ b/src/ts/typing/open-overlay.ts @@ -24,6 +24,9 @@ export interface OverlayChangeEvent { type: EventType; /** list of currenly open overlays */ openOverlays: OpenOverlay[]; + /** index that triggerd the change */ + changedIndex?: number; + changedOverlay: OpenOverlay; combinedOverlayHeight: number; } diff --git a/src/ts/waterfall/details-overlay/overlay-manager.ts b/src/ts/waterfall/details-overlay/overlay-manager.ts index bac4f8be..e5192db7 100644 --- a/src/ts/waterfall/details-overlay/overlay-manager.ts +++ b/src/ts/waterfall/details-overlay/overlay-manager.ts @@ -5,7 +5,7 @@ import { WaterfallEntry } from "../../typing/waterfall"; import { createRowInfoOverlay } from "./svg-details-overlay"; /** Overlay (popup) instance manager */ -export default class OverlayManager implements OverlayManagerClass { +class OverlayManager implements OverlayManagerClass { /** Collection of currely open overlays */ private openOverlays: OpenOverlay[] = []; @@ -19,6 +19,10 @@ export default class OverlayManager implements OverlayManagerClass { return this.openOverlays.reduce((pre, curr) => pre + curr.height, 0); } + public getOpenOverlays() { + return this.openOverlays; + } + /** * Opens an overlay - rerenders others internaly */ @@ -28,8 +32,7 @@ export default class OverlayManager implements OverlayManagerClass { return; } const self = this; - - this.openOverlays.push({ + const newOverlay: OpenOverlay = { "defaultY": y, "entry": entry, "index": index, @@ -37,10 +40,13 @@ export default class OverlayManager implements OverlayManagerClass { self.closeOverlay(index, detailsHeight, barEls); }, "openTabIndex": 0, - }); + }; + this.openOverlays.push(newOverlay); this.renderOverlays(detailsHeight); this.context.pubSub.publishToOverlayChanges({ + "changedIndex": index, + "changedOverlay": newOverlay, "combinedOverlayHeight": self.getCombinedOverlayHeight(), "openOverlays": self.openOverlays, "type": "open", @@ -71,6 +77,7 @@ export default class OverlayManager implements OverlayManagerClass { this.renderOverlays(detailsHeight); this.context.pubSub.publishToOverlayChanges({ + "changedIndex": index, "combinedOverlayHeight": self.getCombinedOverlayHeight(), "openOverlays": self.openOverlays, "type": "closed", @@ -131,3 +138,7 @@ export default class OverlayManager implements OverlayManagerClass { }); } }; +export { + OverlayManager +}; +export default OverlayManager; diff --git a/src/ts/waterfall/details-overlay/pub-sub.ts b/src/ts/waterfall/details-overlay/pub-sub.ts index 8ed3185d..57ad4dc2 100644 --- a/src/ts/waterfall/details-overlay/pub-sub.ts +++ b/src/ts/waterfall/details-overlay/pub-sub.ts @@ -1,6 +1,6 @@ // simple pub/sub for change to the overlay -import {PubSubClass} from "../../typing/context"; -import {OverlayChangeEvent, OverlayChangeSubscriber} from "../../typing/open-overlay"; +import { PubSubClass } from "../../typing/context"; +import { OverlayChangeEvent, OverlayChangeSubscriber } from "../../typing/open-overlay"; export default class PubSub implements PubSubClass { private subscribers: OverlayChangeSubscriber[] = []; @@ -9,6 +9,14 @@ export default class PubSub implements PubSubClass { this.subscribers.push(fn); } + public subscribeToSpecificOverlayChanges(index: number, fn: OverlayChangeSubscriber) { + this.subscribers.push((evt) => { + if (evt.changedIndex === index) { + fn(evt); + } + }); + } + public publishToOverlayChanges(change: OverlayChangeEvent) { this.subscribers.forEach((fn) => fn(change)); } diff --git a/src/ts/waterfall/row/svg-row-subcomponents.ts b/src/ts/waterfall/row/svg-row-subcomponents.ts index e7a831c5..605f5f0a 100644 --- a/src/ts/waterfall/row/svg-row-subcomponents.ts +++ b/src/ts/waterfall/row/svg-row-subcomponents.ts @@ -223,8 +223,7 @@ export function createBgStripe(y: number, height: number, isEven: boolean): SVGR }, className); } -export function createNameRowBg(y: number, rowHeight: number, - onClick: EventListener): SVGGElement { +export function createNameRowBg(y: number, rowHeight: number): SVGGElement { let rowFixed = svg.newG("row row-fixed"); rowFixed.appendChild(svg.newRect({ @@ -237,12 +236,10 @@ export function createNameRowBg(y: number, rowHeight: number, "opacity": 0, })); - rowFixed.addEventListener("click", onClick); - return rowFixed; } -export function createRowBg(y: number, rowHeight: number, onClick: EventListener): SVGGElement { +export function createRowBg(y: number, rowHeight: number): SVGGElement { let rowFixed = svg.newG("row row-flex"); rowFixed.appendChild(svg.newRect({ @@ -255,7 +252,5 @@ export function createRowBg(y: number, rowHeight: number, onClick: EventListener "opacity": 0, })); - rowFixed.addEventListener("click", onClick); - return rowFixed; } diff --git a/src/ts/waterfall/row/svg-row.ts b/src/ts/waterfall/row/svg-row.ts index 6a6e08e7..99bb80fe 100644 --- a/src/ts/waterfall/row/svg-row.ts +++ b/src/ts/waterfall/row/svg-row.ts @@ -2,6 +2,7 @@ import * as icons from "../../helpers/icons"; import * as misc from "../../helpers/misc"; import * as svg from "../../helpers/svg"; import { Context } from "../../typing/context"; +import { OpenOverlay } from "../../typing/open-overlay"; import { RectData } from "../../typing/rect-data"; import { WaterfallEntry } from "../../typing/waterfall"; import { getIndicatorIcons } from "./svg-indicators"; @@ -20,12 +21,13 @@ const ROW_LEFT_MARGIN = 3; export function createRow(context: Context, index: number, maxIconsWidth: number, maxNumberWidth: number, rectData: RectData, entry: WaterfallEntry, - onDetailsOverlayShow: EventListener): SVGGElement { + onDetailsOverlayShow: EventListener): SVGAElement { const y = rectData.y; const rowHeight = rectData.height; const leftColumnWith = context.options.leftColumnWith; - let rowItem = svg.newG(entry.responseDetails.rowClass); + let rowItem = svg.newA(entry.responseDetails.rowClass); + rowItem.setAttribute("href", "javascript:void(0)"); let leftFixedHolder = svg.newSvg("left-fixed-holder", { "width": `${leftColumnWith}%`, "x": "0", @@ -36,8 +38,8 @@ export function createRow(context: Context, index: number, }); let rect = rowSubComponents.createRect(rectData, entry.segments, entry.total); - let rowName = rowSubComponents.createNameRowBg(y, rowHeight, onDetailsOverlayShow); - let rowBar = rowSubComponents.createRowBg(y, rowHeight, onDetailsOverlayShow); + let rowName = rowSubComponents.createNameRowBg(y, rowHeight); + let rowBar = rowSubComponents.createRowBg(y, rowHeight); let bgStripe = rowSubComponents.createBgStripe(y, rowHeight, (index % 2 === 0)); let x = ROW_LEFT_MARGIN + maxIconsWidth; @@ -73,6 +75,84 @@ export function createRow(context: Context, index: number, rowSubComponents.appendRequestLabels(rowName, requestNumberLabel, shortLabel, fullLabel); + // const onOpenOverlayFocusOut = (evt: KeyboardEvent) => { + // if (evt.which !== 9) { + // return; // only handle tabs + // } + // const isUpward = evt.shiftKey; + // console.log("onActiveFocusOut", isUpward); + // }; + + // accordeon a11y guide + // https://www.w3.org/TR/wai-aria-practices-1.1/#accordion + context.pubSub.subscribeToSpecificOverlayChanges(index, (change) => { + console.log("onOverlayChange", change.type); + if (change.type === "open") { + openOverlay = change.changedOverlay; + } else { + openOverlay = undefined; + } + }); + + let isPoinerClick = false; + let openOverlay: OpenOverlay; + // let showDetailsTimeout: number; + // triggered before click by touch and mouse devices + rowItem.addEventListener("mouseup", () => { + isPoinerClick = true; + }); + rowItem.addEventListener("click", (evt: MouseEvent) => { + isPoinerClick = false; + onDetailsOverlayShow(evt); + }); + rowItem.addEventListener("keydown", (evt: KeyboardEvent) => { + if (evt.which === 32) { + evt.preventDefault(); + onDetailsOverlayShow(evt); + } + if (evt.which === 9) { + if (openOverlay) { + // const overlayCount = context.overlayManager.getOpenOverlays().length; + // if(openOverlay.index){ + + // } + // openOverlay. + } else { + let nextRowItem = evt.shiftKey ? rowItem.previousSibling : rowItem.nextSibling; + nextRowItem.lastChild.lastChild.dispatchEvent(new MouseEvent("mouseenter")); + } + } + }); + + // rowItem.addEventListener("keyup", (evt: KeyboardEvent) => { + // if (evt.which === 9) { + // //document.activeElement === rowItem + // console.log("keydown"); + // rowName.dispatchEvent(new MouseEvent("mouseenter")); + // window["eventsStore"]["key"].push(evt); + // } + // }); + + + // rowItem.addEventListener("focusin", (evt: FocusEvent) => { + // console.log("in", isPoinerClick); + // // const test = new MouseEvent("mouseenter"); + // rowName.dispatchEvent(new MouseEvent("mouseenter")); + // window["eventsStore"]["mouse"].push(evt); + // }); + + + rowItem.addEventListener("focusout", () => { + console.log("out"); + rowName.dispatchEvent(new MouseEvent("mouseleave")); + }); + + // rowItem.addEventListener("click", (evt) => { + // console.log("click", evt); + // onDetailsOverlayShow(evt); + // }); + + flexScaleHolder.appendChild(rowBar); leftFixedHolder.appendChild(clipPathElProto.cloneNode(true)); leftFixedHolder.appendChild(rowName);