// ==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() { // 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; var container = $("right_container"); 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; } }; // override original functions var $ = w.$; var Control = w.Control; var Config = w.Config; var should_smooth = function(px) { return config.type == "always" || (config.type == "auto" && Math.abs(px) > config.threshold); }; Control.scroll_page = function(num) { var h = $("right_container").offsetHeight - 40; var c = (Config.scroll_type == "page") ? h: (Config.scroll_type == "half") ? h / 2 : (Config.scroll_px || 100); if(should_smooth(c)) { smooth_scroll_by(c * num); } else { $("right_container").scrollTop += c * num; } }; Control.scroll_to_zero = function() { var container = $("right_container"); var current = container.scrollTop; if(should_smooth(current)) { smooth_scroll_by(- current); } else { container.scrollTop = 0; } }; Control.scroll_to_px = function(top) { var container = $("right_container"); // for opera9 beta var top_offset = $("right_body").offsetTop; var current = $("right_container").scrollTop; var target = top - top_offset; if(should_smooth(target - current)) { smooth_scroll_by(target - current); } else { container.scrollTop = target; } }; var register_hook = w.register_hook; register_hook("before_printfeed", stop_scroll); // add config register_hook("after_init_config", function(){ var document = w.document; // 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]; } w.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 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]; GM_setValue("type", config.type); w.message('set smooth: "' + config.type + '"'); }); // scroll to top Keybind.add("t", Control.scroll_to_zero); // scroll to bottom Keybind.add("b", function() { var container = $("right_container"); var divs = container.getElementsByTagName("h2"); var last_item = divs[divs.length - 1]; var target = last_item.offsetTop + last_item.parentNode.parentNode.offsetHeight - container.offsetHeight + 40; Control.scroll_to_px(target); }); }, false); })();