// ==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-idle
// @grant GM_info
// @grant unsafeWindow
// @version 0.0.1.20160504074852
// ==/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 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 = $('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($) {
$.fn.hasScrollBar = function() {
return this.get(0).scrollHeight > this.height();
}
})(jQuery);
(function($) {
$.fn.hasScrollBar0 = function() {
var divnode = this.get(0);
if(divnode.scrollHeight > divnode.clientHeight)
return true;
}
})(jQuery);
(function($) {
$.fn.hasScrollBar1 = function() {
return this.get(0).scrollHeight > this.height();
}
})(jQuery);
(function($) {
$.fn.hasScrollBar2 = function() {
return this.get(0) ? this.get(0).scrollHeight > this.innerHeight() : false;
}
})(jQuery);
(function($) {
$.fn.hasScrollBar3 = function() {
return this.get(0) ? (this.get(0).scrollHeight > this.innerHeight() && this.get(0).scrollHeight > this.height()) : false;
}
})(jQuery);
function hasVerticalScroll(node){
if(node == undefined){
if(window.innerHeight){
return document.body.offsetHeight> innerHeight;
}
else {
return document.documentElement.scrollHeight >
document.documentElement.offsetHeight ||
document.body.scrollHeight>document.body.offsetHeight;
}
}
else {
return node.scrollHeight> node.offsetHeight;
}
}
*/
function hasscrollbars(scrollfocus)
{
var hasvisiblescrollbars = hasScrollBarVisible(scrollfocus);
var parentelement = $(scrollfocus).parent();
if ( $(parentelement))
{
//if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea") || $(parentelement).is("article") || $(parentelement).is("article"))
{
return true;
}
else
{
/*if ( $(parentelement).height() < $(scrollfocus).height())
{
//maxposition = $(scrollfocus).height() - $(parentelement).height();
}
else
{
if ($(scrollfocus).height()==0)
{
//scrollfocus = $('body');
//maxposition = $(scrollfocus).height();
}
//scrollfocus = $('body');
//return MouseScroll (event);
//return true;
}*/
if ($(parentelement).hasClass( "yt-scrollbar" ) || $(scrollfocus).hasClass( "yt-scrollbar" ))
{
return true;
}
return hasvisiblescrollbars;
}
}
else
{
//scrollfocus = $('body');
//maxposition = $(scrollfocus).height();
return hasvisiblescrollbars;
}
return false;
}
function UpdatePosition(element)
{
gameLoop();
var positiondelta = $(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 - $(element).scrollTop();
//console.log("smoothdelta:" + smoothdelta);
if (Math.abs( (positiondelta-smoothdelta)) <= 1 )
{
$(element).stop();
$(element).animate({
scrollTop: '+=' + Math.round(positiondelta)
}, animationduration, "linear", function() {
$(element).attr( "positiondelta",0 );
$(element)[0].setAttribute( "positiondelta",0 );
if (DEBUG)
{
$(element).css( "border", "1px solid red" );
}
});
}
else
{
$(element).stop();
$(element).animate({
scrollTop: '+=' + Math.round(smoothdelta)
}, animationduration, "linear", function() {
$(element).attr( "positiondelta",positiondelta-smoothdelta );
$(element)[0].setAttribute("positiondelta",positiondelta-smoothdelta );
UpdatePosition(element);
if (DEBUG)
{
$(element).css( "border", "1px solid red" );
}
});
}
}
function MouseScroll (x,y,e) {
scrollfocus = UpdateFocus(x,y);
var positiondelta = 0;
var lastscrolltop = 0;
var parentelement = $(scrollfocus).parent();
if ( $(parentelement))
{
if ($(parentelement).is("textarea") || $(scrollfocus).is("textarea"))
{
//return true;
}
else
{
if ( $(parentelement).height() < $(scrollfocus).height())
{
//maxposition = $(scrollfocus).height() - $(parentelement).height();
}
else
{
if ($(scrollfocus).height()==0)
{
//scrollfocus = $('body');
//maxposition = $(scrollfocus).height();
}
//scrollfocus = $('body');
//return MouseScroll (event);
//return true;
}
}
}
else
{
scrollfocus = $('body');
//maxposition = $(scrollfocus).height();
}
//var maxposition = scrollfocus.scrollHeight - $(scrollfocus).outerHeight();
//console.log(maxposition);
//console.log($(scrollfocus).scrollTop());
/*var rolled = 0;
if ('wheelDelta' in event) {
rolled = event.wheelDelta;
}
else { // Firefox
// The measurement units of the detail and wheelDelta properties are different.
rolled = event.detail*(-120);
}
rolled = rolled*(-1);*/
var rolled = y;
//console.log("rolled: " + rolled);
//if ($(scrollfocus).data("positiondelta" )==undefined)
//$embellishment.data("embellishmentid",1)
if ($(scrollfocus)[0].getAttribute("positiondelta")==undefined)
{
positiondelta = 0;
//console.log("positiondelta: undefined");
}
else
{
positiondelta = $(scrollfocus)[0].getAttribute("positiondelta");
//console.log("positiondelta: " + positiondelta);
}
positiondelta = positiondelta*1;
var lastscrolltop = $(scrollfocus).scrollTop();
$(scrollfocus).scrollTop(lastscrolltop+rolled);
if ($(scrollfocus).scrollTop()==lastscrolltop)
{
if (!$(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();
}
$(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;
//console.log("positiondeltadelta: " + positiondeltadelta);
//Math.abs(positiondelta*relativeratio)
//console.log("target:" + targetposition);
//var targetposition = $(scrollfocus).scrollTop() + positiondelta;
/*
if (targetposition <= 0)
{
targetposition = -startposition;
//console.log("start")
}
else if (targetposition+startposition >= maxposition)
{
targetposition = (maxposition-startposition);
//console.log("end")
}
else
{
}
$(scrollfocus).data( "targetposition", targetposition );
*/
//console.log("document:" + $(document).height());
//console.log("window:" + $(window).height());
//position = startposition + targetposition;
//$(scrollfocus).data( "position", position );
//
//$(scrollfocus).data( "positiondelta", positiondelta );
$(scrollfocus)[0].setAttribute("positiondelta",positiondelta );
UpdatePosition($(scrollfocus));
//element.innerHTML = "";
//console.log("pos:" + position);
//event.preventDefault();
return true;
}
/*
function Init (smoothscrollelem) {
// for mouse scrolling in Firefox
if (smoothscrollelem.addEventListener) { // all browsers except IE before version 9
// Internet Explorer, Opera, Google Chrome and Safari
smoothscrollelem.addEventListener ("mousewheel", MouseScroll, false);
// Firefox
smoothscrollelem.addEventListener ("DOMMouseScroll", MouseScroll, false);
}
else {
if (smoothscrollelem.attachEvent) { // IE before version 9
smoothscrollelem.attachEvent ("onmousewheel", MouseScroll);
}
}
}
*/
/*var elements = $('*');
console.log("Loaded " + elements.length + " scrollable elements.");
$(elements).each(function() {
$( this ).bind({
mouseenter: function(e) {
UpdateFocus(e.originalEvent);
},
mouseleave: function(e) {
UpdateFocus(e.originalEvent);
}
});
});*/
function canscroll(element, dir)
{
var scrollable = $(element);
var lastscrolltop = $(scrollable).scrollTop();
$(scrollable).scrollTop(lastscrolltop+dir);
if ($(scrollable).scrollTop()==lastscrolltop)
{
$(scrollable).scrollTop(lastscrolltop);
return false;
}
else
{
$(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" );
$(nodelist).stop();
scrollfocus = $('body');
for (var i = nodelist.length-1; i >= 0; i--) {
//var parent = nodelist[i-1];
var newfocus = nodelist[i];
if (DEBUG)
{
$(newfocus).css( "border", "1px solid blue" );
//var debugtimer = setTimeout(function(){ $(newfocus).css( "border", "0px solid white" ); }, 1000);
}
//if ($(newfocus).hasScrollBar3() && hasScrollBarVisible(newfocus) && canscroll(newfocus, dir) && hasscrollbars(newfocus))
if (canscroll(newfocus, dir) && hasscrollbars(newfocus))
{
scrollfocus = $(newfocus);
return newfocus;
}
}
//scrollfocus = $('body');
/*if (DEBUG)
{
$(scrollfocus).css( "border", "3px solid green" );
setTimeout(function(){
//console.log(nodelist);
for (var i = nodelist.length-1; i >= 0; i--) {
//var parent = nodelist[i-1];
var newfocus = nodelist[i];
$(newfocus).css( "border", "0px solid white" );
}
}, 1000);
}*/
return scrollfocus;
}
//$(document).off("mousewheel");
/*
$(document).on('mousewheel DOMMouseScroll', function(e){
//var dat = $(e.delegateTarget).data(); //in case you have set some, read it here.
//var datx = dat.x || 0; // just to show how to get specific out of jq-data object
var x = 0;
var y = 0;
var eo = e.originalEvent;
//var xy = eo.wheelDelta || -eo.detail; //shortest possible code
//var x = eo.wheelDeltaX || (eo.axis==1?xy:0);
//var y = eo.wheelDeltaY || (eo.axis==2?xy:0); // () necessary!
x = x*(-1);
y = y*(-1);
console.log(x,y);
//e.preventDefault();
//MouseScroll(x,y);
});
*/
$('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)
{
$(scrollfocus)[0].setAttribute( "positiondelta",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 loaded!");
}
var JQUERY = false;
//max retries
var r_max = 3;
var r_count = 0;
function Init() {
//if (typeof jQuery == 'function') {
if (typeof jQuery == 'undefined' || typeof $ == 'undefined' )
{
JQUERY = false;
}
if (JQUERY) {
//console.log("Using existing jQuery...");
//this.$ = this.jQuery = jQuery.noConflict(true);
//var $ = jQuery.noConflict();
console.log("jQuery OK!");
InitSmoothscroll();
}
else
{
console.log("Loading 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")
{
document.getElementsByTagName("head")[0].appendChild(fileref);
}
JQUERY = true;
if (r_count<r_max)
{
setTimeout(Init, 1000);
}
else
{
console.log("Failed to load smoothscroll!");
}
r_count++;
}
}
console.log("Loading smoothscroll...");
Init();