// ==UserScript==
// @name Smoothscroll
// @include http*
// @author Creec Winceptor
// @description Smooth scrolling on pages using javascript and jquery
// @namespace https://gf.qytechs.cn/users/3167
// @run-at document-load
// @grant GM_info
// @grant unsafeWindow
// @version 0.0.1.20160524014511
// ==/UserScript==
//SETTINGS HERE
//Smoothness factor value (how strong the smoothing effect is)
//values: 1-(infinite) (default = 50)
var smoothness = 30;
//Scroll sensitivity
//values: anything? (default 1.00)
var sensitivity = 1.00;
//Acceleration sensitivity
//values: anything? (default 1.00)
var acceleration = 1.00;
//Refreshrate setting
//values: 30-144 (default = 60/72/120/144 = same as your monitor hz)
var baserefreshrate = 72;
//Alternative scrolling multiplier
//values: true/false (try to set this to true if scrolling is too slow/doesn't work)
var alternative_sesitivity_multiplier = false;
var minimal_jquery_version = 200;
var DEBUG = false;
//CODE STARTS HERE
if (window.top != window.self) //don't run on frames or iframes
return;
if (smoothness>100)
{
smoothness = 100;
}
if (baserefreshrate <= 30 || baserefreshrate>144)
{
baserefreshrate = 144;
}
refreshrate = baserefreshrate;
var animationduration = Math.round(1000/refreshrate);
//var relativeratio = Math.round(51-smoothness/2)/100;
var relativeratio = Math.round(1/(1+smoothness)*100)/100;
//var relativeratio = relativeratio;
var lastLoop = new Date;
//var lastrefreshrate = 0;
function gameLoop() {
var thisLoop = new Date;
var refreshrate0 = 1000 / (thisLoop - lastLoop + 1);
lastLoop = thisLoop;
refreshrate = refreshrate + (refreshrate0-refreshrate)*0.01;
refreshrate = Math.round(refreshrate);
if (DEBUG)
{
console.log(refreshrate);
}
animationduration = Math.round(1000/(refreshrate));
//var relativeratio = Math.round(51-smoothness/2)/100;
relativeratio = Math.round(1/(1+smoothness*refreshrate/baserefreshrate)*100)/100;
}
gameLoop();
function InitSmoothscroll()
{
var startposition = false;
var targetposition = 0;
var position = 0;
var scrollfocus = $0('body');
function hasScrollBarVisible(element)
{
//return (document.documentElement.scrollHeight !== document.documentElement.clientHeight);
// Get the computed style of the body element
var cStyle = element.currentStyle||window.getComputedStyle(element, "");
// Check the overflow and overflowY properties for "auto" and "visible" values
var scrollbar1 = cStyle.overflow == "scroll" || cStyle.overflowY == "scroll";
var scrollbar2 = cStyle.overflow == "auto" || cStyle.overflowY == "auto";
var scrollbar = scrollbar1 || scrollbar2;
return scrollbar;
}
function hasscrollbars(scrollfocus)
{
var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
var parentelement = $0(scrollfocus).parent();
if ( $0(parentelement))
{
//if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea"))
if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea") || $0(parentelement).is("article") || $0(parentelement).is("article"))
{
return true;
}
else
{
if ($0(parentelement).hasClass( "yt-scrollbar" ) || $0(scrollfocus).hasClass( "yt-scrollbar" ))
{
return true;
}
return hasvisiblescrollbars;
}
}
else
{
//scrollfocus = $0('body');
//maxposition = $0(scrollfocus).height();
return hasvisiblescrollbars;
}
return false;
}
function UpdatePosition(element)
{
gameLoop();
var positiondelta = $0(element)[0].getAttribute( "positiondelta" );
//var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
var smoothdelta = Math.sqrt(positiondelta*positiondelta*relativeratio);
if (positiondelta<0)
{
smoothdelta = smoothdelta*(-1);
}
//var relative = position - $0(element).scrollTop();
//console.log("smoothdelta:" + smoothdelta);
if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
{
$0(element).stop();
$0(element).animate({
scrollTop: '+=' + Math.round(positiondelta)
}, animationduration, "linear", function() {
$0(element).attr( "positiondelta",0 );
$0(element)[0].setAttribute( "positiondelta",0 );
if (DEBUG)
{
$0(element).css( "border", "1px solid red" );
}
});
}
else
{
$0(element).stop();
$0(element).animate({
scrollTop: '+=' + Math.round(smoothdelta)
}, animationduration, "linear", function() {
$0(element).attr( "positiondelta",positiondelta-smoothdelta );
$0(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
UpdatePosition(element);
if (DEBUG)
{
$0(element).css( "border", "1px solid red" );
}
});
}
}
function MouseScroll (x,y,e) {
scrollfocus = UpdateFocus(x,y);
var positiondelta = 0;
var lastscrolltop = 0;
var parentelement = $0(scrollfocus).parent();
if ( $0(parentelement))
{
if ($0(parentelement).is("textarea") || $0(scrollfocus).is("textarea"))
{
//return true;
}
else
{
if ( $0(parentelement).height() < $0(scrollfocus).height())
{
//maxposition = $0(scrollfocus).height() - $0(parentelement).height();
}
else
{
if ($0(scrollfocus).height()==0)
{
//scrollfocus = $0('body');
//maxposition = $0(scrollfocus).height();
}
//scrollfocus = $0('body');
//return MouseScroll (event);
//return true;
}
}
}
else
{
scrollfocus = $0('body');
//maxposition = $0(scrollfocus).height();
}
var rolled = y;
//console.log("rolled: " + rolled);
//if ($0(scrollfocus).data("positiondelta" )==undefined)
//$embellishment.data("embellishmentid",1)
if ($0(scrollfocus)[0].getAttribute("positiondelta")==undefined)
{
positiondelta = 0;
//console.log("positiondelta: undefined");
}
else
{
positiondelta = $0(scrollfocus)[0].getAttribute("positiondelta");
//console.log("positiondelta: " + positiondelta);
}
positiondelta = positiondelta*1;
var lastscrolltop = $0(scrollfocus).scrollTop();
$0(scrollfocus).scrollTop(lastscrolltop+rolled);
if ($0(scrollfocus).scrollTop()==lastscrolltop)
{
if (!$0(scrollfocus).is("body"))
{
focus = parentelement;
//focus = UpdateFocus(event);
//return MouseScroll (event);
//console.log("false");
return false;
}
else
{
//console.log("true");
return false;
}
}
else
{
e.preventDefault();
}
$0(scrollfocus).scrollTop(lastscrolltop);
var direction = rolled/Math.abs(rolled);
//var positiondeltadelta = rolled*sensitivity + Math.sqrt(Math.abs(positiondelta/rolled))*acceleration*rolled;
//var positiondeltadelta = rolled*(sensitivity+Math.sqrt(Math.abs(positiondelta))*acceleration);
//
var positiondeltadelta = Math.round(rolled*sensitivity + Math.sqrt(Math.abs(positiondelta-rolled*sensitivity))*acceleration*rolled*0.03/sensitivity);
positiondelta = positiondelta + positiondeltadelta;
$0(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
UpdatePosition($0(scrollfocus));
//element.innerHTML = "";
//console.log("pos:" + position);
//event.preventDefault();
return true;
}
function canscroll(element, dir)
{
var scrollable = $0(element);
var lastscrolltop = $0(scrollable).scrollTop();
$0(scrollable).scrollTop(lastscrolltop+dir);
if ($0(scrollable).scrollTop()==lastscrolltop)
{
$0(scrollable).scrollTop(lastscrolltop);
return false;
}
else
{
$0(scrollable).scrollTop(lastscrolltop);
return true;
}
}
function UpdateFocus(x,y) {
/*var dir = 0;
if ('wheelDelta' in event) {
dir = event.wheelDelta;
}
else { // Firefox
// The measurement units of the detail and wheelDelta properties are different.
dir = event.detail*(-120);
}*/
var dir = y;
//console.log(dir);
//dir = dir*(-1);
//
var nodelist = document.querySelectorAll( ":hover" );
$0(nodelist).stop();
scrollfocus = $0('body');
for (var i = nodelist.length-1; i >= 0; i--) {
//var parent = nodelist[i-1];
var newfocus = nodelist[i];
if (DEBUG)
{
$0(newfocus).css( "border", "1px solid blue" );
//var debugtimer = setTimeout(function(){ $0(newfocus).css( "border", "0px solid white" ); }, 1000);
}
//if ($0(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
{
scrollfocus = $0(newfocus);
return newfocus;
}
}
return scrollfocus;
}
$0('body').bind({
/*
mousewheel: function(e) {
if (DEBUG)
{
console.log(scrollfocus);
}
console.log("scrolling");
MouseScroll(e.originalEvent);
},
*/
mousedown: function(e) {
if (DEBUG)
{
console.log(scrollfocus);
}
if (scrollfocus)
{
$0(scrollfocus)[0].setAttribute( "positiondelta",0 );
$0(scrollfocus).stop();
}
//scrollfocus = UpdateFocus(e.originalEvent);
//console.log("click");
}
});
//Init(window);
(function(window,document) {
var prefix = "", _addEventListener, onwheel, support;
// detect event model
if ( window.addEventListener ) {
_addEventListener = "addEventListener";
} else {
_addEventListener = "attachEvent";
prefix = "on";
}
// detect available wheel event
support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
"DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
window.addWheelListener = function( elem, callback, useCapture ) {
_addWheelListener( elem, support, callback, useCapture );
// handle MozMousePixelScroll in older Firefox
if( support == "DOMMouseScroll" ) {
_addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
}
};
function _addWheelListener( elem, eventName, callback, useCapture ) {
elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
!originalEvent && ( originalEvent = window.event );
// create a normalized event object
var event = {
// keep a ref to the original event object
originalEvent: originalEvent,
target: originalEvent.target || originalEvent.srcElement,
type: "wheel",
deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
deltaX: 0,
deltaZ: 0,
preventDefault: function() {
originalEvent.preventDefault ?
originalEvent.preventDefault() :
originalEvent.returnValue = false;
}
};
// calculate deltaY (and deltaX) according to the event
if ( support == "mousewheel" ) {
event.deltaY = - 1/40 * originalEvent.wheelDelta;
// Webkit also support wheelDeltaX
originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
} else {
event.deltaY = originalEvent.detail;
}
// it's time to fire the callback
return callback( event );
}, useCapture || false );
}
})(window,document);
addWheelListener( window, function( e ) {
var mul = 1;
if (alternative_sesitivity_multiplier)
mul = 40;
//console.log( e.deltaY );
MouseScroll(e.deltaX*mul,e.deltaY*mul, e);
});
console.log("Smoothscroll initiated!");
}
var JQUERY = false;
var OWNJQUERY = false;
var OLDJQUERY = false;
//max retries
var r_max = 10;
var r_count = 0;
function Init() {
//if (typeof jQuery == 'function') {
//if (typeof jQuery == 'undefined' || typeof $ == 'undefined' )
JQUERY = true;
if (typeof $ == 'undefined' )
{
JQUERY = false;
}
OWNJQUERY = true;
if (typeof $0 == 'undefined' )
{
OWNJQUERY = false;
}
if (!OWNJQUERY){
if (JQUERY) {
var versiontable = $.fn.jquery.split('.');
var version = 0;
for (var i = versiontable.length-1; i >= 0; i--) {
var power = versiontable.length-i;
version += Math.pow(10,power-1)*versiontable[i];
}
if (version<=minimal_jquery_version)
{
console.log("Page jQuery OLD! Version: " + version);
if (typeof old$ == 'undefined') {
console.log("Saving old jQuery...");
old$ = $;
oldjQuery = jQuery;
OLDJQUERY = true;
}
}
else
{
$0 = $;
OWNJQUERY = true;
}
}
else
{
console.log("Page jQuery Missing!");
}
}
if (!OWNJQUERY)
{
console.log("Loading new jQuery...");
//this.$ = this.jQuery = jQuery.noConflict(true);
//var $ = jQuery.noConflict();
//this.$ = this.jQuery = jQuery.noConflict(true);
var filename = "https://code.jquery.com/jquery-2.2.3.js";
var fileref = document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", filename);
if (typeof fileref!="undefined")
{
var scriptparent = document.getElementsByTagName("head")[0];
if (typeof scriptparent=="undefined")
{
var scriptparent = document.createElement('head');
document.getElementsByTagName("html")[0].appendChild(scriptparent);
}
scriptparent.appendChild(fileref);
}
if (r_count<r_max)
{
setTimeout(Init, 100);
return 0;
}
else
{
console.log("Failed to load smoothscroll!");
}
r_count++;
}
if (OWNJQUERY) {
var versiontable = $0.fn.jquery.split('.');
var version = 0;
for (var i = versiontable.length-1; i >= 0; i--) {
var power = versiontable.length-i;
version += Math.pow(10,power-1)*versiontable[i];
}
console.log("Script jQuery OK! Version: " + version);
InitSmoothscroll();
}
if (OLDJQUERY) {
console.log("Restoring old jQuery...");
$ = old$;
jQuery = oldjQuery;
var versiontable = $.fn.jquery.split('.');
var version = 0;
for (var i = versiontable.length-1; i >= 0; i--) {
var power = versiontable.length-i;
version += Math.pow(10,power-1)*versiontable[i];
}
console.log("Page jQuery OK! Version: " + version);
}
console.log("Finished loading smoothscroll!");
}
console.log("Loading smoothscroll...");
Init();