<commit_before>import React, {Component} from 'react';

import {
    Image,
    Counter,
    Tooltip,
    Spinner,
    Icon
} from '~/components'


function setHTML(html) {
    return {
        dangerouslySetInnerHTML: {
            __html: html
        }
    }
}


export default class BoardPost extends Component {

    constructor(props) {
        super(props);
        this.state = {
            maxPostHeight: 400,
            isMovable: null,
            imageInvalidated: false
        }

        this.renderImage = this.renderImage.bind(this)
        this.renderComment = this.renderComment.bind(this)

        this.scrollPostUp = this.scrollPostUp.bind(this)
        this.scrollPostDown = this.scrollPostDown.bind(this)
        this.hideImage = this.hideImage.bind(this)
    }

    render() {
        const { onClick, post } = this.props;

        return (
            <div 
                id={"t" + post.id} className="board-post"
                onClick={ onClick }
                onMouseEnter={this.scrollPostUp}
                onMouseLeave={this.scrollPostDown}
            >
                {this.renderImage()}
                {this.renderComment()}
            </div>
        )
    }

    renderImage() {
        const {post:{media}, onLoad} = this.props
        return !this.state.imageInvalidated ? (
            <div className="image-wrap">
                <Image 
                    src={media.thumbnail} 
                    width={media.width} height={media.height}
                    loader={<Spinner/>}
                    onLoad={onLoad} onError={this.hideImage}/>
            </div>
        ) : false
    }

    renderComment() {
        const {post:{ title, comment, date, media, replies }} = this.props

        return (
            <div className="comment-wrap clearfix" ref={el => this._comment = $(el)}>
                <div className="counters">
                    <div className="float-right">
                        <Icon name="comment-text"/>
                        <Counter value={replies.textCount}/>
                    </div>
                    <div className="float-right">
                        <Icon name="image-filter-hdr"/>
                        <Counter value={replies.imgCount} />
                    </div>
                </div>
                <div className="op">
                    <b {...setHTML(title)} className="title" />
                    <div {...setHTML(comment)} />
                </div>
            </div>
        )
    }

    scrollPostUp(){
        // TODO: get height from props not ref
        const imgHeight = this.props.post.media.height, 
              commentHeight = this._comment.clientHeight,
              maxHeight = this.state.maxPostHeight

        if (imgHeight + commentHeight > maxHeight ) {
            // comment is long and offscreen; make it more viewable by moving it up
            
            // move by difference, else if that would move comment outside 
            // thread, use image height (scroll to top)
            const offScreenAmount = commentHeight - (maxHeight - imgHeight) + 5 // 5px for padding at bottom of comment
            const height = imgHeight/1.5 // 3/4 of image height
            const distance = offScreenAmount < height ? offScreenAmount : height
            this._comment.velocity({top: `-${distance}px`}, 200, 'linear')
        }
    }
 
    scrollPostDown(){
        this._comment.velocity({top: 0}, 200)
    }

    hideImage() {
        this.setState({
            imageInvalidated: true
        })
    }
}<commit_msg>feat(BoardPost): Add lazyloading, remove mouseover<commit_after>import React, {Component} from 'react';
import LazyLoad from 'react-lazyload';

import {
    Counter,
    Tooltip,
    Spinner,
    Icon,
    Image,
    Line
} from '~/components'

import PostHeader from './BoardPostHeader'

function setHTML(html) {
    return {
        dangerouslySetInnerHTML: {
            __html: html
        }
    }
}


export default class BoardPost extends Component {

    constructor(props) {
        super(props);
        this.state = {
            maxCommentHeght: 150,
            isMovable: null,
            imageInvalidated: false
        }

        this.hideImage = this.hideImage.bind(this)
    }

    render() {
        const { onClick, onLoad, post } = this.props;

        return (
            <div id={"t" + post.id} className="board-post" onClick={ onClick }>
                {this.renderImage(onLoad, post)}
                {this.renderComment(post)}
            </div>
        )
    }

    renderImage(onLoad, {media}) {
        return <div className="image-wrap">
            <LazyLoad height={media.height} once>
                <Image 
                    src={media.thumbnail} 
                    width={media.width} height={media.height}
                    onLoad={onLoad} onError={this.hideImage}
                    hideUntilLoaded loader={<Spinner/>}
                />
            </LazyLoad>
        </div>
    }

    renderComment({ title, comment, date, replies }) {
        return (
            <div className="comment-wrap">
                <div className="comment-slider" ref={el => this._comment = $(el)}>
                    <PostHeader replies={replies} date={date}/>
                    <Line />
                    <div className="op">
                        { title && <b {...setHTML(title)} className="title" /> }
                        <div {...setHTML(comment)} className="comment"/>
                    </div>
                </div>
            </div>
        )
    }

    hideImage() {
        this.setState({
            imageInvalidated: true
        })
    }
}
{'fraction_non_alphanumeric': 0.11651343705799151, 'fraction_numerical': 0.0033592644978783595, 'mean_word_length': 1.4855008787346222, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 46, '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': '2131482', 'n_tokens_mistral': 1557, 'n_tokens_neox': 1469, 'n_words': 325}