F95 Mobile Upgrade

Improves mobile experience

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name        F95 Mobile Upgrade
// @namespace   1330126-edexal
// @match       *://f95zone.to/*
// @grant       none
// @icon        https://external-content.duckduckgo.com/ip3/f95zone.to.ico
// @license     Unlicense
// @version     1.3
// @author      Edexal
// @description Improves mobile experience
// @homepageURL https://sleazyfork.org/en/scripts/546346-f95-mobile-upgrade
// @supportURL  https://github.com/Edexaal/scripts/issues
// @require     https://cdn.jsdelivr.net/gh/Edexaal/scripts@e58676502be023f40293ccaf720a1a83d2865e6f/_lib/utility.js
// ==/UserScript==
(async () => {
  /*NOTE: F95 uses FontAwesome v5.15.4*/
  Edexal.addCSS(`
@media (width < 480px) {
  /*Fixes 'Your account' navigation menu*/ 
  #js-SideNavOcm .uix_sidebar--scroller {
    margin-top: 149px;
    & .block-header {
        padding: 14px;
        margin: 0;
        font-size: 1.5rem;
        font-weight: 700;
        background-color: #37383a;
        color:#babbbc;
        &::before {
          content: "\\f007";
        }
    }
    & .block-body:nth-of-type(2) {
      margin-bottom: 20px;
    }
  }
  /*Fixes scroll buttons appearing behind threads*/
  .uix_fabBar {
    z-index: 50;
    & .u-scrollButtons {
      position: inherit;
      gap:10px;
      bottom: 55px;
      &.is-active {
        opacity: 0.6;
      }
      & a:last-child {
        margin-left: 0;
      }
      & a.button.button--scroll {
        padding: 6px 12px;
      }
    }
  }
  .has-hiddenscroll .u-scrollButtons {
	  right: 35vw;
  }
  
  /*Fixes sidebar list of all online members & staff*/
  body .p-body-sidebar {
    margin-top: 64px;
    margin-bottom: 45px;
    &::after {
      margin:initial;
    }
  }
  /*Styles for reactions*/
  button.reaction.actionBar-action {
    position: relative;
    cursor: pointer;
  }
  .reactTooltip {
    position: absolute;
    bottom: 30px;
    right: -70px;
    width: 180px;
    z-index: 5;
    background-color: #242629;
    border: 1px solid #343638;
    border-radius: 8px;
    max-width: unset;
    gap: 2px;
  }
   .actionBar .reaction.reaction--imageHidden.reaction--1 i {
      padding-right: 0;
      margin-right: 0;
  } 
  .reaction.reaction--imageHidden img {
    display: unset;
  }
  .reaction.reaction--imageHidden > img {
    display: none;
  }
  .reaction-text {
    margin-left: 6px;
  }
  .has-reaction .reaction-text {
    margin-left: 0;
  }
}`);
  const SELECTOR = {
    likeBtns: 'a.reaction.actionBar-action',
    reactionBtns: 'button.reaction.actionBar-action',
    thread: '.p-body-main',
    latestUpdate: '#latest-page_main-wrap'
  };
  let REACTION_BAR;

  function isLatestUpdatePage() {
    return location.pathname.includes('sam/latest_alpha');
  }

  function setScrollBtn(selector, targetSelector, scrollType, altTargetSelector) {
    const scrollBtn = document.querySelector(selector);
    if (!scrollBtn) return;
    scrollBtn.removeAttribute('data-xf-click');
    Edexal.onEv(scrollBtn,'click', (e) => {
      e.preventDefault();
      const target = document.querySelector(targetSelector) ?? document.querySelector(altTargetSelector);
      target.scrollIntoView({
        block: scrollType
      });
    });
  }

  function initScrollBtns() {
    setScrollBtn('.uix_fabBar .u-scrollButtons a:last-child',
      'div.block-outer:nth-child(4) > div:nth-child(1) > nav:nth-child(1) > div:nth-child(2)',
      'end',
      '#footer');
    setScrollBtn('.uix_fabBar .u-scrollButtons a:first-child',
      '.block--messages',
      'start',
      '#top');
  }

  function assignTabItem(name, pathURL, oldFaIcons, newFaIcons, itemPos) {
    const tabItem = document.querySelector(`.uix_tabBar .uix_tabList .uix_tabItem:nth-of-type(${itemPos})`);
    if (!tabItem) return;
    tabItem.href = pathURL;
    const icon = tabItem.querySelector('i');
    icon.classList.remove(...oldFaIcons);
    icon.classList.add(...newFaIcons);
    const labelDiv = tabItem.querySelector('div');
    labelDiv.textContent = name;
  }

  function initTabItems() {
    assignTabItem('Latest Updates', '/sam/latest_alpha/', ['far', 'fa-comment-alt-exclamation'], ['far', 'fa-gem'], 2);
    assignTabItem('Bookmarks', '/account/bookmarks/', ['far', 'fa-user'], ['far', 'fa-bookmark'], 1);
  }

  /*Removes all effects from tiles on Latest Update Page
   by removing all event listeners from tiles*/
  function removeTileHoverEffects() {
    if (!isLatestUpdatePage()) return;
    const tilesWrapper = document.querySelector(SELECTOR.latestUpdate);
    const tilesWrapperClone = tilesWrapper.cloneNode();
    tilesWrapperClone.append(...tilesWrapper.childNodes);
    const fragment = document.createDocumentFragment();
    fragment.append(tilesWrapperClone);
    tilesWrapper.replaceWith(fragment);
  }

  function createReaction(idNum, altName) {
    const a = Edexal.newEl({
      element: 'a',
      href: `/posts/10864040/react?reaction_id=${idNum}`,
      class: ['reaction', `reaction--${idNum}`],
      'data-reaction-id': idNum
    });
    const img = Edexal.newEl({
      element: 'img',
      src: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
      class: ['reaction-sprite', 'js-reaction'],
      alt: altName,
      title: altName,
      'data-extra-class': "tooltip--basic tooltip--noninteractive",
      'data-delay-in': 50,
      'data-delay-out': 50
    });
    a.append(img);
    return a;
  }

  function createReactionBar() {
    const divBar = Edexal.newEl({element: 'div', class: ['reactTooltip']});
    let reactions = [
      createReaction(1, 'Like'),
      createReaction(14, 'Heart'),
      createReaction(13, "Jizzed my pants"),
      createReaction(12, "Yay, update!"),
      createReaction(3, "Haha"),
      createReaction(9, "Hey there"),
      createReaction(4, "Wow"),
      createReaction(7, "Thinking Face"),
      createReaction(5, "Sad"),
      createReaction(18, "Disagree"),
      createReaction(8, "Angry")
    ];
    divBar.append(...reactions);
    REACTION_BAR = divBar;
  }

  function initReactionBtns(likeBtns) {
    for (const likeBtn of likeBtns) {
      let reactBtn;
      if (!likeBtn.classList.contains('has-reaction')) {
        reactBtn = Edexal.newEl({
          element: 'button',
          'data-post-id': likeBtn.getAttribute('data-th-react-plus-content-id')
        });
        likeBtn.classList.remove('reaction--small');
      } else {
        reactBtn = Edexal.newEl({element: 'a', href: likeBtn.href});
      }
      reactBtn.classList.add(...likeBtn.classList);
      reactBtn.append(...likeBtn.childNodes);
      likeBtn.replaceWith(reactBtn);
    }
  }

  function updateReactionBtnURLs(postId) {
    REACTION_BAR.querySelectorAll('a').forEach(el => {
      el.href = el.href.replace(/\/[0-9]+\//, `/${postId}/`);
    });
  }

  function addReactionBarEvent(e) {
    updateReactionBtnURLs(e.currentTarget.dataset.postId);
    e.currentTarget.append(REACTION_BAR);
  }

  function removeReactionBarEvent(e) {
    if (!e.target.closest(SELECTOR.reactionBtns)) {
      REACTION_BAR.remove();
    }
  }

  function addReactionBtnEvents() {
    const reactionBtns = document.querySelectorAll(SELECTOR.reactionBtns);
    for (const reactBtn of reactionBtns) {
      Edexal.onEv(reactBtn,'click',addReactionBarEvent);
    }
  }

  function setRemoval() {
    document.querySelector(SELECTOR.thread).addEventListener('click', removeReactionBarEvent);
  }

  function initReaction() {
    const likeBtns = document.querySelectorAll(SELECTOR.likeBtns);
    if (!likeBtns || !likeBtns.length) return;
    createReactionBar();
    initReactionBtns(likeBtns);
    addReactionBtnEvents();
    setRemoval();
  }

  function run() {
    //Run only on mobile
    if (window.innerWidth >= 480) return;
    initTabItems();
    initScrollBtns();
    initReaction();
    setTimeout(removeTileHoverEffects, 2000);
  }

  run();
})()