<commit_before>import * as d3 from "d3";

import {MetaDataType} from './meta_data';
import {Node} from './node';
import {classify} from './util';

export class Tooltip {
    private offsetX: number;
    private visibility: string;

    constructor(private node: Node, private eventType: string) {
        this.offsetX = 30;
        this.visibility = 'hidden';
    }

    tspanOffsetY(isHeader: boolean): string {
        return isHeader ? '2em' : '1.1em';
    }

    transform(): string {
        return `translate(${this.node.x}, ${this.node.y})`;
    }

    class(): string {
        return `tooltip ${this.nodeId()}`;
    }

    nodeId(): string {
        return classify((<Node>this.node).name);
    }

    // This doesn't actually toggle visibility, but returns string for toggled visibility
    toggleVisibility(): string {
        if (this.visibility === 'hidden') {
            this.visibility = 'visible';
            return 'visible';
        } else {
            this.visibility = 'hidden';
            return 'hidden';
        }
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    toggleVisibilityCallback(element: SVGGElement): any {
        return () => {
            // Do nothing for dragging
            if (event.defaultPrevented) {
                return;
            }

            d3.select(element).attr('visibility', this.toggleVisibility());
        };
    }

    configureNodeClickCallback(element: SVGGElement): void {
        d3.select(`#${this.nodeId()}`).on('click', this.toggleVisibilityCallback(element));
    }

    configureNodeHoverCallback(element: SVGGElement): void {
        d3.select(`#${this.nodeId()}`).on('mouseenter', this.toggleVisibilityCallback(element));
        d3.select(`#${this.nodeId()}`).on('mouseleave', this.toggleVisibilityCallback(element));
    }

    disableZoom(element: SVGAElement): void {
        d3.select(element).on('mousedown', () => {
            (<MouseEvent>d3.event).stopPropagation();
        })
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    static render(layer: d3.Selection<any>, tooltips: Tooltip[]): d3.Selection<Tooltip> {
        const tooltip = layer.selectAll('.tooltip')
            .data(tooltips)
            .enter()
            .append('g')
            .attr('visibility', (d) => d.visibility)
            .attr('class', (d) => d.class())
            .attr('transform', (d) => d.transform());

        tooltip.each(function (d) {
            Tooltip.appendText(this)<commit_msg>Fix: CSS escape when using as selectors<commit_after>import * as d3 from "d3";

import {MetaDataType} from './meta_data';
import {Node} from './node';
import {classify} from './util';

export class Tooltip {
    private offsetX: number;
    private visibility: string;

    constructor(private node: Node, private eventType: string) {
        this.offsetX = 30;
        this.visibility = 'hidden';
    }

    tspanOffsetY(isHeader: boolean): string {
        return isHeader ? '2em' : '1.1em';
    }

    transform(): string {
        return `translate(${this.node.x}, ${this.node.y})`;
    }

    class(): string {
        return `tooltip ${this.nodeId()}`;
    }

    nodeId(escape = false): string {
        let id = classify((<Node>this.node).name);

        if (escape) {
            id = CSS.escape(id);
        }

        return id;
    }

    // This doesn't actually toggle visibility, but returns string for toggled visibility
    toggleVisibility(): string {
        if (this.visibility === 'hidden') {
            this.visibility = 'visible';
            return 'visible';
        } else {
            this.visibility = 'hidden';
            return 'hidden';
        }
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    toggleVisibilityCallback(element: SVGGElement): any {
        return () => {
            // Do nothing for dragging
            if (event.defaultPrevented) {
                return;
            }

            d3.select(element).attr('visibility', this.toggleVisibility());
        };
    }

    configureNodeClickCallback(element: SVGGElement): void {
        d3.select(`#${this.nodeId(true)}`).on('click', this.toggleVisibilityCallback(element));
    }

    configureNodeHoverCallback(element: SVGGElement): void {
        d3.select(`#${this.nodeId(true)}`).on('mouseenter', this.toggleVisibilityCallback(element));
        d3.select(`#${this.nodeId(true)}`).on('mouseleave', this.toggleVisibilityCallback(element));
    }

    disableZoom(element: SVGAElement): void {
        d3.select(element).on('mousedown', () => {
            (<MouseEvent>d3.event).stopPropagation();
        })
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    static render(layer: d3.Selection<any>, tooltips: Tooltip[]): d3.Selection<Tooltip> {
        const tooltip = layer.selectAll('.tooltip')
            .data(tooltips)
            .enter()
            .append('g')
            .attr('visibility', (d) => d.visibility)
            .attr('class', (d) => d.class())
            .attr('transform', (d) => d.transform());

        tooltip.each(function (d) {
            Tooltip.appendText(this)
{'fraction_non_alphanumeric': 0.15264376688537246, 'fraction_numerical': 0.005789270551910459, 'mean_word_length': 2.372153545868575, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4767414', 'n_tokens_mistral': 1546, 'n_tokens_neox': 1495, 'n_words': 293}