RPS Hide Read Posts

Hides posts on the RPS homepage when they're clicked & adds a "Mark all as read" button

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        RPS Hide Read Posts
// @description Hides posts on the RPS homepage when they're clicked & adds a "Mark all as read" button
// @version     5
// @namespace   https://github.com/insin/greasemonkey
// @grant       none
// @match       https://www.rockpapershotgun.com/
// ==/UserScript==

// @ts-ignore
let debug = false

/**
 * @param {HTMLElement} section
 * @returns {boolean}
 */
function areAllPostsHidden(section) {
  return Array.from(section.querySelectorAll('article.summary')).every(
    (article) => article.parentElement.style.display === 'none'
  )
}

/**
 * @param {HTMLElement} target
 * @returns {string}
 */
function getPostClickHref(target) {
  if (target.tagName === 'A' && target.closest('article.summary')) {
    return /** @type {HTMLAnchorElement} */ (target).pathname
  }
  return ''
}

function postsPage() {
  let $style = document.createElement('style')
  $style.innerText = `
  /* Prevent the top section taking up space when posts are removed */
  #content_above {
    min-height: unset !important;
  }
  `
  document.head.appendChild($style)

  /** @type {string[]} */
  let clickedPosts = JSON.parse(localStorage.getItem('clickedPosts') || '[]')

  function hideEmptySections() {
    for (let section of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll(
      '#content_above, section.featured_tag_shelf, section.latest_shelf, section.shelf, section.supporters_shelf'
    ))) {
      if (section.style.display === 'none') continue
      if (areAllPostsHidden(section)) {
        section.style.display = 'none'
      }
    }
  }

  function hideClickedPosts() {
    for (let link of /** @type {NodeListOf<HTMLAnchorElement>} */ (document.querySelectorAll(
      'a.link_overlay'
    ))) {
      if (clickedPosts.includes(link.pathname)) {
        let nodeToHide = link.closest('li')
        if (nodeToHide && nodeToHide.style.display !== 'none') {
          nodeToHide.style.display = 'none'
        }
      }
    }
    hideEmptySections()
  }

  function markAllAsRead(e) {
    e.preventDefault()
    for (let link of /** @type {NodeListOf<HTMLAnchorElement>} */ (document.querySelectorAll(
      'a.link_overlay'
    ))) {
      if (!clickedPosts.includes(link.pathname)) {
        clickedPosts.unshift(link.pathname)
      }
    }
    localStorage.setItem('clickedPosts', JSON.stringify(clickedPosts))
    hideClickedPosts()
  }

  document.addEventListener('click', (e) => {
    let target = /** @type {HTMLElement} */ (e.target)
    if (e.button === 0 && getPostClickHref(target)) {
      // Hold ctrl + shift when clicking a post to hide it without opening it
      if (debug || (e.shiftKey && e.ctrlKey)) e.preventDefault()
      clickedPosts.unshift(getPostClickHref(target))
      localStorage.setItem('clickedPosts', JSON.stringify(clickedPosts))
      hideClickedPosts()
    }
  })

  document.addEventListener('auxclick', (e) => {
    let target = /** @type {HTMLElement} */ (e.target)
    if (e.button === 1 && getPostClickHref(target)) {
      // Hold ctrl when middle-clicking a post to hide it without opening it
      if (debug || e.ctrlKey) e.preventDefault()
      clickedPosts.unshift(getPostClickHref(target))
      localStorage.setItem('clickedPosts', JSON.stringify(clickedPosts))
      hideClickedPosts()
    }
  })

  let topButtons = document.querySelector('div.commercial.button_group')
  if (topButtons != null) {
    let button = document.createElement('a')
    button.className = 'button supporter'
    button.innerText = 'Mark all as read'
    button.href = '#'
    button.addEventListener('click', markAllAsRead)
    button.id = 'mark-all-as-read'
    topButtons.appendChild(button)
  }

  hideClickedPosts()
}

if (location.pathname === '/' && !document.querySelector('#mark-all-as-read')) {
  postsPage()
}