Greasy Fork is available in English.

Smart Scroll

Provides buttons to scroll web pages up and down

Instalirajte ovu skriptu?
Autorov prijedlog skripta

Možda ti se također svidi SmartChute.

Instalirajte ovu skriptu
// ==UserScript==
// @version         19.11.11
// @name            Smart Scroll
// @description     Provides buttons to scroll web pages up and down
// @license         MIT
// @author          S-Marty
// @compatible      firefox
// @compatible      chrome
// @namespace       https://github.com/s-marty/SmartScroll
// @homepageURL     https://github.com/s-marty/SmartScroll
// @supportURL      https://github.com/s-marty/SmartScroll/wiki
// @icon            https://raw.githubusercontent.com/s-marty/SmartScroll/master/images/smartScroll.png
// @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QHFFSLZ7ENUQN&source=url
// @include         /^https?://.*$/
// @exclude         /[^\s]+\.(jpe?g|png|gif|bmp|svg)(\?[^\s]+)?$/
// @run-at          document-end
// @grant           GM.getValue
// @grant           GM.setValue
// @grant           GM_getValue
// @grant           GM_setValue
// @noframes
// ==/UserScript==

/* greasyfork.org jshint syntax checking hacks */
/* jshint asi: true */
/* jshint boss: true */
/* jshint esversion: 6 */
/* jshint loopfunc: true */

/** ****************** Features ******************
*** Able to leap tall pages in a single click
*** Up and down, slow or faster than a speeding bullet
*** More robust than a locomotive
*** Slow scroll by middle mouse button or mouse hover
*** 26 Slow scrolling speeds
*** Doesn't interfere with the page's native onScroll event
*** Conquers bottomless or never-ending pages in most cases
*** Disableable per site
*** No extra @require files (jquery et.al.)
*** Double-click on either button for settings ***
*** Compatable with Firefox 43 to 63+          ***
*** Compatable with Chrome 62 to 71            ***
*** Compatable with Violentmonkey ? to 2.10    ***
*** Compatable with Greasemonkey 3.9 to 4.7    ***
*** Compatable with Tampermonkey 4.7 to 4.8    ***/

