Sprytny scroll dla Wykop.pl

Płyne przewijanie klawiszami, wyłączanie materiałów które nie są już widoczne.

// ==UserScript==
// @name        Sprytny scroll dla Wykop.pl
// @namespace   http://www.wykop.pl/ludzie/Deykun
// @description Płyne przewijanie klawiszami, wyłączanie materiałów które nie są już widoczne.
// @author      Deykun
// @version     2.00
// @include     htt*.wykop.pl/*
// @grant       none
// @run-at			document-end
// ==/UserScript==

// Możesz nieinwazynie zmienić klawisz przewijający stronę:
// - w konsoli wpisz localStorage.setItem('ssPrevious', 'k')
// - po odświeżeniu zmieni przewijanie z domyślnego b na k
// robiąc to w taki sposób zmiany nie zostaną stracone po aktualizacji dodatku :)

const keysActions = {
  previous: localStorage.getItem('ssPrevious') || 'b',
  next: localStorage.getItem('ssNext') || 'n',
}

const scrollSelectors = {
  newEntryForm: '#commentForm',
  link: '#itemsStream > .link', // znaleziska na liście
  entryAndLink: '#itemsStream.comments-stream > .iC', // komentarze w znaleziskach / wpisy na mikroblogu
  pages: '.pager',
};

const appendCSS = styles => {
  const style = document.createElement('style')
  style.innerHTML = styles
  document.head.append(style)
}

const getElementHeight = selector => {
  const el = document.querySelector(selector);

  return el ? parseFloat(getComputedStyle(el, null).height.replace('px', '')) : 0;
}

const domReady = fn => {
  document.addEventListener('DOMContentLoaded', fn);
  if (document.readyState === 'interactive' || document.readyState === 'complete') {
    fn();
  }
}

const debounce = (fn, time) => {
  let timeoutHandler;

  return (...args) => {
    clearTimeout(timeoutHandler);
    timeoutHandler = setTimeout(() => {
      fn(...args)
    }, time);
  }
}

const isElementVisibleInY = el => {
  const isVisibleEvenWhen = -20; // px
  const { top, bottom } = el.getBoundingClientRect();

  return top >= isVisibleEvenWhen || bottom >= isVisibleEvenWhen;
}

const muteExternalContent = () => {
  const embeds = Array.from(document.querySelectorAll('.closeEmbed')).map(closeEl => closeEl.parentNode.parentNode);
  const embedsToClose = embeds.filter(embed => !isElementVisibleInY(embed));

  if (embedsToClose.length === 0) {
    return;
  }

  embedsToClose.forEach(embedEl => {
    const closeButton = embedEl.querySelector('.closeEmbed');
    const event = document.createEvent('HTMLEvents');
    event.initEvent('click', true, false);
    closeButton.dispatchEvent(event);
  });
}

domReady(() => {
  let navHeight = getElementHeight('#nav'),
      bodyHeight = getElementHeight('body'),
      elements = [];

  appendCSS(`
    html {
      scroll-behavior: smooth;
    }
  `);

  function calcElementsY() {
    elementsY = [];
    navHeight = getElementHeight('#nav');
    bodyHeight = getElementHeight('body');

    const selectedElements = Object.values(scrollSelectors).reduce((stack, selector) => {
      const selectorElements = Array.from(document.querySelectorAll(selector));
      
      return [...stack, ...selectorElements];
    }, []);

    const bodyScrollY = window.scrollY;    
    elements = selectedElements.map(el => ({
      el: el,
      y: el.getBoundingClientRect().top + bodyScrollY,
    })).sort((a, b) => a.y - b.y);

    // Remove duplicated Ys
    elements = elements.filter((el1, index, els) => els.findIndex(el2 => el2.y === el1.y) === index);
  };
  calcElementsY();


  const smartScrollTo = direction => {
    const didBodyHeightChange = bodyHeight !== getElementHeight('body');
    if (didBodyHeightChange) {
      calcElementsY();
    }

    const y = window.pageYOffset;
    const nextIndex = elements.findIndex(el => el.y > y + navHeight + 1);

    if (direction === 'previous') {
      if (nextIndex > 1) {
        const previousElY = elements[nextIndex - 2].y;
        window.scrollTo(0, previousElY - navHeight);
      } else {
        // TOP
        window.scrollTo(0, 0);
      }

      return;
    }

    if (direction === 'next') {
      if (nextIndex <= elements.length) {
        const nextElY = elements[nextIndex].y;
        window.scrollTo(0, nextElY - navHeight);
      } else {
        // BOTTOM
      }

      return;
    }


  }

  document.addEventListener('keyup', event => {
    const tagName = event.target.tagName.toLowerCase();
    const key = event.key.toLowerCase();
    const userIsTyping = tagName === 'input' || tagName === 'textarea';

    if (!userIsTyping) {
      switch (key) {
        case keysActions.next:
          smartScrollTo('next');
          break;
        case keysActions.previous:
          smartScrollTo('previous');
          break;
      }
    }
  });

  document.addEventListener('scroll', debounce(() => {
      muteExternalContent();
  }, 150));
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址