Qiita timeline auto more

auto fetch more entries

// ==UserScript==
// @name         Qiita timeline auto more
// @namespace    https://htsign.hateblo.jp
// @version      0.3.2
// @description  auto fetch more entries
// @author       htsign
// @match        https://qiita.com/*
// @grant        none
// ==/UserScript==

const queryNodes = function* (path, root = document) {
  const result = document.evaluate(path, root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
  let node;
  while ((node = result.iterateNext()) != null) {
    yield node;
  }
};

const listElement = document.querySelector('main');
if (listElement) {
  const READMORE_XPATH = './/button[text()="もっと読む"]';

  const io = new IntersectionObserver((entries, observer) => {
    entries
      .filter(entry => entry.isIntersecting)
      .forEach(({ target }) => {
        observer.unobserve(target);
        target.click();
      });
  }, { rootMargin: '100%' });
  const mo = new MutationObserver(records => {
    const buttons = records
      .flatMap(r => [...r.addedNodes])
      .flatMap(node => [...queryNodes(READMORE_XPATH, node)]);

    buttons.forEach(io.observe.bind(io));
  });
  mo.observe(listElement, { childList: true, subtree: true });

  const button = document.evaluate(READMORE_XPATH, listElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE)?.singleNodeValue;
  if (button) {
    io.observe(button);
  }
}