(function () {
"use strict";

var buttons = {

  monkey: function () {
    let style;

    if (this.user.settings.ignore.indexOf(host) !=-1) return;

    if (this.body && this.is_userscript) {
      style = document.createElement("style");
      style.setAttribute('id', 'smartscrollstyle');
      style.type = "text/css";
      style.innerHTML = this.buttonCss();
      this.head.appendChild(style);

      this.up_ctn = document.createElement("span");
      this.dn_ctn = document.createElement("span");
      this.up_ctn.setAttribute("id","up_btn");
      this.dn_ctn.setAttribute("id","dn_btn");
      this.up_ctn.className = "updn_btn";
      this.dn_ctn.className = "updn_btn";
      this.body.appendChild(this.up_ctn);
      this.body.appendChild(this.dn_ctn);

      if (this.user.settings.crawl_trigger == 'middleclick') {
        this.up_ctn.addEventListener('mousedown', function(e) { if(e.which==2) {buttons.creepUp(1)} }, false);
        this.up_ctn.addEventListener('mouseup', function(e) { if(e.which==2) {buttons.creep = !1} }, false);
        this.dn_ctn.addEventListener('mousedown', function(e) { if(e.which==2) {buttons.creepDn(1)} }, false);
        this.dn_ctn.addEventListener('mouseup', function(e) { if(e.which==2) {buttons.creep = !1} }, false);
      }
      else {
        this.up_ctn.addEventListener('mouseover', function(e) { buttons.creepUp(1) }, false);
        this.up_ctn.addEventListener('mouseout', function(e) { buttons.creep = !1 }, false);
        this.dn_ctn.addEventListener('mouseover', function(e) { buttons.creepDn(1) }, false);
        this.dn_ctn.addEventListener('mouseout', function(e) { buttons.creep = !1 }, false);
      }

      this.up_ctn.addEventListener('dblclick', function(e) { if(e.which===1) {buttons.smartScroll_Settings(e)} }, false);
      this.dn_ctn.addEventListener('dblclick', function(e) { if(e.which===1) {buttons.smartScroll_Settings(e)} }, false);
      this.up_ctn.addEventListener('click', function(e) { if(e.which===1) {buttons.scrollToTop()} }, false);
      this.dn_ctn.addEventListener('click', function(e) { if(e.which===1) {buttons.scrollToBottom()} }, false);

      if (root !== null && this.user.settings.bottomless_pages) {
        this.resize = document.createElement("iframe");
        this.resize.setAttribute("name","resize_frame");
        this.resize.setAttribute("tabindex","-1");
        this.resize.className = "resize_frame";
        root.appendChild(this.resize);
        this.resize.contentWindow.addEventListener('resize', function(e) { buttons.getDocumentHeight(e) }, false);
      }

      window.addEventListener('scroll', buttons.onScroll, {passive : true});
      window.addEventListener('resize', buttons.onResize, false);
      this.body.addEventListener('mouseleave', buttons.saveAccrued, false);
      window.addEventListener('beforeunload', function(e) { buttons.settings_close('unload')}, false);
      document.addEventListener('readystatechange', function(e) { if(document.readyState === "complete") { buttons.getDocumentHeight(e)} }, false);

      if (this.user.settings.dimButtons) {
        setTimeout(buttons.fadeOut, 3000);
      }
    }
    else return

  },
  areOverVid: function(e) {

    var vid = (typeof e === 'object' && e.target.tagName == 'VIDEO') ? e.target : false;
    if (! vid) return false;
    else {
      var isOverV = false;
      var isOverH = false;
      var vidRect = vid.getBoundingClientRect();
      var butRect = buttons.up_ctn.getBoundingClientRect();

      if (vidRect.right - vidRect.left > window.innerWidth / 2) {
        isOverH = true;
      }
      else {
        isOverH = vidRect.left < window.innerWidth - 33 && vidRect.right > window.innerWidth - 33;
      }
      isOverV = vidRect.top < butRect.top && vidRect.bottom > butRect.top;

      return isOverH && isOverV;
    }

  },
  fadeOut: function(e) {

    var up_btn = buttons.up_ctn;
    var dn_btn = buttons.dn_ctn;

    if (buttons.fading) return;
    else if (buttons.areOverVid(e)) {
      if (buttons.opacity_timer) clearInterval(buttons.opacity_timer);
      up_btn.style.visibility = 'visible';
      dn_btn.style.visibility = 'visible';
      up_btn.style.opacity = 0.65;
      dn_btn.style.opacity = 0.65;
      buttons.fading = setTimeout( function(e) {buttons.fading = null}, 3000);
      setTimeout( function(e) {
        buttons.opacity_timer = setInterval(function() {
          if (up_btn.style.opacity <= 0) {
            clearInterval(buttons.opacity_timer);
            buttons.opacity_timer = null;
            up_btn.style.visibility = 'hidden';
            dn_btn.style.visibility = 'hidden';
          }
          else {
            up_btn.style.opacity -= 0.025;
            dn_btn.style.opacity -= 0.025;
          }
        }, 100);
      }, 3000);
    }
    else {
      if (buttons.opacity_timer) {
        clearInterval(buttons.opacity_timer);
        buttons.opacity_timer = null;
      }
      up_btn.style.visibility = 'visible';
      dn_btn.style.visibility = 'visible';
      up_btn.style.opacity = 0.65;
      dn_btn.style.opacity = 0.65;
    }

  },
  reLoadStart: function(e) {

    setTimeout(function() {
      buttons.getDocumentHeight();
      buttons.getVideo();
      setTimeout(buttons.fadeOut, 3000);
    }, 500);

  },
  hideOnFullScreen: function() {

    document.addEventListener("fullscreenchange", () => { buttons.onFullScreen()});
    document.addEventListener("mozfullscreenchange", () => { buttons.onFullScreen()});
    document.addEventListener("webkitfullscreenchange", () => { buttons.onFullScreen()});

  },
  onFullScreen: function(e) {

    if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement) {
      buttons.body.className = buttons.body.className + " isfullscreen";
    }
    else {
      buttons.body.className = buttons.body.className.replace(/\sisfullscreen/g, "");
      window.setTimeout(buttons.resetButtons,100);
    }

  },
  hasScrollbar: function() {

    let x,
        rootElem,
        overflowShown,
        overflowStyle,
        overflowYStyle,
        contentOverflows,
        alwaysShowScroll;

    if (typeof window.innerHeight === 'number') {
      x = window.innerHeight - document.documentElement.clientHeight;
      return [window.innerHeight > document.documentElement.clientHeight, x+1];
    }

    rootElem = document.documentElement || document.body;

    if (typeof rootElem.currentStyle !== 'undefined') {
      overflowStyle = rootElem.currentStyle.overflow;
    }

    overflowStyle = overflowStyle || window.getComputedStyle(rootElem, '').overflow

    if (typeof rootElem.currentStyle !== 'undefined') {
      overflowYStyle = rootElem.currentStyle.overflowY;
    }
    overflowYStyle = overflowYStyle || window.getComputedStyle(rootElem, '').overflowY;
    contentOverflows = rootElem.scrollHeight > rootElem.clientHeight;
    overflowShown = /^(visible|auto)$/.test(overflowStyle) || /^(visible|auto)$/.test(overflowYStyle);
    alwaysShowScroll = overflowStyle === 'scroll' || overflowYStyle === 'scroll';

    if ((contentOverflows && overflowShown) || (alwaysShowScroll)) {
      return true}
    else {
      return false}

  },
  getScrollTop: function() {

    if (typeof pageYOffset != 'undefined') {
      buttons._x = pageXOffset;
      return pageYOffset;
    }

  },
  getDocumentHeight: function(e) {

    let docHeight = Math.max(
      document.documentElement.clientHeight,
      document.body.scrollHeight, document.documentElement.scrollHeight,
      document.body.offsetHeight, document.documentElement.offsetHeight
    ) - ( buttons.hasScrollbar() ? buttons.scrollbar : 0 );

    if (docHeight > window.innerHeight) {
      if(docHeight - window.innerHeight - buttons.scrollable < 6) return;
      buttons.getVideo();
      buttons.scrollable = docHeight - window.innerHeight;
      buttons.onScroll();
    }

  },
  scrollToTop: function(e) {

    var y, start = buttons.scrolled;

    if (start > 0) {
      buttons.animate({
        duration: 1000,
        timing: function(timeFraction) {
          return Math.pow(timeFraction, 5);
        },
        draw: function(progress) {
          y = start - (progress * start);
          if (y < 0) y = 0;
          if (progress < 1) {
            window.scrollTo(buttons._x, y);
          }
          else {
            window.scrollTo(buttons._x, 0);
            buttons.count_accru += start;
            buttons.getVideo();
          }
        }
      });
    }

  },
  scrollToBottom: function(e) {

    var y, start = buttons.scrolled;
    var maxscroll = buttons.scrollable;

    if (maxscroll > start) {
      buttons.animate({
        duration: 1000,
        timing: function(timeFraction) {
          return Math.pow(timeFraction, 5);
        },
        draw: function(progress) {
          y = (progress * maxscroll) + ((1 - progress) * start);
          if (y > maxscroll) y = maxscroll;
          if (progress < 1) {
            window.scrollTo(buttons._x, y);
          }
          else {
            window.scrollTo(buttons._x, maxscroll + 2);
            buttons.count_accru += maxscroll - start;
            buttons.getVideo();
          }
        }
      });
    }

  },
  creepUp: function(e) {

    if (e === 1) {
      buttons.creep = 1;
      buttons.killCreeper();
      buttons.creeper = setInterval(buttons.creepUp, buttons.crawl_speed_ms);
    }
    buttons.scrolled = buttons.getScrollTop();
    if (buttons.creep && buttons.scrolled > 0) {
      window.scrollTo(buttons._x, buttons.scrolled - buttons.step);
      buttons.count_accru += buttons.step;
    }
    else buttons.killCreeper()

  },
  creepDn: function(e) {

    if (e === 1) {
      buttons.creep = 1;
      buttons.killCreeper();
      buttons.creeper = setInterval(buttons.creepDn, buttons.crawl_speed_ms);
    }
    buttons.scrolled = buttons.getScrollTop();
    if (buttons.creep && buttons.scrollable > buttons.scrolled) {
      window.scrollTo(buttons._x, buttons.scrolled + buttons.step);
      buttons.count_accru += buttons.step;
    }
    else buttons.killCreeper()

  },
  onResize: function(e) {

    buttons.getDocumentHeight(e);
    window.setTimeout(buttons.resetButtons,500);

  },
  onScroll: function(e) {

    buttons.scrolled = buttons.getScrollTop();
    if (! buttons.scrollable) { buttons.getDocumentHeight(e) }
    if (buttons.scrolled > 0) {
      buttons.toggle_up_btn("show");
    }
    else {
      buttons.toggle_up_btn("hide");
    }
    if (buttons.scrollable > buttons.scrolled) {
      buttons.toggle_dn_btn("show");
    }
    else {
      buttons.toggle_dn_btn("hide");
    }
  },
  toggle_up_btn: function(action) {

    if (action == "show" && buttons.up_btn_show != "show") {
      buttons.up_btn_show = "show";
      buttons.animate({
        duration: 400,
        timing: function(timeFraction) {
          return Math.pow(timeFraction, 2);
        },
        draw: function(progress) {
          buttons.up_ctn.style.right = -33 + (progress * 33) + 'px';
        }
      });
    }
    else if (action == "hide" && buttons.up_btn_show != "hide") {
      buttons.up_btn_show = "hide";
      buttons.animate({
        duration: 500,
        timing: function back(x, timeFraction) {
          return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x)
        }.bind(null, 2.8),
        draw: function(progress) {
          buttons.up_ctn.style.right = 0 - (progress * 33) + 'px';
        }
      });
    }

  },
  toggle_dn_btn: function(action) {

    if (action == "show" && buttons.dn_btn_show != "show") {
      buttons.dn_btn_show = "show";
      buttons.animate({
        duration: 400,
        timing: function(timeFraction) {
          return Math.pow(timeFraction, 2);
        },
        draw: function(progress) {
          buttons.dn_ctn.style.right = -33 + (progress * 33) + 'px';
        }
      });
    }
    else if (action == "hide" && buttons.dn_btn_show != "hide") {
      buttons.dn_btn_show = "hide";
      buttons.animate({
        duration: 500,
        timing: function back(x, timeFraction) {
          return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x)
        }.bind(null, 2.8),
        draw: function(progress) {
          buttons.dn_ctn.style.right = 0 - (progress * 33) + 'px';
        }
      });
    }

  },
  killCreeper: function() {

    if (this.creeper !== null) {
      clearInterval(this.creeper);
      this.creeper = null;
    }

  },
  getVideo: function() {

    if (buttons.user.settings.dimButtons) {
      var vid = document.querySelectorAll('video');

      if (vid.length) {
        for (let i = 0; i < vid.length; i++) {
          if (vid[i].scrollWidth > 100 && vid[i].scrollHeight > 50) {
            vid[i].addEventListener('mousemove', buttons.fadeOut, false);
          }
        }
        document.addEventListener("keydown", function(e) {
          if ((e.which == 38 || e.which == 40) && ["INPUT", "TEXTAREA"].indexOf(document.activeElement.tagName) < 0) {
            buttons.fadeOut()
          }
        }, false);
      }
    }

  },
  animate: function ({timing, draw, duration}) {

    let start = performance.now();

    requestAnimationFrame(function animate(time) {
      let timeFraction = (time - start) / duration;
      if (timeFraction > 1) timeFraction = 1;
      let progress = timing(timeFraction);
      draw(progress);
      if (timeFraction < 1 && buttons.allowScroll) {
        requestAnimationFrame(animate);
      }
    });

  },
  smartScroll_Settings: function(e) {

    let modal = document.querySelector(".smartScroll_Settings"), form;

    if (! buttons.settings_id && modal === null) {
      buttons.allowScroll = false;
      buttons.killCreeper();

      var s, i, n;
      var sel = '';
      var plus_sel = '';
      var minus_sel = '';
      var crawl_sel = '';
      let hostname = window.location.hostname;
      let m = hostname.match(/^([\w\-]*\.)?([\w\-]+\.((\w{3,4}$)|(\w{2}\.\w{2}$)))/i);

      if (m !== null && m.length > 2) {
        if (typeof m[1] == 'undefined') {m[1] = '';}
        hostname = m[1] + m[2];
      }

      let hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'],
          div = document.createElement("div"),
          div2 = div,
          html = '',
          id = 'a',
          doctype = document.createElement("br").outerHTML.indexOf('/') > 0 ? 'XHTML' : 'HTML';

      for (n = 0; n < 16; n++) {
        id += hex[Math.floor(Math.random()*16)];
      }

      var selected = doctype == 'HTML' ? 'selected' : 'selected="selected"';
      let rangetype = document.createElement("input");

      rangetype.setAttribute("type", "range");
      rangetype = rangetype.type != "text";
      if (! rangetype) {
        let opts = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,19,21,23,26,30,36,44,57,80,100];

        crawl_sel = '<select name="crawl_speed">';
        opts.forEach( function(opt) {
          sel = opt == buttons.user.settings.crawl_speed ? selected : '';
          crawl_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
        });
        crawl_sel += '</select>';
      }

      plus_sel = '<select name="top_plus" style="width: 52px;height: 20px;font-size: 12px;">';
      minus_sel = '<select name="bot_minus" style="width: 52px;height: 20px;font-size: 12px;margin-left:36px;">';

      [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,99].forEach( function(opt) {
        sel = opt == buttons.user.settings.top_plus ? selected : '';
        plus_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
        sel = opt == buttons.user.settings.bot_minus ? selected : '';
        minus_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
      });

      plus_sel += '</select>';
      minus_sel += '</select>';

      let checked = doctype == 'HTML' ? 'checked' : 'checked="checked"';
      let inputclose = doctype == 'HTML' ? '' : '</input>';
      let APOS = '\u0027';
      let NBSP = '\u00A0';
      let MIDDOT = '\u00B7';
      let CDATA1 = doctype == 'HTML' ? '' : '/*<![CD'+'ATA[*/';
      let CDATA2 = doctype == 'HTML' ? '' : '/*]'+']>*/';
      let ignoredHTML = '', ignored = this.user.settings.ignore.split(",");
      let padding = [60, 40, 65];
      let scrolledToDateTitle = 'That'+APOS+'s ';

      switch (true) {
        case this.user.count > 32602522:
            padding = [0,160,5];
            s = ((Math.round(this.user.count * 8.825569e-6)) / 10000);
            scrolledToDateTitle += (s == 1 ? 'The ' : s +' ')+'Light Second'+(s == 1 ? '' : 's')+'.';
          break;
        case this.user.count > 2676326:
            padding = [20,120,25];
            s = ((Math.round(this.user.count * 6.134495e-6)) / 100)
            scrolledToDateTitle += (s == 1 ? 'The ' : s +' Times the ')+'Width of the U.S.';
          break;
        case this.user.count > 669082:
            padding = [30,100,35];
            s = ((Math.round(this.user.count * 7.747293e-5)) / 100)
            scrolledToDateTitle += (s == 1 ? '' : s +' times ')+'the Altitude of the ISS.';
          break;
        case this.user.count > 3041:
            padding = [40,80,45];
            s = ((Math.round(this.user.count * 1.644e-2)) / 100);
            scrolledToDateTitle += s +' Mile'+(s == 1 ? '' : 's')+'.';
          break;
        default:
            s = ((Math.round(this.user.count * 8.68)) / 10);
            scrolledToDateTitle += s +' F'+(s == 1 ? 'oo' : 'ee')+'t';
      }

      let scrolledToDate = this.user.count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +',000 Pixels Smart Scrolled.';
      let addable = false;

      for (n = 0; n < ignored.length; n++) {
        if (ignored[n].length < 5) continue;
        addable = addable || hostname == ignored[n];
        ignoredHTML += '<span class="ignores"><button style="padding:0px 3px 1px;margin-right:6px;background-color:#ff3333;color:#fff;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px" onclick="document.forms[\'sssettings\'].remove.value+=\''+ignored[n]+',\';this.disabled=\'disabled\'" title="Mark '+ignored[n]+' for deletion from this list">x</button><span>'+ignored[n]+'</span></span><br />';
      }
      addable = addable ? '' : ('<span class="addable"><button style="padding:0px 3px 1px;margin-right:6px;background-color:#33ff33;color:#000;font-weight:bold;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px" onclick="document.forms[\'sssettings\'].add.value+=\''+hostname+'\';this.disabled=\'disabled\'" title="Mark '+hostname+' for addition to this list">+</button><span>'+hostname+'</span></span><br />');

      html = '<div id="'+id+'" style="width:500px;height:400px;margin:auto auto;border-radius:12px 54px 12px 100px;-webkit-border-radius:12px 54px 12px 100px;-moz-border-radius:12px 54px 12px 100px;border:3px solid #CCC;">'+
             '  <div style="width:500px;height:50px;background-color:#000;border-radius:12px 50px 0px 0px;-webkit-border-radius:12px 50px 0px 0px;-moz-border-radius:12px 50px 0px 0px;">'+
             '    <div style="width: 380px;height:40px;padding:12px 0 0 65px;color:#eee;font-size: 1.5em;font-weight: bold;background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBwSIh99fynEAAAD9klEQVRIx6XWzW9UVRjH8c+dzjBtAfsCUlIsKbSU8hZpijGRRAzhTY0Y4sqgiYQENVEXJiTEVUPQjSgr3Rhd+i+wKAYJSMJb5U2YAkljpSVAUlqgZZjOzHXR28tMKSSkZzKbc879nuc+z+/53RNsCc1oBEKPZCWft'+
                                     'WFcTighQBj909NsD5GaDhQIjcups0aHf50yqtZ6dS7rMywlJRCWPZFgKmgC0q5TuwWuOewUeGiv9e7I6JGRknoqsimgx2ptstJ8Tc44oCeaPyrQZa0aba44YkT6eaCsNts1W6jeCV3Ol6wdlfOjVUbVa3JY7xRURUvXE0yHbZZoVeOyPc4pL2i/GzZoUmNcg5wBFXFWH0tM5iarzUYtWlX50y6XJk9SqQIBjtnlikrtmm3Q7nHJMYkJZl6t7ZZYoso/9jofRRN41Q6rozIXnfSpXmmtmm1VI18OCuVs0qxVtR479ShGy20O+F2Xpriqf/ncoCrLNNpsvBw0rt0qDWbhtgsxptX3Nil6x3eaY9RZD1Gp0QrtcUwJyOlUb7YQuSgftPjNuxKKknY6aEFclAJCNWp1yEW7'+
                                     'E4yr064xKudanwgltTpovUARRaH3/GSxpCp7LBQKVVukVb2ccEJHOWvUmQ0KXrHfGwKLvSlUiM4rSNqh2oDANrXRS85RZ6mz0pOCXKlRZVSXQKPdRHEEcT8VBLZFgFBREOVpuTNPlL0o7p0g2jidXYiLID4gZVFpsueUbHmxEXqpFJSagbElS0H5GYDKdPRgsuVeeCQ8KAX1y5YYZxD9nrbUJythNPfIf6WvmHHLXJVRNcbcFag0vwyWELotK/CyymjlkVuuPVF2Wp9hDyPTGPGzDut86IKKEh0FLvrAOq/7xVg0/8CIPmnBBChpWK9BWQTO2Oe+ISd8rT+2rgrn7HbKPXftNyAQGHPLDUNR3aLy97hnVIBCFEPBSR+7IIkKJ3wZe1RWEYFhw/6OpROBMq64JYs6DTH'+
                                     'quH3OSzrtG6fjbC1VjVGDMjKxjpIToacc0aSoXadffeZmtHxEymtOOl6COaTRmGsGdZdIOTL/CqPuaVBUb7l5etyPGrffOdflo/Qu84MtxmUM6DYgFZt//DlK642spM1HkvYZiDKSjXW0wgHvG5Ux4JirZk3/OUoaMGyeRyp0anDRvTJJtvnWZnfccFO3SzFmSkQwy1WDNrtvnrcNORTrluW+8pZeIzK63S+LZkpEE1FlXXJbQd5qc92IctXqCxtdd9kfjimU+cVERMF096O8nHotVuhx1EO1tmlxTZ8hqacuMIGCYcHW8Hn3o6CsZdPPuE7lPZAsPNXjk+ekn+M+QdkzedWSIzO7+QklVJvlf7qjThcu+vTfAAAAAElFTkSuQmCC) no-repeat 10px center;">'+
             '    Smart Scroll Settings</div>'+
             '  </div>'+
             '  <form id="'+id+'_settings_form" name="sssettings" class="sssettings" action="javascript:void(0)" onsubmit="return false" style="padding:10px;height:330px;border-radius:0px 0px 10px 96px;-webkit-border-radius:0px 0px 10px 96px;-moz-border-radius:0px 0px 10px 96px;">'+
             '    <div style="width:100%;height:240px;padding-bottom:0px;">'+
             '      <div style="width:50%;height:100%;padding:0px;float:left;border-radius:0px 0px 0px 96px;-webkit-border-radius:0px 0px 0px 96px;-moz-border-radius:0px 0px 0px 96px;">'+
             '        <span style="margin-left:30px;">Slow scrolling speed:</span><br />'+ (rangetype ?
             '        <input name ="crawl_speed" type="range" min="1" max="100" step="1" value="'+this.user.settings.crawl_speed+'" onchange="document.getElementById(\'crawl_speed_now\').innerHTML=this.value" style="width: 180px;">'+inputclose+' <span id="crawl_speed_now">'+this.user.settings.crawl_speed+'</span><br />'+
             '        <span style="font-size:11px;">'+NBSP+'Slow '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Fast '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Faster</span><br /><br />' :
             '        '+crawl_sel+'<br />'+
             '        <span style="font-size:11px;">1 = Slow thru 100 = Fast</span><br /><br />')+
             '        <input type="checkbox" name="bottomless_pages" id="bottomless1" '+(this.user.settings.bottomless_pages ? checked : "")+' >'+inputclose+' <label for="bottomless1" title="Recalculates when pages add content to bottom">Bottomless pages</label><br />'+
             '        <input type="checkbox" name="refresh" id="refresh1" '+(this.user.settings.refresh ? checked : "")+' >'+inputclose+' <label for="refresh1" title="Refresh current page upon critical settings changes made here">Auto page refresh</label><br />'+
             '        <input type="checkbox" name="dimButtons" id="dimButtons1" '+(this.user.settings.dimButtons ? checked : "")+' >'+inputclose+' <label for="dimButtons1" title="Buttons will disappear when over videos after 3 seconds">Fade out over video</label><br />'+
             '        <div style="margin: 6px 0 2px 30px;">Slow scroll trigger</div>'+
             '        <span><input type="radio" name="crawl_trigger" id="trigger1" value="middleclick"'+(this.user.settings.crawl_trigger == "middleclick" ? checked : "")+' >'+inputclose+' <label for="trigger1" title="Middle mouse button held down">Middleclick</label> '+
             '              <input type="radio" name="crawl_trigger" id="trigger2" value="hover" '+(this.user.settings.crawl_trigger == "hover" ? checked : "")+' style="margin-left:10px;">'+inputclose+' <label for="trigger2" title="Mouse pointer held over">Hover</label></span><br />'+
             '        <div style="margin: 6px 0 2px 30px;">Button Position</div>'+
             '        <span><input type="radio" name="position" id="position1" value="top" onmouseout="this.blur()" '+(this.user.settings.position == "top" ? checked : "")+'>'+inputclose+' <label for="position1" title="Always at top right">Top</label>'+
             '              <input type="radio" name="position" id="position2" value="middle" onmouseout="this.blur()" '+(this.user.settings.position == "middle" ? checked : "")+' style="margin-left:6px;">'+inputclose+' <label for="position2" title="Always at middle right">Middle</label>'+
             '              <input type="radio" name="position" id="position3" value="bottom" onmouseout="this.blur()" '+(this.user.settings.position == "bottom" ? checked : "")+' style="margin-left:6px;">'+inputclose+' <label for="position3" title="Always at bottom right">Bottom</label></span><br />'+
             '        <span>'+plus_sel+'<span title="Pixels down from top">:Plus</span>'+minus_sel+'<span title="Pixels up from bottom">:Less</span></span><br />'+
             '      </div>'+
             '      <div style="width:50%;height:100%;float:left;">'+
             '        <div style="width:100%;height:20px;text-align:center;" title="(Scroll buttons will not be used)">Ignored Sites</div>'+
             '        <div id="ssignored" style="width:224px;height:180px;overflow-y: auto;overflow-x: hidden;border: 1px solid #000;padding: 6px;line-height:1.3;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;">'+
             '        '+addable+ignoredHTML+'</div>'+
             '        <div style="width:100%;height:12px;text-align:center;font-style: italic;color:blue;font-size: 12px;padding-top: 4px;cursor:help" title="'+scrolledToDateTitle+'">'+scrolledToDate+'</div>'+
             '      </div>'+
             '    </div>'+
             '    <div style="width:100%;height:90px;border-radius:0px 0px 10px 96px;-webkit-border-radius:0px 0px 10px 96px;-moz-border-radius:0px 0px 10px 96px;">'+
             '      <div style="width:fit-content;width: -moz-fit-content;height:80px;margin:10px auto 0px;background-color:transparent">'+
             '        <button id="'+id+'_settings_close" style="background-color:#ff3333;padding:30px '+padding[0]+'px;border-radius:0px 0px 0px 74px;-webkit-border-radius:0px 0px 0px 74px;-moz-border-radius:0px 0px 0px 74px;">Cancel</button> '+
             '        <button id="'+id+'_settings_donate" style="background-color:#ffff33;padding:30px '+padding[1]+'px;">Donate</button>'+
             '        <button id="'+id+'_settings_save" style="background-color:#33ff33;padding:30px '+padding[2]+'px;">Save</button>'+
             '      </div>'+
             '    </div>'+
             '    <input name ="remove" type="hidden" value="">'+inputclose+'<input name ="add" type="hidden" value="">'+inputclose+'<input name ="'+id+'" type="hidden" value="">'+inputclose+
             '    <input name ="submit" type="submit" value="" style="width:0px;height:0px;opacity:0;">'+inputclose+
             '  </form>'+
             '</div>'+
             '<style type="text/css">'+CDATA1+
             '  #pdus div, #pdus span, #pdus label, #pdus form, #pdus input, #pdus button {margin:0px;padding:0px;border:0px;color:#333;box-sizing:content-box;background-color:#EEE; font: 14px \'Titillium Web\', \'Helvetica Neue\', Helvetica, Arial, sans-serif; box-shadow: none;min-height:0px;line-height: 1;text-align:left; text-decoration:none;outline:none; }'+
             '  #pdus div, #pdus form  {display:block;} #pdus span, #pdus label {display:inline;} #pdus input, #pdus button {display:inline-block;}'+CDATA2+
             '</style>';
      div.setAttribute('id', 'pdus');
      div.className = "smartScroll_Settings";
      div.style = 'width:100%;height:100%;margin:0;padding:0;position:fixed;top:0px;left:0px;background-color: rgba(0, 0, 0, 0.7);z-index:84000;';
      div.innerHTML = html;
        /* Some (unmentionable large) sites remove settings modal as soon as it is appended */
      buttons.body.removeChild=function() {return div2}
      buttons.body.replaceChild=function() {return div2}
      if (e && e == 'removed') {
          buttons.body.innerHTML += div.outerHTML
      }
      else {
        buttons.body.appendChild(div);
        setTimeout(function() {
          if (document.querySelector(".smartScroll_Settings") === null) {
            buttons.settings_id = "";
            buttons.smartScroll_Settings('removed');
          }
        }, 300);
      }
      buttons.settings_id = id;
      form = document.querySelector('form#'+id+'_settings_form');
      form.querySelector('#'+id+'_settings_close').addEventListener('click', function(e) { buttons.settings_close() }, false);
      form.querySelector('#'+id+'_settings_donate').addEventListener('click', function(e) { buttons.settings_donate() }, false);
      form.querySelector('#'+id+'_settings_save').addEventListener('click', function(e) { buttons.onSettingsSave() }, false);
      form.querySelector('#'+id+'_settings_save').addEventListener('change', function(e) { buttons.onSettingsSave() }, false);
      form.querySelector('#position1').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);
      form.querySelector('#position2').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);
      form.querySelector('#position3').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);

      let options1 = form.top_plus.options;
      let options2 = form.bot_minus.options;

      for (i = 0;i < options1.length; i++) {
        options1[i].addEventListener('mouseup', function(e) { buttons.updateButtonCss(e) }, false);
        options2[i].addEventListener('mouseup', function(e) { buttons.updateButtonCss(e) }, false);
      };

    }
    else {
      buttons.settings_close()
    }

  },
  onSettingsSave: function() {

    var form = document.querySelector('form#'+buttons.settings_id+'_settings_form');
    var inputs = form.querySelectorAll('input, select'),
        settings = { ignore: this.user.settings.ignore },
        input,
        val,
        i, n,
        ignoreUpdated = false,
        refreshNeeded = false;

    if (form.querySelector('input[name="'+buttons.settings_id+'"]') !== null) {
      for (i = 0; i < inputs.length; i++) {
        val = null;
        input = inputs[i];

        switch (input.type) {
          case 'checkbox':
            val = input.checked;
            if (this.user.settings[input.name] != val && input.name != 'refresh') {
              refreshNeeded = true;
            }
            break;
          case 'select':
          case 'select-one':
            val = parseInt(input[input.selectedIndex].value);
            break;
          case 'radio':
            if (input.checked) {
              val = input.value;
              if (this.user.settings[input.name] != val) {
                refreshNeeded = true;
              }
            }
            else {continue;}
            break;
          case 'range':
              val = parseInt(input.value);
            break;
          case 'hidden':
            if (input.name == buttons.settings_id) {
              continue;
            }
            else if (input.name == "remove" && input.value != "") {
              let thisUrl = false;
              let urls = input.value.split(",");

              for (n = 0; n < urls.length; n++) {
                if (urls[n].length < 5) continue;
                if (urls[n].indexOf(window.location.hostname) !=-1) {
                  thisUrl = true;
                }
                var url = new RegExp(urls[n] +",", "gi");
                settings.ignore = settings.ignore.replace(url, "");
              }
              refreshNeeded = refreshNeeded || thisUrl;
              continue;
            }
            else if (input.name == "add" && input.value != "") {
              settings.ignore += input.value.trim() +',';
              refreshNeeded = ignoreUpdated = true;
              continue;
            }
            else { continue; }
            break;
          default: continue;
        }
        if (val !== null) {
          settings[input.name] = val;
        }
      }
      if (ignoreUpdated) {
        let ignore = settings.ignore.split(',');

        ignore.pop();
        if (ignore.length > 1) {
          ignore.sort();
          settings.ignore = ignore.join() +',';
        }
      }
      buttons.saveSettings({name: 'user_settings', value: settings});
      if (refreshNeeded && settings.refresh) {
        window.location = window.location;
      }
      else {
        this.resetButtons();
      }
    }
    buttons.settings_close();

  },
  settings_close: function(e) {

    let modal = document.querySelector(".smartScroll_Settings");

    if (modal !== null) {
      modal.remove();
    }
    buttons.settings_id = "";
    if (typeof e != "undefined" && e == 'unload') {
      buttons.toggle_up_btn("hide");
      buttons.toggle_dn_btn("hide");
    }
    else { buttons.resetButtons(); }

  },
  saveAccrued: function(e) {

    if (buttons.count_accru > 1000) {
      buttons.initSettings({name: "count"});
    }

  },
  saveSettings: function(settings) {

    if (typeof settings == 'undefined' || typeof settings.name == 'undefined' || settings.name == '') {
      console.error('saveSettings() input error');
      return;
    }

    switch(settings.name) {
      case 'user_settings':
        this.GM.setValue('settings', JSON.stringify(settings.value));
        break;
      case 'count':
          if (this.count_accru > 999) {
            let totalCount = Math.round(this.count_accru / 1000) + settings.value;

            this.GM.setValue('count', totalCount);
            this.user.count = totalCount;
            this.count_accru = 0;
          }
          else {
            this.user.count = settings.value;
          }
        break;
    }

  },
  settings_donate: function() {

    let donate_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QHFFSLZ7ENUQN&source=url";
    window.open(donate_url, '_blank');

  },
  updateButtonCss: function(e) {

    let style = document.querySelector('#smartscrollstyle');
    let form = document.querySelector('form#'+buttons.settings_id+'_settings_form');
    let position2 = form.position2.checked;
    let position3 = form.position3.checked;
    let position = 'top';

    if (position2) position = 'middle';
    else if (position3) position = 'bottom';

    let settings = {
      position: position,
      top_plus: parseInt(form.top_plus[form.top_plus.selectedIndex].value),
      bot_minus: parseInt(form.bot_minus[form.bot_minus.selectedIndex].value),
      bottomless_pages: buttons.user.settings.bottomless_pages
    };
    style.innerHTML = buttons.buttonCss(settings);

  },
  buttonCss: function(settings) {

    let btn_css = '',
        dn_btn_css = '',
        updn_btn_css = '';

    settings = typeof settings === 'object' ? settings : this.user.settings;
    if (settings.position == 'top') {
      updn_btn_css = 'top:'+(settings.top_plus)+'px;';
      dn_btn_css = 'margin-top:33px;';
    } else if (settings.position == 'bottom') {
      updn_btn_css = 'bottom:'+(settings.bot_minus+33)+'px;';
      dn_btn_css = 'margin-bottom:-33px;';
    } else if (settings.position == 'middle') {
      updn_btn_css = 'bottom:50%;';
      dn_btn_css = 'margin-bottom:-33px;';
    }

    btn_css += '#up_btn { position:fixed; right:-33px; z-index:54000; height:36px; width:33px; display:inline; cursor:pointer; background:url('+up_btn_src+') no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); }';
    btn_css += '#dn_btn { position:fixed; right:-33px; z-index:54000; height:36px; width:33px; display:inline; cursor:pointer; '+dn_btn_css+'background:url('+dn_btn_src+') no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); }';
    btn_css += '.updn_btn { '+updn_btn_css+'opacity:0.65; } .isfullscreen > .updn_btn { display:none;}';
    btn_css += '.sssettings button:hover {opacity:0.85;} .updn_btn:hover { opacity:1; } .sssettings button[disabled], .sssettings button[disabled]:hover { opacity:0.35;} ';
    btn_css += '.sssettings span button:hover:enabled {line-height: 1.4 !important; width: 10px !important;} .sssettings .ignores button[disabled] + span { opacity:0.5;} .sssettings .addable button + span { opacity:0.5;} .sssettings .addable button[disabled] + span { opacity:1;}';

    if (settings.bottomless_pages) {
      btn_css += 'iframe.resize_frame {position: absolute; display: block ;top: 0; bottom: 0; left: 0; height: 100%; opacity: 0; z-index: 0; width: 0; border: 0; background-color: transparent;}';
      if ('contentType' in document) { // Firefox
        if (document.contentType.indexOf("image") ==-1) {
          btn_css += 'body {position:relative !important;} body.isfullscreen {position:initial !important;}';
        }
      }
      else {
        btn_css += 'body {position:relative !important;} body.isfullscreen {position:initial !important;}';
      }
    }

    return btn_css;

  },
  scrolledUpdate: function(e) {

    if (buttons.count_accru > 1000 || e === true) {
      buttons.initSettings({name: "count"});
    }
    window.setTimeout(buttons.scrolledUpdate, 120000);

  },
  resetButtons: function (e) {

    buttons.allowScroll = true;
    buttons.up_btn_show = "";
    buttons.dn_btn_show = "";
    buttons.getDocumentHeight(e);
    buttons.crawl_speed_ms = Math.round(200 / buttons.user.settings.crawl_speed);

  },
  syncGM_getValue: function (e) {

    if (e.detail.setting == 'settings') {
      buttons.initSettings(e.detail);
    }
    else if (e.detail.setting == 'count') {
      if (e.detail.value && e.detail.value != "{}") {
        buttons.saveSettings({name: "count", value: JSON.parse(e.detail.value)});
      }
    }

  },
  initSettings: function (detail) {

    if (typeof detail.name != 'undefined') {
      this.GM.getValue(detail.name, "{}").then(function (value) {

        var details = {
          detail: {
            setting: detail.name,
            value: value || "{}"
          }
        };

        try{
          buttons.syncGM_getValue(details);
        }
        catch (e) {
          console.warn( 'Smart Scroll: UPDATE Your Browser ',e.name );
        }
      });

    }
    else {

      var settings,
          setting = detail.setting,
          value = detail.value;

      if (! value || value == "{}") {
        settings = false;
        console.warn( 'Smart Scroll: NO storage database');
      }
      else {
        settings = JSON.parse(value);
        //console.log( 'Smart Scroll: Initializing settings from storage database');
      }

      if (! settings) {
        settings = this.user;
        console.log( 'Smart Scroll: Installing storage database...' );
        for (let k in settings) {
          let jstr = JSON.stringify(settings[k]);

          this.GM.setValue(k, jstr);
          console.log( 'Smart Scroll: Inserting '+k+': '+ jstr);
        }
        settings = this.user.settings;
        console.log( 'Smart Scroll: dONE' );
      }
      this.user.settings = settings;
      this.scrolledUpdate(true);
      this.monkey();
      this.monkey = null;
    }

  },
  init: function () {

    if (typeof GM_info === "object" || typeof GM === "object") {
      this.is_userscript = true;
      if (typeof GM === "undefined") {
        console.log( 'Smart Scroll: Legacy GM_setValue enabled' );
        this.GM = {
          info: GM_info,
          setValue: GM_setValue,
          getValue: function () {
            return new Promise( (resolve, reject) => {
              try {
                resolve(GM_getValue.apply(this, arguments));
              }
              catch (e) { reject(e) }
            });
          }
        };
      }
      else { this.GM = GM; }

      var outerscroll = document.createElement("div");
      var innerscroll = document.createElement("div");

      outerscroll.style = "position:absolute;top:0px;background-color:transparent;";
      innerscroll.style = "height:"+ (window.innerHeight - 100) +"px;width:100px;overflow:scroll;background-color:transparent;";
      this.body.appendChild(outerscroll);
      outerscroll.appendChild(innerscroll);
      let h1 = innerscroll.scrollHeight;
      innerscroll.style.overflow = 'hidden';
      let h2 = innerscroll.scrollHeight;
      this.scrollbar = h2 - h1;
      innerscroll.remove();
      outerscroll.remove();

      this.initSettings({name: "settings"});
    }

  },
  head: document.head || document.getElementsByTagName('head')[0],
  body: document.body || document.documentElement,
  user: {
    settings: {
      bottomless_pages: true,
      crawl_trigger: 'hover',
      position: 'bottom',
      dimButtons: true,
      crawl_speed: 21,
      refresh: true,
      bot_minus: 30,
      top_plus: 0,
      ignore: ''
    },
    count: 0
  },
  crawl_speed_ms: 10,
  opacity_timer: null,
  allowScroll: true,
  settings_id: "",
  up_btn_show: "",
  dn_btn_show: "",
  count_accru: 0,
  scrollable: 0,
  scrollbar: 0,
  scrolled: 0,
  creeper: null,
  up_ctn: null,
  dn_ctn: null,
  creep: !1,
  step: 5,
  GM: null,
  _x: 0
};

var _once = 0;
var up_btn_src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAkCAQAAACtIJtXAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBkQOCqvuzNgAAABWElEQVRIx6XWO7aDIBCA4V+OWYOaVbiDFGlccopkD/Sp0qiswcJb+ODhgNwjXXh8DpFhLKa558uVVvxmuF8iyi8PcWBkCHoaapmILTdA5fQZDJXIlPHl/vSlX2LKENDCcoCaemdab7Q8Am1kzxuj0d4clQ9sTAtoxiORB0jITgyZg'+
                 'EUGnxgxVJnAglSYNQ5lY2iEqR03bnTCSLPHoVIxdHwA+AiIjUPFY9iAGLLFsW7kGIMLyEi9JoCS/64QiEUSJVzgyfMEUWfAi9cJIhA+AARI1kZ8IEQihHHS5n0AXOTtpKWxyd5gGPbX+mASn/YKfm+nSYUnPrfZE63CE5/b7IlWx8z7XwzOG2mCuygNaCerVPxCSwP2elKpWzEHCG7wmhaNjpQcW2MSRWBB5JITK1FCNXNLjl8QyS2ILuO2KlWWe/HjoM6+z4vffO0DBco7V1sB09xfIv4A9ICG7qoP1KkAAAAASUVORK5CYII=';
var dn_btn_src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAkCAQAAACtIJtXAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBkRAC0ngnAPAAABV0lEQVRIx6XWO5KDMAyA4R8PnAHIKbjBFtkiR06TIjdwnyoN4DOkYAsClm2Z8Q4q/fhGgGxRfZaRF2eiei9wOUXUL37UiZkpGunpdCK33QGtGHM4WpWp89vD5eu4xtQxYJXtAB3dzgzBbJ0CQ+aZN8ZigzWmHNiYAbDMKVEGaMhOT'+
                 'IWAR6aQmHG0hcCKtLhvHsbn0P+rJvs9D5Pm8KSh4ZZsutHQ8EzyMGkOvwA8IuTGQ8zKPL4Por0HiWxA/D6iutjimiASuCbrFeIeISFwLyFi5BjIECFyDGSJFMkBO+HEsdEQDZhxnuhFxWuInsFWTbWstE5BcuEr2sQVXxq+ok168kpCniojK94WIuv11McfNb3QjgF/PZmjW7EEiG7wjgGLzbQc32MOmsCK6C0n16KUbiZbTtgQKW2IkpHRHrXlUf056Irv8+q9nPtBgfrC2ajgs4yniD+XioU/GQ3iSgAAAABJRU5ErkJggg==';
var root = buttons.body;
var host = window.location.hostname;
  /* Not in Frames */
if (window.self == window.top) {
  switch(true) {
    /* Special case sites */
    case host.indexOf('youtube') !=-1 :
      buttons.hideOnFullScreen();
      window.addEventListener("yt-navigate-finish", function(e) { buttons.reLoadStart(e) }, false);
      /* body remains 0 height propter full-screen styling */
      if (root = document.querySelector("ytd-app #content")) {
        buttons.init();
      }
      else {
        buttons.body.addEventListener('yt-page-data-updated', function(e) {
          if (root = document.querySelector("ytd-app #content")) {
            if (_once++ < 1) buttons.init();
          }
        }, false);
      }
      break;
    default: buttons.init();
  }
}
}());