<commit_before>import React, { Component, PropTypes } from "react";

import OnClickOutsideWrapper from "./OnClickOutsideWrapper.react";
import Tether from "tether";

import cx from "classnames";

export default class Popover extends Component {
    constructor(props) {
        super(props);

        this.handleClickOutside = this.handleClickOutside.bind(this);
    }

    componentWillMount() {
        this._popoverElement = document.createElement('span');
        this._popoverElement.className = 'PopoverContainer';
        this._popoverElement.id = Math.floor((Math.random() * 698754) + 1);
        document.querySelector('body').appendChild(this._popoverElement);
    }

    componentDidMount() {
        this._renderPopover();
    }

    componentDidUpdate() {
        this._renderPopover();
    }

    componentWillUnmount() {
        if (this._tether) {
            this._tether.destroy();
            delete this._tether;
        }
        React.unmountComponentAtNode(this._popoverElement);
        if (this._popoverElement.parentNode) {
            this._popoverElement.parentNode.removeChild(this._popoverElement);
        }
    }

    handleClickOutside(...args) {
        if (this.props.onClose) {
            this.props.onClose(...args)
        }
    }

    _popoverComponent() {
        return (
            <OnClickOutsideWrapper handleClickOutside={this.handleClickOutside}>
                <div className={cx("PopoverBody", { "PopoverBody--withArrow": this.props.hasArrow }, this.props.className)}>
                    {this.props.children}
                </div>
            </OnClickOutsideWrapper>
        );
    }

    _setTetherOptions(tetherOptions) {
        if (this._tether) {
            this._tether.setOptions(tetherOptions);
        } else {
            this._tether = new Tether(tetherOptions);
        }
    }

    _renderPopover() {
        if (this.props.isOpen) {
            // popover is open, lets do this!
            React.render(
                <div className="Popover-backdrop">
                    {this._popoverComponent()}
                </div>
            , this._popoverElement);

            var tetherOptions = {};

            tetherOptions.element = this._popoverElement;

            if (!tetherOptions.target && this.props.getTriggerTarget) {
                tetherOptions.target = React.findDOMNode(this.props.getTriggerTarget());
            }
            if (!tetherOptions.target) {
                tetherOptions.target = React.findDOMNode(this).parentNode;
            }

            if (this.props.tetherOptions) {
                this._setTetherOptions({
                    ...tetherOptions,
                    ...this.props.tetherOptions
                });
            } else {
                for (let attachmentX of ["center", "left", "right"]) {
                    let [offsetY, offsetX] = [5, 0];
                    if (attachmentX === "left") {
                        offsetX = -(offsetX + 24);
                    } else if (attachmentX === "right") {
                        offsetX = offsetX + 24;
                    }
                    this._setTetherOptions({
                        ...tetherOptions,
                        attachment: "top " + attachmentX,
                        targetAttachment: "bottom center",
                        targetOffset: [offsetY, offsetX].map(o => o + "px").join(" "),
                        constraints: [{ to: 'window', attachment: 'together', pin: ['top', 'bottom']}]
                    });
                    let elementRect = Tether.Utils.getBounds(tetherOptions.element);
                    let obscured = Math.min(elementRect.left, 0) + Math.min(elementRect.right, 0);
                    if (obscured === 0) {
                        break;
                    }
                }
            }
        } else {
            // if the popover isn't open then actively unmount our popover
            React.unmountComponentAtNode(this._popoverElement);
        }
    }

    render() {
        return <span className="hide" />;
    }
}

Popover.propTypes = {
    isOpen: PropTypes.bool,
    hasArrow: PropTypes.bool,
    getTriggerTarget: PropTypes.func,
    tetherOptions: PropTypes.object
};

Popover.defaultProps = {
    isOpen: true,
    hasArrow: true
};<commit_msg>Fix Popover positioning issue due to use of constraints while testing positions<commit_after>import React, { Component, PropTypes } from "react";

import OnClickOutsideWrapper from "./OnClickOutsideWrapper.react";
import Tether from "tether";

import cx from "classnames";

export default class Popover extends Component {
    constructor(props) {
        super(props);

        this.handleClickOutside = this.handleClickOutside.bind(this);
    }

