Expand comments at webinar.ru

Добавляет кнопки, раскрывающие ветки с обсуждениями на сайте webinar.ru

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Expand comments at webinar.ru
// @namespace   Webinar Scripts
// @match       https://events.webinar.ru/course-info/*
// @grant       none
// @version     1.3
// @author      in_vite
// @description Добавляет кнопки, раскрывающие ветки с обсуждениями на сайте webinar.ru
// ==/UserScript==

const waitForElement = async selector => {
  while (document.getElementsByClassName(selector).length == 0) {
    await new Promise(resolve => requestAnimationFrame(resolve))
  }

  return document.getElementsByClassName(selector)
}

const waitAndClickElement = async (where, selector, selector2, minimumExpectedLength=1) => {
  while ((where.getElementsByClassName(selector).length == 0) &&
         (where.getElementsByClassName(selector2).length < minimumExpectedLength)) {
    await new Promise(resolve => requestAnimationFrame(resolve))
  }

  if (where.getElementsByClassName(selector).length > 0) {
    where.getElementsByClassName(selector)[0].click()
  }

  return where.getElementsByClassName(selector2).length
}

function main() {
  'use strict'

  const nameCommentsCount = 'PostNewsComments__commentsCount____zB8X'
  const nameFetchMoreComments = 'PostNewsComments__fetchMoreCommentsBtn___tyN_f'
  const nameNewsItem = 'NewsFeed__newsItem___VAlN_'
  const nameCommentRoot = 'Comment__root___sd3C5'
  const nameButton = 'ExpandingButton'
  
  // wait till the page is loaded and add two kinds of buttons with different behavior
  waitForElement(nameCommentsCount).then((selector) => {
    // check there are no buttons yet
    if (document.getElementsByClassName(nameButton).length == 0) {
      addButtons('Развернуть комментарии', '10px', openComments, false)
      addButtons('Развернуть и прокрутить', '20px', openComments, true)
    }
  })

  function addButtons(text, leftPosition, onClick, withScroll) {
    // find all elements with information about total number of comments
    let elementCommentsCounts = document.getElementsByClassName(nameCommentsCount)

    // default button style and position
    let cssObj = {
      position: 'relative',
      left: leftPosition,
      //'-webkit-appearance': 'none',
      //'-moz-appearance': 'none',
      //'appearance': 'none',   
      background: 'white',
      color: 'black',
      'border-radius': '3px',
      'border-color': 'lightgray'
    }

    // for every such element create a button with specified style, position and behavior
    for (let i = elementCommentsCounts.length; i--;) {
      let button = document.createElement('button'), btnStyle = button.style
      elementCommentsCounts[i].appendChild(button)
      button.className = nameButton
      button.innerHTML = text
      button.onclick = onClick.bind(button, withScroll)
      Object.keys(cssObj).forEach(key => btnStyle[key] = cssObj[key])
    }
  }

  async function openComments(withScroll) {
    // find an element with the whole discussion
    let post = this.parentElement.parentElement
    // retrieve total number of comments
    let totalCommentsNumber = parseInt(post.getElementsByClassName(nameCommentsCount)[0].innerText, 10)
    let done = false
    let currentCommentsNumber = 0
    const whileGenerator = function* () {
      while (!done) {
        yield currentCommentsNumber
      }
    }

    for (let i of whileGenerator()) {
      // find the link for expansion while it exists and click it
      currentCommentsNumber = await waitAndClickElement(post, nameFetchMoreComments, nameCommentRoot, totalCommentsNumber)

      // stop when we got all possible comments
      if (currentCommentsNumber >= totalCommentsNumber) {
        done = true;
      }
    }

    // change button style when it expanded everything
    this.style.background = '#f6f6f6'
    this.style.color = 'black'

    if (withScroll && (totalCommentsNumber > 0)) {
      // get element with the last comment
      let lastComment = post.getElementsByClassName(nameCommentRoot)[totalCommentsNumber - 1]
      let yOffset = -90
      // get element position and correct it
      let y = lastComment.getBoundingClientRect().top + window.pageYOffset + yOffset

      // scroll to the corrected position
      window.scrollTo({top: y, behavior: 'smooth'});
    }
  }
}

let oldHref = ''

// check url is changed to add buttons again
window.onload = function() {
    let bodyList = document.querySelector('body')
    let observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (oldHref != document.location.href) {
          oldHref = document.location.href
          main()
        }
      })
    })

    let config = {
      childList: true,
      subtree: true
    }

    observer.observe(bodyList, config)
}