// ==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 // @downloadURL none // ==/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 = ''; } plus_sel = ''; [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 += ''; sel = opt == buttons.user.settings.bot_minus ? selected : ''; minus_sel += ''; }); plus_sel += ''; minus_sel += ''; let checked = doctype == 'HTML' ? 'checked' : 'checked="checked"'; let inputclose = doctype == 'HTML' ? '' : ''; let APOS = '\u0027'; let NBSP = '\u00A0'; let MIDDOT = '\u00B7'; let CDATA1 = 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 += ''+ignored[n]+'
'; } addable = addable ? '' : (''+hostname+'
'); html = '
'+ '
'+ '
'+ ' Smart Scroll Settings
'+ '
'+ '
'+ '
'+ '
'+ ' Slow scrolling speed:
'+ (rangetype ? ' '+inputclose+' '+this.user.settings.crawl_speed+'
'+ ' '+NBSP+'Slow '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Fast '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Faster

' : ' '+crawl_sel+'
'+ ' 1 = Slow thru 100 = Fast

')+ ' '+inputclose+'
'+ ' '+inputclose+'
'+ ' '+inputclose+'
'+ '
Slow scroll trigger
'+ ' '+inputclose+' '+ ' '+inputclose+'
'+ '
Button Position
'+ ' '+inputclose+' '+ ' '+inputclose+' '+ ' '+inputclose+'
'+ ' '+plus_sel+':Plus'+minus_sel+':Less
'+ '
'+ '
'+ '
Ignored Sites
'+ '
'+ ' '+addable+ignoredHTML+'
'+ '
'+scrolledToDate+'
'+ '
'+ '
'+ '
'+ '
'+ ' '+ ' '+ ' '+ '
'+ '
'+ ' '+inputclose+''+inputclose+''+inputclose+ ' '+inputclose+ '
'+ '
'+ ''; 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(); } } }());