Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
// ==UserScript==
// @name ldr smooth scroll
// @namespace http://relaxedcolumn.blog8.fc2.com/
// @description smoothing scroll for livedoor reader (ldr) and fastladder
// @include http://reader.livedoor.com/reader/
// @include http://reader.livedoor.com/public/*
// @include http://fastladder.com/reader/
// ==/UserScript==
//
(function() {
// shorthand
var _gm = !!this.unsafeWindow;
var _w = this.unsafeWindow || window;
var $ = _w.$;
var container = $("right_container");
// config
var config = {
type: "always",
threshold: 300,
duration: 300,
easing: "easeInOutCubic"
};
// load config
if(_gm) for(var val in config) config[val] = GM_getValue(val, config[val]);
// easing
var easingFunctions = {
linear: function(t, b, c, d) {
return c * t / d + b;
},
easeInOutCubic: function(t, b, c, d) {
if((t/=d/2) < 1) return c /2*t*t*t + b;
else return c/2*((t-=2)*t*t + 2) + b;
},
easeInOutSine: function(t, b, c, d) {
return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
},
easeInBounce: function(t, b, c, d) {
return c - easingFunctions.easeOutBounce(d-t, 0, c, d) + b;
},
easeOutBounce: function(t, b, c, d) {
if((t/=d) <(1/2.75)) {
return c*(7.5625*t*t) + b;
} else if(t <(2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
} else if(t <(2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
}
},
easeInOutBounce: function(t, b, c, d) {
if(t < d/2) return easingFunctions.easeInBounce(t*2, 0, c, d) * .5 + b;
else return easingFunctions.easeOutBounce(t*2-d, 0, c, d) * .5 + c*.5 + b;
}
};
// smooth scroll
var timer = null;
var smooth_scroll_to = function(elem, px) {
if(timer != null) return;
var startTime = Date.now();
var begin = elem._scrollTop;
var change = px - elem.scrollTop;
timer = setInterval(function() {
var time = Date.now() - startTime;
elem._scrollTop = easingFunctions[config.easing](time, begin, change, config.duration);
if(time >= config.duration) {
elem._scrollTop = px;
stop_scroll();
}
}, 5);
};
var stop_scroll = function() {
if(timer != null) {
clearInterval(timer);
timer = null;
}
};
// override scrollTop
var force_nonsmooth = false;
var current_to = 0;
var override_scrollTop = function(elem) {
elem = elem.wrappedJSObject || elem;
elem.__defineGetter__("_scrollTop", elem.__lookupGetter__("scrollTop"));
elem.__defineSetter__("_scrollTop", elem.__lookupSetter__("scrollTop"));
elem.__defineGetter__("scrollTop", function() { return elem._scrollTop; });
elem.__defineSetter__("scrollTop", function(px) {
// don't cancel if distination is same as current scroll
if(px == current_to) return;
stop_scroll();
current_to = px;
var diff = Math.abs(px - elem._scrollTop);
if(!force_nonsmooth && (
config.type == "always" ||
config.type == "auto" && diff > config.threshold
))
smooth_scroll_to(elem, px);
else
elem._scrollTop = px;
});
};
override_scrollTop(container);
// privent scroll when go to next feed
// override scrollTop of each items for fastladder_fixed_item_height.js
var register_hook = _w.register_hook;
register_hook("BEFORE_PRINTFEED", function() { force_nonsmooth = true; });
register_hook("BEFORE_SUBS_LOAD", function() { force_nonsmooth = true; });
register_hook("AFTER_PRINTFEED", function() {
force_nonsmooth = false;
Array.slice(container.getElementsByClassName("item")).map(override_scrollTop);
});
register_hook("AFTER_SUBS_LOAD", function() {
force_nonsmooth = false;
Array.slice(container.getElementsByClassName("item")).map(override_scrollTop);
});
window.addEventListener('load', function() {
// Keybind
var Keybind = _w.Keybind;
// toggle smooth type
var next_type = {
none: "always",
always: "auto",
auto: "none"
};
Keybind.add("S", function() {
config.type = next_type[config.type];
_w.message('set smooth: "' + config.type + '"');
if(_gm) window.setTimeout(function() { GM_setValue("type", config.type); }, 0);
});
// scroll to top
Keybind.add("t", function() { container.scrollTop = 0; });
// scroll to bottom
Keybind.add("b", function() {
var divs = container.getElementsByClassName("item");
var last_item = divs[divs.length - 1];
var target = last_item.offsetTop + last_item.offsetHeight
- container.offsetHeight + 40;
container.scrollTop = target;
});
}, false);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment