<commit_before>import React from "react";
import PropTypes from "prop-types";
import { FormControl } from "react-bootstrap";
import { Flex, FlexItem, Button } from "./index";

/**
 * An Input component combined with a save button addon.
 */
export class InputSave extends React.Component {

    constructor (props) {
        super(props);
        this.state = {
            value: this.props.initialValue,
            pending: false
        };
    }

    static propTypes = {
        name: PropTypes.string,
        onSave: PropTypes.func.isRequired,
        label: PropTypes.string,
        type: PropTypes.string,
        min: PropTypes.number,
        max: PropTypes.number,
        step: PropTypes.number,
        initialValue: PropTypes.any,
        autoComplete: PropTypes.bool,
        onInvalid: PropTypes.func,
        onChange: PropTypes.func,
        disabled: PropTypes.bool,
        noMargin: PropTypes.bool,
        error: PropTypes.string
    };

    static defaultProps = {
        initialValue: "",
        autoComplete: true
    };

    componentWillReceiveProps (nextProps) {
        // If the initialValue has changed. Remove the pending state on the component. This will remove the spinner on
        // the save button and enable the Input component again.
        if (nextProps.initialValue !== this.props.initialValue) {
            this.setState({
                pending: false,
                value: nextProps.initialValue
            });
        }
    }

    /**
     * Resets the setting value to the initialValue if the form component loses focus. Clicking the saveButton does not
     * make the form lose focus. The form is intentionally blurred once an updated initialValue is received in props.
     */
    handleBlur = (e) => {
        // If click on focus element that does not submit, reset value
        if (!this.state.pending && e.relatedTarget && e.relatedTarget.type !== "submit") {
            this.setState({value: this.props.initialValue});
        // If click on non focus element, reset value
        } else if (!e.relatedTarget) {
            this.setState({value: this.props.initialValue});
        }
        // If click on focus element that does submit, keep value
        this.props.onChange(e);
    };

    /**
     * Handle the data from a change in the input element. Updates state to reflect what is being typed by the user.
     *
     * @param event {event} - the change event from the FormControl
     */
    handleChange = (e) => {
        if (!this.props.disabled) {
            this.setState({value: e.target.value});
        }
        this.props.onChange(e);
    };

    /**<commit_msg>Fix InputSave bug when missing onChange() prop<commit_after>import React from "react";
import PropTypes from "prop-types";
import { FormControl } from "react-bootstrap";
import { Flex, FlexItem, Button } from "./index";

/**
 * An Input component combined with a save button addon.
 */
export class InputSave extends React.Component {

    constructor (props) {
        super(props);
        this.state = {
            value: this.props.initialValue,
            pending: false
        };
    }

    static propTypes = {
        name: PropTypes.string,
        onSave: PropTypes.func.isRequired,
        label: PropTypes.string,
        type: PropTypes.string,
        min: PropTypes.number,
        max: PropTypes.number,
        step: PropTypes.number,
        initialValue: PropTypes.any,
        autoComplete: PropTypes.bool,
        onInvalid: PropTypes.func,
        onChange: PropTypes.func,
        disabled: PropTypes.bool,
        noMargin: PropTypes.bool,
        error: PropTypes.string
    };

    static defaultProps = {
        initialValue: "",
        autoComplete: true
    };

    componentWillReceiveProps (nextProps) {
        // If the initialValue has changed. Remove the pending state on the component. This will remove the spinner on
        // the save button and enable the Input component again.
        if (nextProps.initialValue !== this.props.initialValue) {
            this.setState({
                pending: false,
                value: nextProps.initialValue
            });
        }
    }

    /**
     * Resets the setting value to the initialValue if the form component loses focus. Clicking the saveButton does not
     * make the form lose focus. The form is intentionally blurred once an updated initialValue is received in props.
     */
    handleBlur = (e) => {
        // If click on focus element that does not submit, reset value
        if (!this.state.pending && e.relatedTarget && e.relatedTarget.type !== "submit") {
            this.setState({value: this.props.initialValue});
        // If click on non focus element, reset value
        } else if (!e.relatedTarget) {
            this.setState({value: this.props.initialValue});
        }

        // If click on focus element that does submit, keep value
        if (this.props.onChange) {
            this.props.onChange(e);
        }
    };

    /**
     * Handle the data from a change in the input element. Updates state to reflect what is being typed by the user.
     *
     * @param event {event} - the change event from the FormControl
     */
    handleChange = (e) => {
        if (!this.props.disabled) {
            this.setState({value: e.target.value});
        }

        if (this.props.onChange) {
            this.props.onChange(e);
        }
    };

    /**
{'fraction_non_alphanumeric': 0.09755199705503405, 'fraction_numerical': 0.0, 'mean_word_length': 2.0927717700626065, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '3286534', 'n_tokens_mistral': 1407, 'n_tokens_neox': 1419, 'n_words': 468}