返回首頁 

Scroll like Opera

Based on Linkify Plus. Turn plain text URLs into links.

  1. // ==UserScript==// @name Scroll like Opera// @version 2.1.1// @description Based on Linkify Plus. Turn plain text URLs into links.// @license MIT// @author eight04 <eight04@gmail.com>// @homepageURL https://github.com/eight04/scroll-like-opera// @supportURL https://github.com/eight04/scroll-like-opera/issues// @namespace eight04.blogspot.com// @grant GM.getValue// @grant GM.setValue// @grant GM.deleteValue// @grant GM_registerMenuCommand// @grant GM_getValue// @grant GM_setValue// @grant GM_deleteValue// @grant GM_addValueChangeListener// @compatible firefox Tampermonkey latest// @compatible chrome Tampermonkey latest// @require https://greasyfork.org/scripts/7212-gm-config-eight-s-version/code/GM_config%20(eight's%20version).js?version=29833// @require https://greasyfork.org/scripts/7108-bezier-easing/code/bezier-easing.js?version=29098// @include *// ==/UserScript==/* eslint-env browser, greasemonkey *//* global GM_config BezierEasing */var config;GM_config.init("Scroll like Opera",{useWhenOnScrollbar: {label: "Scroll horizontally if cursor hover on horizontal scrollbar.",type: "checkbox",default: true},useWhenOneScrollbar: {label: "Scroll horizontally if there is only horizontal scrollbar presented.",type: "checkbox",default: true},useAlways: {label: "Always use script's scrolling handler. Enable this if you want to use the script's smooth scrolling on chrome.",type: "checkbox",default: false},scrollDelay: {label: "Smooth scrolling delay.",type: "text",default: 400},scrollOffset: {label: "Scrolling offset.",type: "text",default: 120},continueScrollingTimeout: {label: "Scrolled target changing delay.",type: "number",default: 400}});config = GM_config.get();GM_registerMenuCommand("Scroll like Opera - Configure", function(){GM_config.open();});GM_config.onclose = function(){config = GM_config.get();};/**Cache current scrolling target*/var cache = {timeout: null,target: null,cache: function(element) {cache.target = element;cache.delay();},reset: function() {clearTimeout(cache.timeout);cache.timeout = null;cache.target = null;},delay: function() {clearTimeout(cache.timeout);cache.timeout = setTimeout(cache.reset, config.continueScrollingTimeout);}};/**Register event*/window.addEventListener("wheel", function(e){var q;if (cache.target) {q = getScrollInfo(cache.target, e, true);// Scrolled to edgeif (!q) {e.preventDefault();return;}cache.delay();} else {q = getScrollInfo(e.target, e);// Can't find scrollable elementif (!q) {return;}cache.cache(q.element);}if (q.use || config.useAlways) {e.preventDefault();scrollElement(q.element, q.offsetX, q.offsetY);}}, {passive: false});window.addEventListener("mousemove", function(){cache.reset();});/**Main logic*/function getInfo(element, e) {var rect, css;if (element == document.documentElement) {return {element: element,onScrollbarX: e.clientY >= element.clientHeight && e.clientY <= window.innerHeight,scrollableX: element.scrollWidth > element.clientWidth,scrollableY: element.scrollHeight > element.clientHeight};} else if (element == document.body) {return {element: element,onScrollbarX: false,scrollableX: false,scrollableY: false};} else {rect = element.getBoundingClientRect();css = getCss(element);return {element: element,onScrollbarX: element.clientHeight && e.clientY >= rect.top + css.borderTop + element.clientHeight && e.clientY <= rect.bottom - css.borderBottom,scrollableX: element.clientWidth && element.scrollWidth > element.clientWidth && css.overflowX != "visible" && css.overflowX != "hidden",scrollableY: element.clientHeight && element.scrollHeight > element.clientHeight && css.overflowY != "visible" && css.overflowY != "hidden"};}}function getScrollInfo(element, e, noParent) {var q;// Get scrollable parentwhile (element) {q = getInfo(element, e);if (e.deltaY && (q.onScrollbarX || useHorizontalScroll(q)) && scrollable(element, e.deltaY, 0)) {// Horizontal scrollq.offsetX = getOffset(e.deltaY);q.offsetY = 0;q.use = true;return q;}if ((e.deltaX && q.scrollableX || e.deltaY && q.scrollableY) && scrollable(element, e.deltaX, e.deltaY)) {q.offsetX = getOffset(e.deltaX);q.offsetY = getOffset(e.deltaY);return q;}if (noParent) {return null;}element = element.parentNode;if (element == document) {return null;}}return null;}/**Scroll function. Should I put them into seperate library?Thanks to https://github.com/galambalazs/smoothscroll*/var animate = null;var que = [];function scrollElement(element, x, y) {var elapsed = config.scrollDelay;que.push({offsetX: x,offsetY: y,lastX: 0,lastY: 0,element: element,timeStart: null});if (animate != null) {return;}function animation(timestamp){var i, j, len, q, time, offsetX, offsetY, process, swap;swap = [];for (i = 0, j = 0, len = que.length; i < len; i++) {q = que[i];if (q.timeStart == null) {q.timeStart = timestamp;}if (timestamp - q.timeStart >= elapsed || !scrollable(q.element, q.offsetX, q.offsetY)) {scrollBy(q.element, q.offsetX - q.lastX, q.offsetY - q.lastY);} else {time = (timestamp - q.timeStart) / elapsed;process = ease(time);offsetX = Math.floor(q.offsetX * process);offsetY = Math.floor(q.offsetY * process);scrollBy(q.element, offsetX - q.lastX, offsetY - q.lastY);q.lastX = offsetX;q.lastY = offsetY;swap[j++] = q;}}que = swap;if (!que.length) {animate = null;return;}animate = requestAnimationFrame(animation);}animate = requestAnimationFrame(animation);function scrollBy(element, x, y) {if (element != document.documentElement) {element.scrollLeft += x;element.scrollTop += y;} else {window.scrollBy(x, y);}}}/**Helpers*/function useHorizontalScroll(q) {return config.useWhenOneScrollbar && q.scrollableX && !q.scrollableY;}function getOffset(delta) {var direction = 0;if (delta > 0) {direction = 1;} else if (delta < 0) {direction = -1;}return direction * config.scrollOffset;}function ease(t){return BezierEasing.css.ease(t);}function getCss(element){var css = getComputedStyle(element);return {borderTop: parseInt(css.getPropertyValue("border-top-width"), 10),borderRight: parseInt(css.getPropertyValue("border-right-width"), 10),borderBottom: parseInt(css.getPropertyValue("border-bottom-width"), 10),borderLeft: parseInt(css.getPropertyValue("border-left-width"), 10),overflowX: css.getPropertyValue("overflow-x"),overflowY: css.getPropertyValue("overflow-y")};}function scrollable(element, offsetX, offsetY) {var top, left;if (element == document.documentElement) {top = window.scrollY;left = window.scrollX;} else {top = element.scrollTop;left = element.scrollLeft;}if (top == 0 && offsetY < 0) {return false;}if (left == 0 && offsetX < 0) {return false;}if (top + element.clientHeight >= element.scrollHeight && offsetY > 0) {return false;}if (left + element.clientWidth >= element.scrollWidth && offsetX > 0) {return false;}return true;}