    componentWillMount() {
        this._popoverElement = document.createElement('span');
        this._popoverElement.className = 'PopoverContainer';
        this._popoverElement.id = Math.floor((Math.random() * 698754) + 1);
        document.querySelector('body').appendChild(this._popoverElement);
    }

    componentDidMount() {
        this._renderPopover();
    }

    componentDidUpdate() {
        this._renderPopover();
    }

    componentWillUnmount() {
        if (this._tether) {
            this._tether.destroy();
            delete this._tether;
        }
        React.unmountComponentAtNode(this._popoverElement);
        if (this._popoverElement.parentNode) {
            this._popoverElement.parentNode.removeChild(this._popoverElement);
        }
    }

    handleClickOutside(...args) {
        if (this.props.onClose) {
            this.props.onClose(...args)
        }
    }

    _popoverComponent() {
        return (
            <OnClickOutsideWrapper handleClickOutside={this.handleClickOutside}>
                <div className={cx("PopoverBody", { "PopoverBody--withArrow": this.props.hasArrow }, this.props.className)}>
                    {this.props.children}
                </div>
            </OnClickOutsideWrapper>
        );
    }

    _setTetherOptions(tetherOptions) {
        if (this._tether) {
            this._tether.setOptions(tetherOptions);
        } else {
            this._tether = new Tether(tetherOptions);
        }
    }

    _renderPopover() {
        if (this.props.isOpen) {
            // popover is open, lets do this!
            React.render(
                <div className="Popover-backdrop">
                    {this._popoverComponent()}
                </div>
            , this._popoverElement);

            var tetherOptions = {};

            tetherOptions.element = this._popoverElement;

            if (!tetherOptions.target && this.props.getTriggerTarget) {
                tetherOptions.target = React.findDOMNode(this.props.getTriggerTarget());
            }
            if (!tetherOptions.target) {
                tetherOptions.target = React.findDOMNode(this).parentNode;
            }

            if (this.props.tetherOptions) {
                this._setTetherOptions({
                    ...tetherOptions,
                    ...this.props.tetherOptions
                });
            } else {
                let bestOptions;
                let bestOffScreen = -Infinity;
                for (let attachmentX of ["center", "left", "right"]) {
                    let [offsetY, offsetX] = [5, 0];
                    if (attachmentX === "left") {
                        offsetX = -(offsetX + 24);
                    } else if (attachmentX === "right") {
                        offsetX = (offsetX + 24);
                    }
                    let options = {
                        ...tetherOptions,
                        attachment: "top " + attachmentX,
                        targetAttachment: "bottom center",
                        targetOffset: [offsetY, offsetX].map(o => o + "px").join(" ")
                    }
                    this._setTetherOptions(options);
                    // test to see how much of the popover is off-screen
                    let elementRect = Tether.Utils.getBounds(tetherOptions.element);
                    let offScreen = Math.min(elementRect.left, 0) + Math.min(elementRect.right, 0);
                    if (offScreen === 0) {
                        bestOptions = options;
                        break;
                    } else if (offScreen > bestOffScreen) {
                        bestOptions = options;
                        bestOffScreen = offScreen;
                    }
                }
                // re-set the best options with constraints (setting constraints aboves messes with positioning)
                this._setTetherOptions({
                    ...bestOptions,
                    constraints: [{ to: 'window', attachment: 'together', pin: ['top', 'bottom']}]
                });
            }
        } else {
            // if the popover isn't open then actively unmount our popover
            React.unmountComponentAtNode(this._popoverElement);
        }
    }

    render() {
        return <span className="hide" />;
    }
}

Popover.propTypes = {
    isOpen: PropTypes.bool,
    hasArrow: PropTypes.bool,
    getTriggerTarget: PropTypes.func,
    tetherOptions: PropTypes.object
};

Popover.defaultProps = {
    isOpen: true,
    hasArrow: true
};
{'fraction_non_alphanumeric': 0.11022519125094278, 'fraction_numerical': 0.0034479043206551018, 'mean_word_length': 1.6146478873239436, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 20, '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': '1070096', 'n_tokens_mistral': 2485, 'n_tokens_neox': 2365, 'n_words': 450}