<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Plato - components/Logbook/NewOrEditEventPanel.js</title>

  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="">
  <meta name="author" content="">

  <!--[if lt IE 9]>
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->

  <link href="../../assets/css/vendor/morris.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/bootstrap.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/font-awesome.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/codemirror.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/plato.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/plato-file.css" rel="stylesheet" type="text/css">

</head>

<body>

<div class="navbar navbar-fixed-top">
  <div class="container">
    <a class="navbar-brand" href="https://github.com/the-simian/es6-plato">ES6 Plato on Github</a>
    <ul class="nav navbar-nav">
      <li>
        <a href="../../index.html">Report Home</a>
      </li>
      <li class="active">
        <a href="display.html">Summary Display</a>
      </li>
    </ul>
  </div>
</div>

<div class="jumbotron">
  <div class="container">
    <h1>components/Logbook/NewOrEditEventPanel.js</h1>
  </div>
</div>

<div class="container aggregate-stats">
  <div class="row">
    <div class="col-md-6">
      <h2 class="header">Maintainability <a href="http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="A value between 0 and 100 that represents the relative ease of maintaining the code. A high value means better maintainability." data-original-title="Maintainability Index"  data-container="body"></i></a></h2>
      <p class="stat">65.41</p>
    </div>
    <div class="col-md-6">
      <h2 class="header">Lines of code <i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Source Lines of Code / Logical Lines of Code" data-original-title="SLOC/LSLOC" data-container="body"></i></h2>
      <p class="stat">212</p>
    </div>
  </div>
  <div class="row historical">
    <div class="col-md-6">
      <p id="chart_historical_maint" class="chart"></p>
    </div>
    <div class="col-md-6">
      <p id="chart_historical_sloc" class="chart"></p>
    </div>
  </div>
  <div class="row">
    <div class="col-md-6">
      <h2 class="header">Difficulty  <a href="http://en.wikipedia.org/wiki/Halstead_complexity_measures"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="The difficulty measure is related to the difficulty of the program to write or understand." data-original-title="Difficulty" data-container="body"></i></a></h2>
      <p class="stat">37.08</p>
    </div>
    <div class="col-md-6">
      <h2 class="header">Estimated Errors  <a href="http://en.wikipedia.org/wiki/Halstead_complexity_measures"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Halstead's delivered bugs is an estimate for the number of errors in the implementation." data-original-title="Delivered Bugs" data-container="body"></i></a></h2>
      <p class="stat">1.87</p>
    </div>
  </div>
</div>

<div class="container charts">
  <div class="row">
    <h2 class="header">Function weight</h2>
  </div>
  <div class="row">
    <div class="col-md-6">
      <h3 class="chart-header">By Complexity <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="This metric counts the number of distinct paths through a block of code. Lower values are better." data-original-title="Cyclomatic Complexity" data-container="body"></i></a></h3>
      <div id="fn-by-complexity" class="stat"></div>
    </div>
    <div class="col-md-6">
      <h3 class="chart-header">By SLOC  <i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Source Lines of Code / Logical Lines of Code" data-original-title="SLOC/LSLOC" data-container="body"></i></h3>
      <div id="fn-by-sloc" class="stat"></div>
    </div>
  </div>
</div>

<div class="container">
  <div class="row">
    <textarea id="file-source" class="col-md-12">import React from &#039;react&#039;;
import PropTypes from &#039;prop-types&#039;;
import { Panel, Label, Glyphicon, OverlayTrigger, Tooltip, Button } from &#039;react-bootstrap&#039;;
import EventFooter from &#039;./EventFooter&#039;;
import { EVENT_CATEGORY_COMMENT, ANNOTATION, LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT, LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_HTML_FORMAT, LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT, LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT } from &#039;../../constants/EventTypes&#039;;
import { getContent } from &#039;../../helpers/EventHelpers&#039;;
import _ from &#039;lodash&#039;;
import EventVersions from &#039;./EventVersions&#039;;
import TagsSelectorContainer from &#039;../../containers/Logbook/Tags/TagsSelectorContainer&#039;;
import EditorWrapper from &#039;./EditorWrapper&#039;;
import ReactTimeAgo from &#039;react-time-ago&#039;;
import Moment from &#039;moment&#039;;

import JavascriptTimeAgo from &#039;javascript-time-ago&#039;
import en from &#039;javascript-time-ago/locale/en&#039;
JavascriptTimeAgo.locale(en);


/**
 * React component which renders a Panel for creating of editing an event
 */
