<commit_before>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

var PostStore = require('../stores/post_store.jsx');
var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx');
var UserProfile = require( './user_profile.jsx' );
var AsyncClient = require('../utils/async_client.jsx');
var Post = require('./post.jsx');
var LoadingScreen = require('./loading_screen.jsx');
var SocketStore = require('../stores/socket_store.jsx');
var utils = require('../utils/utils.jsx');
var Client = require('../utils/client.jsx');
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;

function getStateFromStores() {
    var channel = ChannelStore.getCurrent();

    if (channel == null) channel = {};

    return {
        post_list: PostStore.getCurrentPosts(),
        channel: channel
    };
}

module.exports = React.createClass({
    displayName: "PostList",
    scrollPosition: 0,
    preventScrollTrigger: false,   // Can't think of an intuitive name, but when true,
                                   // scrollPosition is affected by the 'on scroll' event below
    gotMorePosts: false,
    oldScrollHeight: 0,
    oldZoom: 0,
    scrolledToNew: false,
    componentDidMount: function() {

        // Add CSS required to have the theme colors
        var user = UserStore.getCurrentUser();
        if (user.props && user.props.theme) {
            utils.changeCss('div.theme', 'background-color:'+user.props.theme+';');
            utils.changeCss('.btn.btn-primary', 'background: ' + user.props.theme+';');
            utils.changeCss('.modal .modal-header', 'background: ' + user.props.theme+';');
            utils.changeCss('.mention', 'background: ' + user.props.theme+';');
            utils.changeCss('.mention-link', 'color: ' + user.props.theme+';');
            utils.changeCss('@media(max-width: 768px){.search-bar__container', 'background: ' + user.props.theme+';}');
        }
        if (user.props.theme != '#000000' && user.props.theme != '#585858') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, -10)  +';');
            utils.changeCss('a.theme', 'color:'+user.props.theme+'; fill:'+user.props.theme+'!important;');
        } else if (user.props.theme == '#000000') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +50)  +';');
            $('.team__header').addClass('theme--black');
        } else if (user.props.theme == '#585858') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +10)  +';');
            $('.team__header').addClass('theme--gray');
        }

        // Start our Store listeners
        PostStore.addChangeListener(this._onChange);
        ChannelStore.addChangeListener(this._onChange);
        UserStore.addStatusesChangeListener(this._onTimeChange);
        SocketStore.addChangeListener(this._onSocketChange);

        // Initialize perfect scrollbar
        $(".post-list-holder-by-time").perfectScrollbar();

        this.resize();

        var post_holder = $(".post-list-holder-by-time")[0];
        this.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
        this.oldScrollHeight = post_holder.scrollHeight;
        this.oldZoom = (window.outerWidth - 8) / window.innerWidth;

        /*************** End of 'run on mount' code, Start of event listeners *****************/

        var self = this;
        $(window).resize(function(){
            $(post_holder).perfectScrollbar('update');

            // this only kind of works, detecting zoom in browsers is a nightmare
            var newZoom = (window.outerWidth - 8) / window.innerWidth;

            if (self.scrollPosition >= post_holder.scrollHeight || (self.oldScrollHeight != post_holder.scrollHeight && self.scrollPosition >= self.oldScrollHeight) || self.oldZoom != newZoom) self.resize();

            self.oldZoom = newZoom;

            if ($('#create_post').length > 0) {
                var height = $(window).height() - $('#create_post').height() - $('#error_bar').outerHeight() - 50;
                $(".post-list-holder-by-time").css("height", height + "px");
            }
        });

        // scrollPosistion records and holds every position that the user has been at
        // Disabled by preventScrollTrigger
        // Consider storing this in localStorage instead
        $(post_holder).scroll(function(e){
            if (!self.preventScrollTrigger) {
                self.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
            }
            self.preventScrollTrigger = false;
        });

        $('body').on('click.userpopover', function(e){
            if ($(e.target).attr('data-toggle') !== 'popover'
                && $(e.target).parents('.popover.in').length === 0) {
                $('.user-popover').popover('hide');
            }
        });

        $('.post-list__content div .post').removeClass('post--last');
        $('.post-list__content div:last-child .post').addClass('post--last');

        $('body').on('mouseenter mouseleave', '.post', function(ev){
            if(ev.type === 'mouseenter'){
                $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
                $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before');
            }
            else {
                $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--after');
                $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--before');
            }
        });

        $('body').on('mouseenter mouseleave', '.post.post--comment.same--root', function(ev){
            if(ev.type === 'mouseenter'){
                $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--comment');
                $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--comment');
            }
            else {
                $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--comment');
                $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--comment');
            }
        });

    },
    componentDidUpdate: function() {
        this.resize();
        var post_holder = $(".post-list-holder-by-time")[0];
        this.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
        this.oldScrollHeight = post_holder.scrollHeight;
        $('.post-list__content div .post').removeClass('post--last');
        $('.post-list__content div:last-child .post').addClass('post--last');
    },
    componentWillUnmount: function() {
        PostStore.removeChangeListener(this._onChange);
        ChannelStore.removeChangeListener(this._onChange);
        UserStore.removeStatusesChangeListener(this._onTimeChange);
        SocketStore.removeChangeListener(this._onSocketChange);
        $('body').off('click.userpopover');
    },
    resize: function() {
        var post_holder = $(".post-list-holder-by-time")[0];
        this.preventScrollTrigger = true;
        if (this.gotMorePosts) {
            this.gotMorePosts = false;
            $(post_holder).scrollTop($(post_holder).scrollTop() + (post_holder.scrollHeight-this.oldScrollHeight) );
        } else if ($("#new_message")[0] && !this.scrolledToNew) {
            $(post_holder).scrollTop($(post_holder).scrollTop() + $("#new_message").offset().top - 63);
            this.scrolledToNew = true;
        } else {
            $(post_holder).scrollTop(post_holder.scrollHeight);
        }
        $(post_holder).perfectScrollbar('update');
    },
    _onChange: function() {
        var newState = getStateFromStores();

        if (!utils.areStatesEqual(newState, this.state)) {
            if (this.state.post_list &&
                this.state.post_list.order &&
                this.state.channel.id === newState.channel.id &&
                this.state.post_list.order.length !== newState.post_list.order.length &&
                newState.post_list.order.length > Constants.POST_CHUNK_SIZE) {
                // Thus marking the end of the conditional
                this.gotMorePosts = true;
            }
            if (this.state.channel.id !== newState.channel.id) {
                this.scrolledToNew = false;
            }
            this.setState(newState);
        }
    },
    _onSocketChange: function(msg) {
        if (msg.action == "posted") {
            var post = JSON.parse(msg.props.post);

            var post_list = PostStore.getPosts(msg.channel_id);
            if (!post_list) return;

            post_list.posts[post.id] = post;
            if (post_list.order.indexOf(post.id) === -1) {
                post_list.order.unshift(post.id);
            }

            if (this.state.channel.id === msg.channel_id) {
                this.setState({ post_list: post_list });
            };

            PostStore.storePosts(post.channel_id, post_list);
        } else if (msg.action == "post_edited") {
            if (this.state.channel.id == msg.channel_id) {
                var post_list = this.state.post_list;
                if (!(msg.props.post_id in post_list.posts)) return;<commit_msg>Further added comments and split up if statments to make it more readable<commit_after>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

var PostStore = require('../stores/post_store.jsx');
var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx');
var UserProfile = require( './user_profile.jsx' );
var AsyncClient = require('../utils/async_client.jsx');
var Post = require('./post.jsx');
var LoadingScreen = require('./loading_screen.jsx');
var SocketStore = require('../stores/socket_store.jsx');
var utils = require('../utils/utils.jsx');
var Client = require('../utils/client.jsx');
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;

function getStateFromStores() {
    var channel = ChannelStore.getCurrent();

    if (channel == null) channel = {};

    return {
        post_list: PostStore.getCurrentPosts(),
        channel: channel
    };
}

module.exports = React.createClass({
    displayName: "PostList",
    scrollPosition: 0,
    preventScrollTrigger: false,    // Can't think of an intuitive name, but when true,
                                    // scrollPosition is affected by the 'on scroll' event below
    gotMorePosts: false,
    oldScrollHeight: 0,
    oldZoom: 0,
    scrolledToNew: false,           // Signifies we've already scrolled to the "new message" bar
                                    // one time, don't want to do it again even if the bar
                                    // doesn't go away
    componentDidMount: function() {

        // Add CSS required to have the theme colors
        var user = UserStore.getCurrentUser();
        if (user.props && user.props.theme) {
            utils.changeCss('div.theme', 'background-color:'+user.props.theme+';');
            utils.changeCss('.btn.btn-primary', 'background: ' + user.props.theme+';');
            utils.changeCss('.modal .modal-header', 'background: ' + user.props.theme+';');
            utils.changeCss('.mention', 'background: ' + user.props.theme+';');
            utils.changeCss('.mention-link', 'color: ' + user.props.theme+';');
            utils.changeCss('@media(max-width: 768px){.search-bar__container', 'background: ' + user.props.theme+';}');
        }
        if (user.props.theme != '#000000' && user.props.theme != '#585858') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, -10)  +';');
            utils.changeCss('a.theme', 'color:'+user.props.theme+'; fill:'+user.props.theme+'!important;');
        } else if (user.props.theme == '#000000') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +50)  +';');
            $('.team__header').addClass('theme--black');
        } else if (user.props.theme == '#585858') {
            utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +10)  +';');
            $('.team__header').addClass('theme--gray');
        }

        // Start our Store listeners
        PostStore.addChangeListener(this._onChange);
        ChannelStore.addChangeListener(this._onChange);
        UserStore.addStatusesChangeListener(this._onTimeChange);
        SocketStore.addChangeListener(this._onSocketChange);

        // Initialize perfect scrollbar
        $(".post-list-holder-by-time").perfectScrollbar();

        this.resize();

        // Set initial values of these component properties, will be updated on every re-render
        // scrollPosition - scroll point of bottom of current viewport
        // oldScrollHeight - bottom scroll point possible of viewport
        // oldZoom - represents "browser zoom"
        var post_holder = $(".post-list-holder-by-time")[0];
        this.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
        this.oldScrollHeight = post_holder.scrollHeight;
        this.oldZoom = (window.outerWidth - 8) / window.innerWidth;

        /*************** End of 'run on mount' code, Start of event listeners *****************/

        var self = this;
        $(window).resize(function(){
            $(post_holder).perfectScrollbar('update');

            // this only kind of works, detecting zoom in browsers is a nightmare
            var newZoom = (window.outerWidth - 8) / window.innerWidth;

            // We resize if :
            // 1. We are scrolled below the max scroll
            // 2. ???
            // 3. We changed zoom sizes
            if (self.scrollPosition >= post_holder.scrollHeight ||
                (self.oldScrollHeight !== post_holder.scrollHeight && self.scrollPosition >= self.oldScrollHeight) ||
                self.oldZoom !== newZoom) {
                self.resize();
            }

            self.oldZoom = newZoom;

            // Sets the size of the viewport, doesn't affect the overflowed component
            if ($('#create_post').length > 0) {
                var height = $(window).height() - $('#create_post').height() - $('#error_bar').outerHeight() - 50;
                $(".post-list-holder-by-time").css("height", height + "px");
            }
        });

        // scrollPosistion records and holds every position that the user has been at
        // unless preventScrollTrigger is enabled, then it skips one reading
        // Consider storing this in localStorage instead
        $(post_holder).scroll(function(e){
            if (!self.preventScrollTrigger) {
                self.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
            }
            self.preventScrollTrigger = false;
        });

        $('body').on('click.userpopover', function(e){
            if ($(e.target).attr('data-toggle') !== 'popover'
                && $(e.target).parents('.popover.in').length === 0) {
                $('.user-popover').popover('hide');
            }
        });

        $('.post-list__content div .post').removeClass('post--last');
        $('.post-list__content div:last-child .post').addClass('post--last');

        $('body').on('mouseenter mouseleave', '.post', function(ev){
            if(ev.type === 'mouseenter'){
                $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
                $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before');
            }
            else {
                $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--after');
                $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--before');
            }
        });

        $('body').on('mouseenter mouseleave', '.post.post--comment.same--root', function(ev){
            if(ev.type === 'mouseenter'){
                $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--comment');
                $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--comment');
            }
            else {
                $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--comment');
                $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--comment');
            }
        });

    },
    componentDidUpdate: function() {
        this.resize();
        var post_holder = $(".post-list-holder-by-time")[0];
        this.scrollPosition = $(post_holder).scrollTop() + $(post_holder).innerHeight();
        this.oldScrollHeight = post_holder.scrollHeight;
        $('.post-list__content div .post').removeClass('post--last');
        $('.post-list__content div:last-child .post').addClass('post--last');
    },
    componentWillUnmount: function() {
        PostStore.removeChangeListener(this._onChange);
        ChannelStore.removeChangeListener(this._onChange);
        UserStore.removeStatusesChangeListener(this._onTimeChange);
        SocketStore.removeChangeListener(this._onSocketChange);
        $('body').off('click.userpopover');
    },
    resize: function() {
        var post_holder = $(".post-list-holder-by-time")[0];
        this.preventScrollTrigger = true;
        if (this.gotMorePosts) {
            this.gotMorePosts = false;
            $(post_holder).scrollTop($(post_holder).scrollTop() + (post_holder.scrollHeight-this.oldScrollHeight) );
        } else if ($("#new_message")[0] && !this.scrolledToNew) {
            $(post_holder).scrollTop($(post_holder).scrollTop() + $("#new_message").offset().top - 63);
            this.scrolledToNew = true;
        } else {
            $(post_holder).scrollTop(post_holder.scrollHeight);
        }
        $(post_holder).perfectScrollbar('update');
    },
    _onChange: function() {
        var newState = getStateFromStores();

        if (!utils.areStatesEqual(newState, this.state)) {
            if (this.state.post_list &&
                this.state.post_list.order &&
                this.state.channel.id === newState.channel.id &&
                this.state.post_list.order.length !== newState.post_list.order.length &&
                newState.post_list.order.length > Constants.POST_CHUNK_SIZE) {
                this.gotMorePosts = true;
            }
            if (this.state.channel.id !== newState.channel.id) {
                this.scrolledToNew = false;
            }
            this.setState(newState);
        }
    },
    _onSocketChange: function(msg) {
        if (msg.action == "posted") {
            var post = JSON.parse(msg.props.post);

            var post_list = PostStore.getPosts(msg.channel_id);
            if (!post_list) return;

            post_list.posts[post.id] = post;
            if (post_list.order.indexOf(post.id) === -1) {
                post_list.order.unshift(post.id);
            }

            if (this.state.channel.id === msg.channel_id) {
                this.setState({ post_list: post_list });
            };

            PostStore.storePosts(post.channel_id, post_list);
        } else if (msg.action == "post_edited") {
            if (this.state.channel.id == msg.channel_id) {
                var post_list = this.state.post_list;
                if (!(msg.props.post_id in post_list.posts)) return;
{'fraction_non_alphanumeric': 0.16455633593827282, 'fraction_numerical': 0.0053912355326936395, 'mean_word_length': 2.419414848638593, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3727642', 'n_tokens_mistral': 5860, 'n_tokens_neox': 5619, 'n_words': 996}