diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index d758717101..f5ad684595 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -51,31 +51,6 @@ import { CommandContainer } from "./command-palette/command-container"; import { KubeObjectStore } from "../kube-object.store"; import { clusterContext } from "./context"; -/** - * Hacking into document event listeners to detect leaks - * TODO: remove this - */ -(function watchEvent() { - const addOne = document.addEventListener; - const removeOne = document.removeEventListener; - - (document as any)["listeners"] = new Map(); - - document.addEventListener = (type: string, listener: any) => { - const registry: Map = (document as any)["listeners"]; - - registry.set(listener, type); - addOne(type, listener); - }; - - document.removeEventListener = (type: string, listener: any) => { - const registry: Map = (document as any)["listeners"]; - - registry.delete(listener); - removeOne(type, listener); - }; -})(); - @observer export class App extends React.Component { static async init() { diff --git a/src/renderer/components/table/table-cell.tsx b/src/renderer/components/table/table-cell.tsx index 978344f4b7..6b80935213 100644 --- a/src/renderer/components/table/table-cell.tsx +++ b/src/renderer/components/table/table-cell.tsx @@ -24,7 +24,16 @@ export interface TableCellProps extends React.DOMAttributes { _sorting?: Partial; // sorting state, don't use this prop outside (!) _sort?(sortBy: TableSortBy): void; //
sort function, don't use this prop outside (!) _nowrap?: boolean; // indicator, might come from parent , don't use this prop outside (!) - _onResize?(width: number): void; //
resize callbalck, don't use this prop outside (!) + + /** + * Triggers every time this cell is resized by user + * @param width desired width of this cell + */ + _onResize?(width: number): void; + + /** + * Triggers once the user has finished resizing this cell + */ _onResizeComplete?(): void; // triggers a callback when user stops resizing } @@ -36,6 +45,77 @@ export class TableCell extends React.Component { private resizeHandlerState?: ResizeHandlerState; private cellContainer: React.RefObject = React.createRef(); + /** + * Stores an instance of `` that is currently responsible for handling resize-related events + */ + private static currentEventHandlingInstance?: TableCell; + + /** + * Appends static event proxies to document `mousemove` and `mouseup` events for resizing, + * sets a particulate instance of `` to handle these events + * @param handlingInstance instance of `` responsible for handling events + */ + private static addMouseEventListeners(handlingInstance: TableCell) { + TableCell.currentEventHandlingInstance = handlingInstance; + + document.addEventListener("mousemove", TableCell.mouseMoveEventProxy); + document.addEventListener("mouseup", TableCell.mouseUpEventProxy); + } + + /** + * Detaches static proxies from document `mousemove` and `mouseup`, + * cleans up the reference to current event handling instance + */ + private static removeMouseEventListeners() { + document.removeEventListener("mousemove", TableCell.mouseMoveEventProxy); + document.removeEventListener("mouseup", TableCell.mouseUpEventProxy); + + delete TableCell.currentEventHandlingInstance; + } + + /** + * Proxy for document-level `mousemove` events. + * + * Forwards the event to a member function + * of a current event handling instance of ``. + * + * Static to prevent it from leaking events. + */ + private static mouseMoveEventProxy(event: MouseEvent) { + TableCell.currentEventHandlingInstance.mouseMoveHandler(event); + } + + /** + * Proxy for document-level `mouseup` events. + * + * Forwards the event to a member function + * of a current event handling instance of ``. + * + * Static to prevent it from leaking events. + */ + private static mouseUpEventProxy() { + TableCell.currentEventHandlingInstance.mouseUpHandler(); + } + + private mouseMoveHandler = throttle((event: MouseEvent) => { + if (!this.resizeHandlerState) { + return; + } + + const diffPosX = event.pageX - this.resizeHandlerState.mousePosX; + const currentWidth = this.cellContainer.current.offsetWidth; + + this.props?._onResize(currentWidth + diffPosX); + this.resizeHandlerState.mousePosX = event.pageX; + }, ERGONOMIC_RESIZE_THROTTLE_RATE); + + private mouseUpHandler() { + TableCell.removeMouseEventListeners(); + + this.props?._onResizeComplete(); + delete this.resizeHandlerState; + } + @autobind() onClick(evt: React.MouseEvent) { if (this.props.onClick) { @@ -48,7 +128,7 @@ export class TableCell extends React.Component { } componentWillUnmount() { - this.removeMouseEventListeners(); + TableCell.removeMouseEventListeners(); } get isSortable() { @@ -81,37 +161,24 @@ export class TableCell extends React.Component { } } - addMouseEventListeners() { - document.addEventListener("mousemove", this.mouseMoveHandler.bind(this)); - document.addEventListener("mouseup", this.mouseUpHandler.bind(this)); - } - - removeMouseEventListeners() { - document.removeEventListener("mousemove", this.mouseMoveHandler.bind(this)); - document.removeEventListener("mouseup", this.mouseUpHandler.bind(this)); - } - - mouseMoveHandler = throttle((event: MouseEvent) => { - if (!this.resizeHandlerState) { - return; - } - - const diffPosX = event.pageX - this.resizeHandlerState.mousePosX; - const currentWidth = this.cellContainer.current.offsetWidth; - - this.props?._onResize(currentWidth + diffPosX); - this.resizeHandlerState.mousePosX = event.pageX; - }, ERGONOMIC_RESIZE_THROTTLE_RATE); - - mouseUpHandler() { - this.removeMouseEventListeners(); - console.log((document as any)["listeners"]); - this.props?._onResizeComplete(); - this.resizeHandlerState = undefined; - } - render() { - const { className, checkbox, isChecked, isResizable: resizable, size, sortBy, _sort, _sorting, _nowrap, children, title, renderBoolean: displayBoolean, showWithColumn, _onResize, ...cellProps } = this.props; + const { + className, + checkbox, + isChecked, + isResizable: resizable, + size, + sortBy, + _sort, + _sorting, + _nowrap, + children, + title, + renderBoolean: displayBoolean, + showWithColumn, + _onResize, + _onResizeComplete, + ...cellProps } = this.props; const classNames = cssNames("TableCell", className, { checkbox, nowrap: _nowrap, @@ -126,7 +193,7 @@ export class TableCell extends React.Component { this.resizeHandlerState = { mousePosX: event.pageX }; - this.addMouseEventListeners(); + TableCell.addMouseEventListeners(this); }, // prevent click events from triggering onClick: prevDefault(() => {})