<commit_before>var _ = require('lodash');

var React = require('react');

var MessagesSection = require('./dialog/MessagesSection.react');
var ComposeSection = require('./dialog/ComposeSection.react');

var DialogStore = require('../stores/DialogStore');
var MessageStore = require('../stores/MessageStore');

var initialMessagesCount = 100;

var getStateFromStores = function() {
  var messages = MessageStore.getAll();

  var messagesToRender;

  if (messages.length > initialMessagesCount) {
    messagesToRender = messages.slice(messages.length - initialMessagesCount);
  } else {
    messagesToRender = messages;
  }

  return({
    dialog: DialogStore.getSelectedDialog(),
    messages: messages,
    messagesToRender: messagesToRender
  });
};

var DialogSection = React.createClass({
  getInitialState: function() {
    return(getStateFromStores());
  },

  componentDidMount: function() {
    DialogStore.addSelectListener(this._onChange);
    MessageStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    MessageStore.removeChangeListener(this._onChange);
    DialogStore.removeSelectListener(this._onChange);
  },

  render: function() {
    if (this.state.dialog) {
      return (
        <section className="dialog">
          <MessagesSection peer={this.state.dialog.peer.peer} messages={this.state.messagesToRender} ref="MessagesSection"/>
          <ComposeSection dialog={this.state.dialog}/>
        </section>
      )
    } else {
      return(
        <section className="dialog"></section>
      )
    }
  },

  _scrollToBottom: function() {
    var ul = this.refs.MessagesSection.getDOMNode();
    ul.scrollTop = ul.scrollHeight;
  },

  _scrollToBottomDebounced: _.debounce(function() {
    this._scrollToBottom();
  }, 50),

  _scrolledToBottom: function() {
    var self = this.getDOMNode();

    return(self.scrollHeight - self.scrollTop - self.clientHeight == 0);
  },

  _onChange: _.debounce(function() {
    this.setState(getStateFromStores());

    if (this._scrolledToBottom()) {
      this._scrollToBottomDebounced()
    }
  }, 30, 300)
});

module.exports = DialogSection;
<commit_msg>feat(web): load messages on scroll top<commit_after>var _ = require('lodash');

var React = require('react');

var MessagesSection = require('./dialog/MessagesSection.react');
var ComposeSection = require('./dialog/ComposeSection.react');

var DialogStore = require('../stores/DialogStore');
var MessageStore = require('../stores/MessageStore');

var _renderMessagesStep = 100;
var _renderMessagesCount = 100;

var getStateFromStores = function() {
  var messages = MessageStore.getAll();

  var messagesToRender;

  if (messages.length > _renderMessagesCount) {
    messagesToRender = messages.slice(messages.length - _renderMessagesCount);
  } else {
    messagesToRender = messages;
  }

  return({
    dialog: DialogStore.getSelectedDialog(),
    messages: messages,
    messagesToRender: messagesToRender
  });
};

var _lastScrolledFromBottom = 0;

var DialogSection = React.createClass({
  getInitialState: function() {
    return(getStateFromStores());
  },

  componentDidMount: function() {
    DialogStore.addSelectListener(this._onChange);
    MessageStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    MessageStore.removeChangeListener(this._onChange);
    DialogStore.removeSelectListener(this._onChange);
  },

  componentDidUpdate: function() {
    this._fixScroll()
  },

  render: function() {
    if (this.state.dialog) {
      return (
        <section className="dialog" onScroll={this._onScroll}>
          <MessagesSection peer={this.state.dialog.peer.peer}
                           messages={this.state.messagesToRender}
                           ref="MessagesSection"/>
          <ComposeSection dialog={this.state.dialog}/>
        </section>
      )
    } else {
      return(
        <section className="dialog"></section>
      )
    }
  },

  _fixScroll: function() {
    var node = this.refs.MessagesSection.getDOMNode();
    node.scrollTop = node.scrollHeight - _lastScrolledFromBottom;
  },

  _onChange: _.debounce(function() {
    this.setState(getStateFromStores());
  }, 30, 300),

  _onScroll: _.debounce(function() {
    var node = this.refs.MessagesSection.getDOMNode();

    var scrollTop = node.scrollTop;
    _lastScrolledFromBottom = node.scrollHeight - scrollTop;

    if (node.scrollTop == 0) {
      if (this.state.messages.length > this.state.messagesToRender.length) {
        _renderMessagesCount += _renderMessagesStep;

        if (_renderMessagesCount > this.state.messages.length) {
          _renderMessagesCount = this.state.messages.length;
        }

        this.setState(getStateFromStores());
      }
    }
  }, 10)
});

module.exports = DialogSection;

{'fraction_non_alphanumeric': 0.12905911740216486, 'fraction_numerical': 0.005412156536219817, 'mean_word_length': 3.550189393939394, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 19, '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': '5006444', 'n_tokens_mistral': 1442, 'n_tokens_neox': 1374, 'n_words': 238}