HotKey Next Page

按左右键快速翻页,也可点击浮动按钮快速翻页

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           HotKey Next Page
// @namespace      hzhbest
// @author         hzhbest
// @version        1.5
// @description    按左右键快速翻页,也可点击浮动按钮快速翻页
// @include        http://*
// @include        https://*
// @license        MIT
// @run-at         document-end
// @grant          unsafeWindow
// ==/UserScript==

// original author : [email protected] (https://userscripts-mirror.org/scripts/show/87895)
// mod by hzhbest  : add hilite and float buttons

const Strs = {
    next: [
        "下一页",
        "下壹頁",
        "下页",
        "下一页 »",
        "下一页 >",
        "下一节",
        "下一章",
        "下一篇",
        "后一章",
        "后一篇",
        "后页>",
        "»",
        ">",
        "next",
        "next page",
        "Next →",
        "old",
        "older",
        "earlier",
        "下頁",
        "下一頁",
        "后一页",
        "后一頁",
        "翻下页",
        "翻下頁",
        "后页",
        "后頁",
        "下翻",
        "下一个",
        "下一张",
        "下一幅",
    ],
    last: [
        "上一页",
        "上壹頁",
        "上页",
        "« 上一页",
        "< 上一页",
        "上一节",
        "上一章",
        "上一篇",
        "前一章",
        "前一篇",
        "<前页",
        "«",
        "<",
        "previous",
        "prev",
        "previous page",
        "← Previous",
        "new",
        "newer",
        "later",
        "上頁",
        "上一頁",
        "前一页",
        "前一頁",
        "翻上页",
        "翻上頁",
        "前页",
        "前頁",
        "上翻",
        "上一个",
        "上一张",
        "上一幅",
    ]
}

const GeneralXpaths = [
    ["//a[(normalize-space(text())='", "')]"],
    ["//a[@class='", "']"],
    ["//a[@id='", "']"],
    ["//a[starts-with(@class,'", " ')]"],
    ["//a[starts-with(@id,'", " ')]"],
    ["//input[@type='button' and @value='", "']"],
];

//编辑下面的数组来自定义规则
const SpecialXpaths = [
    {
        urls: ["http://www.google.com"],    //匹配的url
        last: "//a[@id='pnprev']",    //上一页节点的xpath
        next: "//a[@id='pnnext']",    //下一页节点的xpath
    },
    {
        urls: ["bilibili.com"],
        last: '//li[@class="be-pager-prev"]',
        next: '//li[@class="be-pager-next"]',
    },
    {
        urls: ["taobao.com"],
        last: '//button[contains(@aria-label,"上一页")]',
        next: '//button[contains(@aria-label,"下一页")]',
    },
    {
        urls: ["gov.cn"],
        last: '//button[@class="btn-prev"]',
        next: '//button[@class="btn-next"]',
    },
	/*{
        urls: ["anime1.me"],
        last: '//a[@id="table-list_previous"]',
        next: '//a[@id="table-list_next"]',
    },
    {
        urls: ["e-hentai.org"],
        last: '//a[@id="dprev"]',
        next: '//a[@id="dnext"]',
    },*/
];
const LastKEY = [
    37,     // 左方向键
    65      // 字母键A
];
const NextKEY = [
    39,     // 右方向键
    68      // 字母键D
];
const css = `.__hkbtn {outline: 3px solid #bb1a6a; font-size: larger;}
            .__hkbse {position: fixed; z-index: 1000; right: 2em; bottom: 5em; background: #fff9;}
            .__hkbse>div:first-of-type {display: none;}
            .__hkbse:hover>div:first-of-type {display: inline-block;}
            .__hkfbtn {width: 4em; height: 3em; display: inline-block; border: 2px solid #8a8a8a8a;
                cursor: pointer; text-align: center; font-size: 1.5em; line-height: 3em; opacity: 0.7;}
            .__hkfbtn.disabled {opacity: 0.3;}
            .__hkfbtn:hover {opacity: 1; background: #fbcf84dd;}
            `;
addCSS(css, 'hknp_css');
var lnode,rnode,bnode,href;
setTimeout(init, 2000);

