<commit_before>import _ from 'lodash';
import React, { Component, PropTypes } from 'react';
import ReactDom from 'react-dom';
import { Motion, spring } from 'react-motion';
import Draggable from './Draggable';
import TextArea from './Textarea';
import Mouse from '../constants/mouse';

const Paper = require('material-ui/lib/paper');
const FlatButton = require('material-ui/lib/flat-button');

const MOUSE_CLICK_DELAY = 100; // ms
const CONTENTS_CHANGE_DELAY = 200; // ms
const DIMENSION_CHANGE_DELAY = 200; // ms

/**
 * Draggable, resizable, editable and deletable note component
 */
export default class Note extends Component {
  constructor(props) {
    super(props);
    this.state = { isEditing: false };

    // Throttle the callback functions for keeping the application performant

    this._throttledOnContentsChange = _.throttle(
      this.props.onContentsChange, CONTENTS_CHANGE_DELAY
    );

    this._throttledOnPositionChange = _.throttle(
      this.props.onPositionChange, DIMENSION_CHANGE_DELAY
    );

    this._throttledOnSizeChange = _.throttle(
      this.props.onSizeChange, DIMENSION_CHANGE_DELAY
    );

    this.onMouseDown = (e) => this._onMouseDown(e);
  }

  componentWillUnmount() {
    // Don't leak event listeners
    document.removeEventListener('mousedown', this.onMouseDown);
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (this.props.position.x !== nextProps.position.x ||
            this.props.position.y !== nextProps.position.y ||
            this.props.size.x !== nextProps.size.x ||
            this.props.size.y !== nextProps.size.y ||
            this.props.contents !== nextProps.contents ||
            this.state.isEditing !== nextState.isEditing);
  }

  render() {
    let { id, size, position, contents, onDelete } = this.props;
    let { isEditing } = this.state;

    let noteStyle = {
      position: 'absolute',
      cursor: 'pointer',
      opacity: '0.8',
      backgroundColor: '#E0F2F1'
    };

    let idStyle = {
      position: 'absolute',
      left: '5px',
      top: '2px',
      color: '#26A69A',
      fontSize: '12px'
    };

    let deleteButtonStyle = {
      position: 'absolute',
      right: '5px',
      top: '3px',
      fontSize: '10px',
      lineHeight: '25px',
      minWidth: '15px'
    };

    if (!isEditing) {
      deleteButtonStyle['display'] = 'none';
      idStyle['display'] = 'none';
    }

    return (
      <Motion style={{
                      x: spring(position.x, [120, 17]),
                      y: spring(position.y, [120, 17]),
                      width: spring(size.width, [60, 7]),
                      height: spring(size.height, [60, 7])
                     }}>
        { interpolation =>
          <Draggable initialPosition={{x: interpolation.x,
                                       y: interpolation.y}}
                     initialSize={{width: interpolation.width,
                                   height: interpolation.height}}
                     style={noteStyle}
                     onMove={position => this._onMove(position)}
                     onResize={size => this._onResize(size)}>
            <Paper style={{width: '100%', height: '100%'}}
                   onMouseDown={e => this.onMouseDown(e)}
                   onMouseUp={() => this._startEditing()}>
              <div style={idStyle}>#{id}</div>
              <TextArea
                isEditing={isEditing}
                value={contents}
                onChange={contents => this._onContentsChange(contents)} />
              <FlatButton style={deleteButtonStyle}
                          secondary={true}
                          label="X"
                          onClick={() => onDelete(id)} />
            </Paper>
          </Draggable>
        }
      </Motion>
    );
  }

  _onResize(size) {
    this._throttledOnSizeChange(size);
  }

  _onMove(position) {
    this._throttledOnPositionChange(position);
  }

  _onContentsChange(contents) {
    this._throttledOnContentsChange(contents);
  }