class NewOrEditEventPanel extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isSaveButtonEnabled: false, //whether the editor contains some text or not
            isEditorContentValid: false,
            optionPanelDecollaped: false,
            selectedTags: []  // tags which are currently selected
        }

        this.isSaveButtonEnabled = this.isSaveButtonEnabled.bind(this);
        this.onCancelButtonClicked = this.onCancelButtonClicked.bind(this);
        this.onEventContentChanged = this.onEventContentChanged.bind(this);
        this.onSaveButtonClicked = this.onSaveButtonClicked.bind(this);
        this.onTagSelectionChanged = this.onTagSelectionChanged.bind(this);
    }

    render() {
        let { event, user, investigationId } = this.props;

        return &lt;div style={{ display: &#039;flex&#039;, flexDirection: &#039;column&#039;, height: &#039;100%&#039; }}&gt;

            &lt;div style={{ flex: &#039;0 0 33px&#039; }}&gt;
                &lt;Panel bsStyle=&#039;primary&#039; style={{ marginBottom: &#039;0px&#039; }}&gt;
                    &lt;Panel.Heading style={{ padding: &#039;5px 15px&#039; }}&gt;
                        &lt;b&gt;{this.props.event ? &quot;Edit&quot; : &quot;New comment&quot;}&lt;/b&gt;
                        &lt;div className=&quot;pull-right&quot;&gt;
                            &lt;AuthorAndTime event={event} /&gt;
                        &lt;/div&gt;
                    &lt;/Panel.Heading&gt;
                &lt;/Panel&gt;
            &lt;/div&gt;

            &lt;div style={{ flex: &#039;2 2 70%&#039; }}&gt;
                &lt;EditorWrapper
                    event={event}
                    investigationId={investigationId}
                    onContentChanged={this.onEventContentChanged}
                    user={user} /&gt;
            &lt;/div&gt;

            &lt;div style={{ flex: &#039;1 1 32px&#039;, padding: &quot;5px 10px 0px 10px&quot; }}&gt;
                &lt;div style={{ display: &#039;flex&#039; }}&gt;
                    &lt;div style={{ flex: &#039;0 0 70px&#039; }}&gt;
                        &lt;h5 style={{ marginTop: &#039;5px&#039;, marginBottom: &#039;5px&#039; }}&gt;
                            &lt;Label style={{ margin: &#039;0px 6px 0px 0px&#039;, paddingRight: &#039;2px&#039; }}&gt; Tags &lt;/Label&gt;
                            &lt;OverlayTrigger placement=&#039;top&#039;
                                overlay={&lt;Tooltip id=&#039;tooltip&#039;&gt; &lt;p&gt; Manage tags &lt;/p&gt; &lt;/Tooltip&gt;}&gt;
                                &lt;a href={&quot;/investigation/&quot; + this.props.investigationId + &quot;/events/tagManager&quot;} target=&quot;_blank&quot;&gt; &lt;Glyphicon glyph=&#039;cog&#039; /&gt; &lt;/a&gt;
                            &lt;/OverlayTrigger&gt;
                        &lt;/h5&gt;
                    &lt;/div&gt;
                    &lt;div style={{ flex: &#039;1 1 100px&#039; }}&gt;
                        &lt;TagsSelectorContainer 
                            investigationId={this.props.investigationId}
                            onChange={this.onTagSelectionChanged}
                            tags={this.props.event ? this.props.event.tag : []}
                        /&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div &gt;

            &lt;div style={{ flex: &#039;0 0 37px&#039; }}&gt;
                &lt;EventFooter
                    isSaveButtonEnabled={this.isSaveButtonEnabled()}
                    onCancelButtonClicked={() =&gt; this.onCancelButtonClicked()}
                    onSaveButtonClicked={() =&gt; this.onSaveButtonClicked()} /&gt;
            &lt;/div&gt;
        &lt;/div &gt;
    }

    /**
     * Function triggered when the tag selection has changed
     * @param {array} selectedTags tags currently selected by the user on the widget
     */
    onTagSelectionChanged(selectedTags) {
        this.setState({ selectedTags: selectedTags });
    }

    /**
     * Function triggered when the event content has changed
     */
    onEventContentChanged() {
        let isEditorContentValid = false;

        if (this.props.event) { //editing an event
            let currentTextInEditionMode = localStorage.getItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT + this.props.event._id)
            isEditorContentValid = (currentTextInEditionMode !== &quot;&quot; &amp;&amp; currentTextInEditionMode !== getContent(this.props.event.content, &#039;plainText&#039;));
        } else { //creating an event
            let currentTextInCreationMode = localStorage.getItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT);
            isEditorContentValid = currentTextInCreationMode !== &quot;&quot;;
        }
        this.setState({ isEditorContentValid: isEditorContentValid })
    }

    /** Enable or disable the save button */
    isSaveButtonEnabled() {
        if (this.props.event) { //editing an event
            return (this.state.isEditorContentValid === true || !_.isEqual(this.props.event.tag.map(tag =&gt; tag._id).sort(), this.state.selectedTags.map(tag =&gt; tag._id).sort()))
        } else { //creating an event
            return (this.state.isEditorContentValid === true)
        }
    }

    /**
     * Callback function triggered when the user clicks on the cancel button
     */
    onCancelButtonClicked() {
        if (this.props.event) { // edition of an event
            this.props.onCancelButtonClicked()
        } else { // creation of an event
            localStorage.removeItem(&#039;plainText&#039;);
            localStorage.removeItem(&#039;HTMLText&#039;);
            this.props.onCancelButtonClicked();
        }
    }

    /**
     * Callback function triggered when the user click the save button while an event is being created or updated.
     */
    onSaveButtonClicked() {
        let currentTagIds = this.state.selectedTags.map(tag =&gt; tag._id);
        if (this.props.event) { // edition of an event
            let { event, user } = this.props;

            this.props.onSaveButtonClicked({
                _id: event._id,
                category: event.category,
                content: [
                    { format: &#039;plainText&#039;, text: localStorage.getItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT + event._id) },
                    { format: &#039;html&#039;, text: localStorage.getItem(LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT + event._id) }
                ],
                creationDate: Date(),
                type: event.type,
                tag: currentTagIds,
                title: null,
                username: user.username,
                previousVersionEvent: event._id
            });
        } else { // creation of an event
            this.props.onSaveButtonClicked({
                category: EVENT_CATEGORY_COMMENT,
                content: [
                    { format: &quot;plainText&quot;, text: localStorage.getItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_PLAINTEXT_FORMAT) },
                    { format: &quot;html&quot;, text: localStorage.getItem(LOCALSTORAGE_KEY_NEW_EVENT_CONTENT_IN_HTML_FORMAT) }
                ],
                creationDate: Date(),
                investigationId: this.props.investigationId,
                title: null,
                tag: currentTagIds,
                type: ANNOTATION,
                username: this.props.user.username,
            })
        }
    }
}


/** Render author and time */
const AuthorAndTime = props =&gt; {
    if (props.event) {
        return &lt;h5 style={{ marginTop: &#039;0px&#039;, marginBottom: &#039;0px&#039; }}&gt;
            &lt;small style={{ color: &#039;white&#039; }}&gt; &lt;em&gt;
                @{props.event.username} - &lt;ReactTimeAgo date={Moment(props.event.creationDate).toDate()} /&gt;
                &lt;OverlayTrigger
                    trigger=&#039;click&#039; placement=&#039;bottom&#039; overlay={EventVersions(props.event)} rootClose={true} &gt;
                    &lt;div style={{ display: &#039;inline-block&#039; }}&gt;
                        &lt;Button bsStyle=&#039;link&#039; bsSize=&#039;xs&#039;&gt; &lt;Glyphicon glyph=&#039;cog&#039; style={{ color: &#039;white&#039; }} /&gt; &lt;/Button&gt;
                    &lt;/div&gt;
                &lt;/OverlayTrigger&gt;
            &lt;/em&gt; &lt;/small&gt;
        &lt;/h5&gt;
    }
    return null;
}

NewOrEditEventPanel.propTypes = {
    /* event to edit. Null when a new event is being created. */
    event: PropTypes.object,
    /* investigation identifier */
    investigationId: PropTypes.string,
    /** Function triggered when the user clicks on the save button during event creation or edition*/
    onSaveButtonClicked: PropTypes.func,
    /** Function triggered when the user hits the cancel button */
    onCancelButtonClicked : PropTypes.func,
    /* User who is using this component */
    user: PropTypes.object,
}

export default NewOrEditEventPanel;</textarea>
  </div>
</div>

<footer class="footer">
  <div class="container">
    <p>.</p>
  </div>
</footer>

<script type="text/html" id="complexity-popover-template">
  <div class="complexity-notice">
    Complexity : {{ complexity.cyclomatic }} <br>
    Length : {{ complexity.halstead.length }} <br>
    Difficulty : {{ complexity.halstead.difficulty.toFixed(2) }} <br>
    Est # bugs : {{ complexity.halstead.bugs.toFixed(2) }}<br>
  </div>
</script>

<script type="text/javascript" src="../../assets/scripts/bundles/core-bundle.js"></script>
<script type="text/javascript" src="../../assets/scripts/bundles/codemirror.js"></script>
<script type="text/javascript" src="../../assets/scripts/codemirror.markpopovertext.js"></script>
<script type="text/javascript" src="report.js"></script>
<script type="text/javascript" src="report.history.js"></script>
<script type="text/javascript" src="../../assets/scripts/plato-file.js"></script>
</body>
</html>