function init(){
	lnode = getNode('last');
	rnode = getNode('next');
	if (!!lnode || !!rnode) {
		if (!!bnode) bnode.parentNode.removeChild(bnode);
		bnode = creaElemIn('div', document.body);
		bnode.className = '__hkbse';
		var lbutton = creaElemIn('div', bnode);
		var rbutton = creaElemIn('div', bnode);
		lbutton.className = rbutton.className = '__hkfbtn disabled';
		lbutton.innerHTML = "<";
		rbutton.innerHTML = ">";
		bnode.addEventListener('mouseover', ()=>{
			// console.log("href?",href == document.location.href);
			if(href !== document.location.href) init();
		},false);
		if (!!lnode && lnode.offsetHeight !== 0) {
			lnode.classList.add('__hkbtn') ;
			lbutton.classList.remove('disabled');
			if (lnode.textContent.length > 0) lbutton.innerHTML = lnode.textContent.substring(0,3);
			lbutton.title = lnode.textContent + ((!!lnode.href)? '\n' + lnode.href : '');
			lbutton.addEventListener('click', ()=>{
				click(lnode);
				setTimeout(init, 1000);
			}, false);
		}
		if (!!rnode && rnode.offsetHeight !== 0) {
			rnode.classList.add('__hkbtn') ;
			rbutton.classList.remove('disabled');
			if (rnode.textContent.length > 0) rbutton.innerHTML = rnode.textContent.substring(0,3);
			rbutton.title = rnode.textContent + ((!!rnode.href)? '\n' + rnode.href : '');
			rbutton.addEventListener('click', ()=>{
				click(rnode);
				setTimeout(init, 1000);
			}, false);
		}
	}
	href = document.location.href;
}

function creaElemIn(tagname, destin) {
    let theElem = destin.appendChild(document.createElement(tagname));
    return theElem;
}

function addCSS(css, cssid) {
    let stylenode = creaElemIn('style',document.getElementsByTagName('head')[0]);
    stylenode.textContent = css;
    stylenode.type = 'text/css';
    stylenode.id = cssid || '';
}

function checkKey(e) {
    if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) return;
    if (checkTextArea(e.target)) return;
    //console.log("hknp_keydown:",e.keyCode);
    if (LastKEY.includes(e.keyCode) && !!lnode) {
        click(lnode);
		setTimeout(init, 1000);
    }
    if (NextKEY.includes(e.keyCode) && !!rnode) {
        click(rnode);
		setTimeout(init, 1000);
    }
}

function checkTextArea(node) {
    var name = node.localName.toLowerCase();
    if (name == "textarea" || name == "input" || name == "select") {
		return true;
	}
    if (name == "div" && (node.id.toLowerCase().indexOf("textarea") != -1 || node.contentEditable !== false)) {
        return true;
	}
    return false;
}

function click(node) {
    if (node.onclick) node.onclick();
	if (href !== document.location.href) return;
    if (node.click) node.click();
	if (href !== document.location.href) return;
    if (node.href) location.href = node.href;
}
function xpath(query) {
	return unsafeWindow.document.evaluate(
        query,
        document,
        null,
        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
        null
    );
}
function getNode(lnstr) {
    var node = getNodeByGeneralXpath(lnstr);
	// console.log("n1",lnstr,node);
    if (!node) node = getNodeBySpecialXpath(lnstr);
    // console.log("n2",lnstr,node);
	return node;
}
function getNodeByGeneralXpath(lnstr) { // lnstr 只支持输入 【last】 或者 【next】
    var strs;
    strs = Strs[lnstr];
    var x = GeneralXpaths;
    for (var i in x) {
        for (var j in strs) {
            var query = x[i][0] + strs[j] + x[i][1];
            var nodes = xpath(query);
            if (nodes.snapshotLength > 0) return nodes.snapshotItem(0);
        }
    }
    return null;
}
function getNodeBySpecialXpath(lnstr) {   // lnstr 只支持输入 【last】 或者 【next】
    var s = SpecialXpaths;
    for (var i in s) {
        if (checkXpathUrl(s[i].urls)) {
            return xpath(s[i][lnstr]).snapshotItem(0);
        }
    }
    return null;
}
function checkXpathUrl(urls) {
    for (var i in urls) if (location.href.indexOf(urls[i]) >= 0) return true;
    return false;
}
if (top.location != self.location) return;
unsafeWindow.document.addEventListener("keydown", checkKey, false);