  _onMouseDown(e) {
    if (e.button !== Mouse.LEFT_BUTTON) {
      return;
    }

    this._mouseDownTime = new Date();

    // FIXME: This most likely fails if the render function is changed :-)
    //        Anyway, the idea is to stop editing if click was outside of
    //        the note.<commit_msg>Improve rendering performance even more<commit_after>import _ from 'lodash';
import React, { Component, PropTypes } from 'react';
import ReactDom from 'react-dom';
import { Motion, spring } from 'react-motion';
import Draggable from './Draggable';
import TextArea from './Textarea';
import Mouse from '../constants/mouse';

const FlatButton = require('material-ui/lib/flat-button');

const MOUSE_CLICK_DELAY = 100; // ms
const CONTENTS_CHANGE_DELAY = 200; // ms
const DIMENSION_CHANGE_DELAY = 200; // ms

/**
 * Draggable, resizable, editable and deletable note component
 */
export default class Note extends Component {
  constructor(props) {
    super(props);
    this.state = { isEditing: false };

    // Throttle the callback functions for keeping the application performant

    this._throttledOnContentsChange = _.throttle(
      this.props.onContentsChange, CONTENTS_CHANGE_DELAY
    );

    this._throttledOnPositionChange = _.throttle(
      this.props.onPositionChange, DIMENSION_CHANGE_DELAY
    );

    this._throttledOnSizeChange = _.throttle(
      this.props.onSizeChange, DIMENSION_CHANGE_DELAY
    );

    this.onMouseDown = (e) => this._onMouseDown(e);
  }

  componentWillUnmount() {
    // Don't leak event listeners
    document.removeEventListener('mousedown', this.onMouseDown);
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (this.props.position.x !== nextProps.position.x ||
            this.props.position.y !== nextProps.position.y ||
            this.props.size.width !== nextProps.size.width ||
            this.props.size.height !== nextProps.size.height ||
            this.props.contents !== nextProps.contents ||
            this.state.isEditing !== nextState.isEditing);
  }

  render() {
    let { id, size, position, contents, onDelete } = this.props;
    let { isEditing } = this.state;

    let noteStyle = {
      position: 'absolute',
      cursor: 'pointer',
      backgroundColor: '#E0F2F1',
      boxShadow: '1px'
    };

    let idStyle = {
      position: 'absolute',
      left: '5px',
      top: '2px',
      color: '#26A69A',
      fontSize: '12px'
    };

    let deleteButtonStyle = {
      position: 'absolute',
      right: '5px',
      top: '3px',
      fontSize: '10px',
      lineHeight: '25px',
      minWidth: '15px'
    };

    return (
      <Motion style={{
                      x: spring(position.x, [120, 17]),
                      y: spring(position.y, [120, 17]),
                      width: spring(size.width, [60, 7]),
                      height: spring(size.height, [60, 7])
                     }}>
        { interpolation =>
          <Draggable initialPosition={{x: interpolation.x,
                                       y: interpolation.y}}
                     initialSize={{width: interpolation.width,
                                   height: interpolation.height}}
                     style={noteStyle}
                     onMove={position => this._onMove(position)}
                     onResize={size => this._onResize(size)}>
            <div style={{width: '100%', height: '100%'}}
                 onMouseDown={e => this.onMouseDown(e)}
                 onMouseUp={() => this._startEditing()}>
              { isEditing ? <div style={idStyle}>#{id}</div> : undefined }
              <TextArea
                isEditing={isEditing}
                value={contents}
                onChange={contents => this._onContentsChange(contents)} />
              { isEditing ? <FlatButton style={deleteButtonStyle}
                                        secondary={true}
                                        label="X"
                                        onClick={() => onDelete(id)} /> :
                            undefined }
            </div>
          </Draggable>
        }
      </Motion>
    );
  }

  _onResize(size) {
    this._throttledOnSizeChange(size);
  }

  _onMove(position) {
    this._throttledOnPositionChange(position);
  }

  _onContentsChange(contents) {
    this._throttledOnContentsChange(contents);
  }

  _onMouseDown(e) {
    if (e.button !== Mouse.LEFT_BUTTON) {
      return;
    }

    this._mouseDownTime = new Date();

    // FIXME: This most likely fails if the render function is changed :-)
    //        Anyway, the idea is to stop editing if click was outside of
    //        the note.
{'fraction_non_alphanumeric': 0.1260834392696175, 'fraction_numerical': 0.011903386108863977, 'mean_word_length': 2.038623595505618, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '646888', 'n_tokens_mistral': 2593, 'n_tokens_neox': 2469, 'n_words': 524}