// ==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://fastladder.com/reader/ // ==/UserScript== // (function() { var w = unsafeWindow; w.addEventListener('load', function() { // shorthand var shorthands = "document $ Control Form Keybind register_hook message".split(" "); for(var i = 0, len = shorthands.length; i < len; ++i) { eval("var " + shorthands[i] + " = w." + shorthands[i]); } var container = $("right_container"); // config var config = { type: "always", velocity: 30, threshold: 250 }; // load config for(var val in config) { config[val] = GM_getValue(val, config[val]); } // smooth scroll var timer = null; var smooth_scroll_by = function(px) { if(timer != null) return; var step = (px < 0 ? -1 : 1) * config.velocity var times = Math.floor(px / step); var remain = px - step * times; timer = setInterval(function() { container._scrollTop += step; if(--times <= 0) { stop_scroll(); container._scrollTop += remain; } }, 10); }; var stop_scroll = function() { if(timer != null) { clearInterval(timer); timer = null; } }; var should_smooth = function(px) { return config.type == "always" || config.type == "auto" && Math.abs(px) > config.threshold; }; register_hook("before_printfeed", stop_scroll); // override scrollTop container.__defineGetter__("_scrollTop", container.__lookupGetter__("scrollTop")); container.__defineSetter__("_scrollTop", container.__lookupSetter__("scrollTop")); container.__defineGetter__("scrollTop", function() container._scrollTop); container.__defineSetter__("scrollTop", function(px) { var diff = px - container._scrollTop; if(should_smooth(diff)) smooth_scroll_by(diff); else container._scrollTop = px; }); // add config register_hook("after_init_config", function(){ // get DOM nodes var form = $("config_form"); var config_detail = $("config_detail"); var tbody = config_detail.getElementsByTagName("tbody")[0]; var insert_target = tbody.childNodes[8]; // localization var labels = {}; // fastladder if(location.href.match(/^http:\/\/fastladder/)) { labels.title = "Smoothing scroll"; labels.description = "Smooth scroll mode and settings"; labels.none = "none"; labels.always = "always"; labels.auto = "auto (smoothing only when scroll length is longer than threshold)"; labels.velocity = "velocity"; labels.velocity_description = "px (more than 1)"; labels.threshold = "threshold"; labels.threshold_description = "px (only for auto)"; } // livedoor reader else { labels.title = "スムーズスクロール"; labels.description = "スムーズのタイプと動作の設定ができます"; labels.none = "なし"; labels.always = "常に"; labels.auto = "自動(スクロール距離が閾値より長いときだけスムージング)"; labels.velocity = "速さ"; labels.velocity_description = "px (1以上)"; labels.threshold = "閾値"; labels.threshold_description = "px (自動のときのみ)"; } // create config nodes var smooth_tr = document.createElement("tr"); var smooth_th = document.createElement("th"); smooth_th.textContent = labels.title; smooth_th.style.background = "#ffa"; smooth_tr.appendChild(smooth_th); var smooth_td = document.createElement("td"); smooth_td.style.background = "#ffa"; smooth_td.innerHTML = <> {labels.description}
{labels.none}
{labels.always}
{labels.auto}
{labels.velocity} {labels.velocity_description}
{labels.threshold} {labels.threshold_description} .toString(); smooth_tr.appendChild(smooth_td); tbody.insertBefore(smooth_tr, insert_target); // fill value var fillConfig = {}; for(var val in config) { fillConfig["smooth_" + val] = config[val]; } Form.fill(form, fillConfig); // add submit event form.addEventListener("submit", function() { for(var i = 0, len = form.smooth_type.length; i < len; ++i) { var radio = form.smooth_type[i]; if(radio.checked) { config.type = radio.value; break; } } var v = parseInt(form.smooth_velocity.value); config.velocity = (v > 0) ? v : 30; config.threshold = parseInt(form.smooth_threshold.value); for(var val in config) { GM_setValue(val, config[val]); } }, false); }); // Keybind // toggle smooth type var next_type = { none: "always", always: "auto", auto: "none" }; Keybind.add("S", function() { config.type = next_type[config.type]; message('set smooth: "' + config.type + '"'); window.setTimeout(function() { GM_setValue("type", config.type); }, 0); }); // scroll to top Keybind.add("t", Control.scroll_to_zero); // scroll to bottom Keybind.add("b", function() { var divs = container.getElementsByTagName("h2"); var last_item = divs[divs.length - 1].parentNode.parentNode; var target = last_item.offsetTop + last_item.offsetHeight - container.offsetHeight + 40; container.scrollTop = target; }); }, false); })();