<commit_before>import React, {
  Component,
  PropTypes,
} from 'react';
import { connect, Provider } from 'react-redux';
import $ from 'jquery';
import { toClassName } from '../utils';
import { GET } from '../utils/http';
import postHelper from '../utils/postHelper';
import { insertTextIntoEditor } from '../common/editor';
import { setConfig } from '../../options/ConfigItem';
import { getConfig } from '../../options/OptionPage';
import { increasePageStatusId } from '../actions/voz';

let threadId;
const genUrl = (page) => `https://vozforums.com/showthread.php?t=${threadId}&page=${page}`;
const _c = (e) => document.createElement(e);
// const _t = document.createTextNode;
const getNextPageDiv = (props) => {
  const w = _c('div');
  w.id = 'page-control-next-end';
  w.innerHTML = 'Load Next Page (HotKey: Phím →)';
  document.querySelector('#lastpost').parentNode.appendChild(w);
  w.addEventListener('click', props.onClick);
  return w;
};
const getPreviousPageDiv = (props) => {
  const w = _c('div');
  w.id = 'page-control-prev-top';
  w.innerHTML = 'Load Previous Page (Hotkey: Phím ←)';
  document.querySelector('#posts').parentElement.insertBefore(w, document.querySelector('#posts'));
  w.addEventListener('click', props.onClick);
  return w;
};

const getPageNumState = ($html) => {
  const state = {
    pageNum: 1,
    pageCurrent: 1,
    isLoading: false,
  };
  if ($html.find('.pagenav .vbmenu_control').length > 0) {
    const matches = $html.find('.pagenav .vbmenu_control').eq(0).text().trim().match(/Page +(\d+) +of +(\d+)/);
    if (matches && matches.length > 2) {
      state.pageNum = parseInt(matches[2], 10);
      state.pageCurrent = parseInt(matches[1], 10);
    }
  }
  return state;
};

const loadPage = (page) => {
  const url = genUrl(page);
  return GET(url)
    .then((html) => {
      const $html = $(html);
      const posts = $html.find('#posts > div');
      const pageState = getPageNumState($html);
      return { posts, pageState, url };
    });
};

class UIRevampThread extends Component {
  static propTypes = {
    dispatch: PropTypes.func,
  }

  constructor(props) {
    super(props); // enable

    this.state = {
      status: null, /* processing, text, copied, cancel */
      text: '',
    };
  }

  componentDidMount() {
    if (this.props.enable === true) {
      require('../styles/thread-ui.less');
      threadId = postHelper($(document.body)).getThreadId();
      getNextPageDiv({ onClick: this.clickNext });
      getPreviousPageDiv({ onClick: this.clickPrevious });
      this.init();
      window.__goNextPage = this.clickNext.bind(this);
      window.__goPreviousPage = this.clickPrevious.bind(this);
    } else {
      this.addRecommend();
    }
  }

  addRecommend() {
    const posts = document.querySelector("#posts");
    const $btn = $('<a href="#" style="color: white;font-size: 14px;font-weight: bold;text-shadow: 0px 0px 2px black">Kích hoạt giao diện mới cho trang xem thớt</a>');
    // console.log($(posts.previousElementSibling));
    // console.log($(posts.previousElementSibling).find('.tcat > div'));
    $(posts.previousElementSibling).find('.tcat > div').append($btn);
    $btn.bind('click', () => {
      getConfig()
        .then(config => {
          return setConfig('newThreadUI', true, config)
        })
        .then(() => {
          window.location.href = window.location.href + '#newThreadUIFirstEnable';
          location.reload();
        });
    });
  }

  disableNavigationControl() {
    document.querySelector('#page-control-prev-top').classList.add('hide-nav');
    document.querySelector('#page-control-next-end').classList.add('hide-nav');
  }

  goToPage(page) {
    this.setState({ isLoading: true })
    this.disableNavigationControl();
    return loadPage(page)
      .then(({ posts, pageState, url }) => {
        window.history.replaceState(null, window.document.title.replace(/Page \d+/, '') + ` - Page ${page}`, url);
        this.setState({ isLoading: false, ...pageState }, () => {
          this.updateOffElements();
        });
        return posts;
      });
  }

  clickPrevious = (e) => {
    const nextPage = Math.max(1, this.state.pageCurrent - 1);
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').prepend(posts);
        setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();
    return false;
  }
  clickNext = (e) => {
    const nextPage = Math.min(this.state.pageCurrent + 1, this.state.pageNum);
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').append(posts);
        setTimeout(() => window.scrollTo(0, 0), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();
    return false;
  }
  clickFirst = (e) => {
    const nextPage = 1;
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').prepend(posts);
        setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();<commit_msg>scroll to top when prev<commit_after>import React, {
  Component,
  PropTypes,
} from 'react';
import { connect, Provider } from 'react-redux';
import $ from 'jquery';
import { toClassName } from '../utils';
import { GET } from '../utils/http';
import postHelper from '../utils/postHelper';
import { insertTextIntoEditor } from '../common/editor';
import { setConfig } from '../../options/ConfigItem';
import { getConfig } from '../../options/OptionPage';
import { increasePageStatusId } from '../actions/voz';

let threadId;
const genUrl = (page) => `https://vozforums.com/showthread.php?t=${threadId}&page=${page}`;
const _c = (e) => document.createElement(e);
// const _t = document.createTextNode;
const getNextPageDiv = (props) => {
  const w = _c('div');
  w.id = 'page-control-next-end';
  w.innerHTML = 'Load Next Page (HotKey: Phím →)';
  document.querySelector('#lastpost').parentNode.appendChild(w);
  w.addEventListener('click', props.onClick);
  return w;
};
const getPreviousPageDiv = (props) => {
  const w = _c('div');
  w.id = 'page-control-prev-top';
  w.innerHTML = 'Load Previous Page (Hotkey: Phím ←)';
  document.querySelector('#posts').parentElement.insertBefore(w, document.querySelector('#posts'));
  w.addEventListener('click', props.onClick);
  return w;
};

const getPageNumState = ($html) => {
  const state = {
    pageNum: 1,
    pageCurrent: 1,
    isLoading: false,
  };
  if ($html.find('.pagenav .vbmenu_control').length > 0) {
    const matches = $html.find('.pagenav .vbmenu_control').eq(0).text().trim().match(/Page +(\d+) +of +(\d+)/);
    if (matches && matches.length > 2) {
      state.pageNum = parseInt(matches[2], 10);
      state.pageCurrent = parseInt(matches[1], 10);
    }
  }
  return state;
};

const loadPage = (page) => {
  const url = genUrl(page);
  return GET(url)
    .then((html) => {
      const $html = $(html);
      const posts = $html.find('#posts > div');
      const pageState = getPageNumState($html);
      return { posts, pageState, url };
    });
};

class UIRevampThread extends Component {
  static propTypes = {
    dispatch: PropTypes.func,
  }

  constructor(props) {
    super(props); // enable

    this.state = {
      status: null, /* processing, text, copied, cancel */
      text: '',
    };
  }

  componentDidMount() {
    if (this.props.enable === true) {
      require('../styles/thread-ui.less');
      threadId = postHelper($(document.body)).getThreadId();
      getNextPageDiv({ onClick: this.clickNext });
      getPreviousPageDiv({ onClick: this.clickPrevious });
      this.init();
      window.__goNextPage = this.clickNext.bind(this);
      window.__goPreviousPage = this.clickPrevious.bind(this);
    } else {
      this.addRecommend();
    }
  }

  addRecommend() {
    const posts = document.querySelector("#posts");
    const $btn = $('<a href="#" style="color: white;font-size: 14px;font-weight: bold;text-shadow: 0px 0px 2px black">Kích hoạt giao diện mới cho trang xem thớt</a>');
    // console.log($(posts.previousElementSibling));
    // console.log($(posts.previousElementSibling).find('.tcat > div'));
    $(posts.previousElementSibling).find('.tcat > div').append($btn);
    $btn.bind('click', () => {
      getConfig()
        .then(config => {
          return setConfig('newThreadUI', true, config)
        })
        .then(() => {
          window.location.href = window.location.href + '#newThreadUIFirstEnable';
          location.reload();
        });
    });
  }

  disableNavigationControl() {
    document.querySelector('#page-control-prev-top').classList.add('hide-nav');
    document.querySelector('#page-control-next-end').classList.add('hide-nav');
  }

  goToPage(page) {
    this.setState({ isLoading: true })
    this.disableNavigationControl();
    return loadPage(page)
      .then(({ posts, pageState, url }) => {
        window.history.replaceState(null, window.document.title.replace(/Page \d+/, '') + ` - Page ${page}`, url);
        this.setState({ isLoading: false, ...pageState }, () => {
          this.updateOffElements();
        });
        return posts;
      });
  }

  clickPrevious = (e) => {
    const nextPage = Math.max(1, this.state.pageCurrent - 1);
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').prepend(posts);
        setTimeout(() => window.scrollTo(0, 0), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();
    return false;
  }
  clickNext = (e) => {
    const nextPage = Math.min(this.state.pageCurrent + 1, this.state.pageNum);
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').append(posts);
        setTimeout(() => window.scrollTo(0, 0), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();
    return false;
  }
  clickFirst = (e) => {
    const nextPage = 1;
    if (nextPage === this.state.pageCurrent) return false;
    this.goToPage(nextPage)
      .then(posts => {
        $('#posts').empty();
        $('#posts').prepend(posts);
        setTimeout(() => window.scrollTo(0, 0), 100);
        if (window.__postTrackerSetup) window.__postTrackerSetup();
        setTimeout(() => this.props.dispatch(increasePageStatusId()), 200);
      });
    e.preventDefault();
{'fraction_non_alphanumeric': 0.18038030922338724, 'fraction_numerical': 0.007641727385818376, 'mean_word_length': 3.170062986291219, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 65, 'https://': 2, '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': '2991921', 'n_tokens_mistral': 3531, 'n_tokens_neox': 3504, 'n_words': 689}