<commit_before>/* Copyright (C) 2017 Canonical Ltd. */
'use strict';

const PropTypes = require('prop-types');
const React = require('react');

const SvgIcon = require('../svg-icon/svg-icon');
/**
  A single accordion section, with clickable header and collapsable content.
  Providing a height will animate the opening and closing.
*/
class AccordionSection extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: this.props.startOpen
    };
  }

  /**
    Toggles the collapsable content section.
  */
  _toggle() {
    this.setState({open: !this.state.open});
  }

  /**
    Get's the content style based on some rules.

    @return {Object} Object of CSS styles.
  */
  _getStyle() {
    const content = this['accordion-section-content'];
    // If the content does not yet exist then set it to a very high number so
    // that the content does not get cut off.
    const scrollHeight = content ? content.scrollHeight : 9999999;
    return {
      maxHeight: this.state.open ? scrollHeight + 'px' : 0
    };
  }

  /**
    Generates the clickable title element.

    @return {Object} The React div element.
  */
  _generateTitle() {
    if (!this.props.title) {
      return null;
    }
    const chevron = this.state.open ?
      'chevron_up_16' : 'chevron_down_16';
    const icon = this.props.children ? (
      <SvgIcon
        name={chevron}
        size="16" className="right" />) : null;
    const role = this.props.children ? 'button' : null;
    const onClick = this.props.children ? this._toggle.bind(this) : null;
    return (<div
      role={role}
      className="accordion-section__title"
      onClick={onClick}>
      <span className="accordion-section__title-content">
        {this.props.title}
      </span>
      {icon}
    </div>);
  }

  /**
    The callback for after the content has been mounted/unmounted.
    @param content {Object} The content element that was (un)mounted.
  */
  _contentRefCallback(content) {
    this['accordion-section-content'] = content;
    // This gets called on mount and unmount, so the div won't exist
    // on unmount, nor do we wish to update the max-height.
    if (content && this.props.startOpen) {
      // After the div is mounted then set the max-height to the actual
      // height of the div. This is only required when the section starts
      // expanded as the div does not exist when the first max-height
      // calculation is made.
      this['accordion-section-content'].style.maxHeight = this._getStyle().maxHeight;
    }
  }

  /**
    Generates the content from the components children.

    @return {Object} The React div element.
  */
  _generateContent() {
    return (<div className="accordion-section__content"
      ref={this._contentRefCallback.bind(this)}
      style={this._getStyle()}>
      {this.props.children}
    </div>);
  }

  render() {
    return (
      <div className="accordion-section">
        {this._generateTitle()}
        {this._generateContent()}
      </div>
    );
  }
};

AccordionSection.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  startOpen: PropTypes.bool,
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ])
};

module.exports = AccordionSection;
<commit_msg>Move max-height update to componentDidMount<commit_after>/* Copyright (C) 2017 Canonical Ltd. */
'use strict';

const PropTypes = require('prop-types');
const React = require('react');

const SvgIcon = require('../svg-icon/svg-icon');
/**
  A single accordion section, with clickable header and collapsable content.
  Providing a height will animate the opening and closing.
*/
class AccordionSection extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: this.props.startOpen
    };
  }

  componentDidMount() {
    // After the div is mounted then set the max-height to the actual
    // height of the div. This is only required when the section starts
    // expanded as the div does not exist when the first max-height
    // calculation is made.
    if (this.props.startOpen) {
      const styles = this._getStyle();
      this['accordion-section-content'].style.maxHeight = styles.maxHeight;
    }
  }

  /**
    Toggles the collapsable content section.
  */
  _toggle() {
    this.setState({open: !this.state.open});
  }

  /**
    Get's the content style based on some rules.

    @return {Object} Object of CSS styles.
  */
  _getStyle() {
    const content = this['accordion-section-content'];
    // If the content does not yet exist then set it to a very high number so
    // that the content does not get cut off.
    const scrollHeight = content ? content.scrollHeight : 9999999;
    return {
      maxHeight: this.state.open ? scrollHeight + 'px' : 0
    };
  }

  /**
    Generates the clickable title element.

    @return {Object} The React div element.
  */
  _generateTitle() {
    if (!this.props.title) {
      return null;
    }
    const chevron = this.state.open ?
      'chevron_up_16' : 'chevron_down_16';
    const icon = this.props.children ? (
      <SvgIcon
        name={chevron}
        size="16" className="right" />) : null;
    const role = this.props.children ? 'button' : null;
    const onClick = this.props.children ? this._toggle.bind(this) : null;
    return (<div
      role={role}
      className="accordion-section__title"
      onClick={onClick}>
      <span className="accordion-section__title-content">
        {this.props.title}
      </span>
      {icon}
    </div>);
  }

  /**
    Generates the content from the components children.

    @return {Object} The React div element.
  */
  _generateContent() {
    return (<div className="accordion-section__content"
      ref={(div) => { this['accordion-section-content'] = div; }}
      style={this._getStyle()}>
      {this.props.children}
    </div>);
  }

  render() {
    return (
      <div className="accordion-section">
        {this._generateTitle()}
        {this._generateContent()}
      </div>
    );
  }
};

AccordionSection.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  startOpen: PropTypes.bool,
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ])
};

module.exports = AccordionSection;

{'fraction_non_alphanumeric': 0.12343922870238659, 'fraction_numerical': 0.005689900426742532, 'mean_word_length': 2.731132075471698, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, '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': '6205243', 'n_tokens_mistral': 1951, 'n_tokens_neox': 1897, 'n_words': 532}