🏠 Home 

Keyboard and Mouse Wheel Page Turner

Quickly navigate between pages by scrolling the mouse wheel or pressing keys.


Install this script?
Author's suggested script

You may also like Hide end-screens of YouTube..


Install this script
// ==UserScript==
// @name         按鍵與滑鼠滾輪翻頁器
// @name:zh-TW   按鍵與滑鼠滾輪翻頁器
// @name:ja      キーとマウスホイールでのページめくり機
// @name:en      Keyboard and Mouse Wheel Page Turner
// @name:ko      키보드 및 마우스 휠 페이지 전환기
// @name:es      Navegador de Páginas con Teclado y Rueda del Ratón
// @namespace    https://github.com/Max46656
// @version      1.2.6
// @description  使用滑鼠滾輪或按鍵快速切換上下頁。
// @description:zh-TW 使用滑鼠滾輪或按鍵快速切換上下頁。
// @description:ja マウスホイールをスクロールするか、キーを押すことで、簡単にページを上下に切り替えることができます。
// @description:en Quickly navigate between pages by scrolling the mouse wheel or pressing keys.
// @description:ko 마우스 휠을 스크롤하거나 키를 눌러 페이지를 쉽게 전환할 수 있습니다.
// @description:es Navega rápidamente entre páginas desplazando la rueda del ratón o presionando teclas.
// @author       Max
// @match        https://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=pixiv.net
// @grant    GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license MPL2.0
// ==/UserScript==
class PageButtonManager {
constructor() {
this.pageButtonsMap = {};
this.loadPageButtons();
}
loadPageButtons() {
this.pageButtonsMap = GM_getValue('pageButtonsMap', {});
}
async savePageButtons() {
await GM_setValue('pageButtonsMap', this.pageButtonsMap);
}
getButtonsForDomain(domain) {
return this.pageButtonsMap[domain] || {
nextButton: '.next',
prevButton: '.prev'
};
}
setButtonsForDomain(domain, buttons) {
this.pageButtonsMap[domain] = buttons;
this.savePageButtons();
}
getAllDomains() {
return Object.keys(this.pageButtonsMap);
}
}
class NavigationPaginationWithInput {
constructor(buttonManager) {
this.buttonManager = buttonManager;
this.pageButtons = this.buttonManager.getButtonsForDomain(self.location.hostname);
console.log(this.pageButtons);
this.init();
}
async init() {
await this.loadSettings();
this.setEventListeners();
}
async loadSettings() {
this.togglePaginationMode = await GM_getValue('togglePaginationMode', 'key');
this.modifierKey = await GM_getValue('modifierKey', 'Control');
this.nextPageKey = await GM_getValue('nextPageKey', 'W');
this.prevPageKey = await GM_getValue('prevPageKey', 'Q');
console.group("Settings");
console.log("togglePaginationMode",this.togglePaginationMode);
console.log("modifierKey",this.modifierKey);
console.log("nextPageKey",this.nextPageKey);
console.log("prevPageKey",this.prevPageKey);
console.groupEnd();
this.saveSettings();
}
async saveSettings() {
await GM_setValue('togglePaginationMode', this.togglePaginationMode);
await GM_setValue('modifierKey', this.modifierKey);
await GM_setValue('nextPageKey', this.nextPageKey);
await GM_setValue('prevPageKey', this.prevPageKey);
}
async toNextPage() {
const pageButtons = document.querySelectorAll(this.pageButtons.nextButton);
let nextPageButton = pageButtons[pageButtons.length-1];
nextPageButton.click();
}
async toPrevPage() {
const prevPageButton = document.querySelectorAll(this.pageButtons.prevButton)[0];
console.log(this.pageButtons.prevButton,prevPageButton);
prevPageButton.click();
}
async setEventListeners() {
this.scrollHandler = () => this.handleScroll();
this.keydownHandler = (event) => this.handleKeydown(event);
if (this.togglePaginationMode !== "key") {
self.addEventListener("scroll", this.scrollHandler);
} else {
self.addEventListener("keydown", this.keydownHandler);
}
}
handleScroll(scrollThreshold=3) {
const isBottom = document.documentElement.scrollHeight - self.innerHeight - self.pageYOffset <= scrollThreshold;
if (isBottom) {
this.toNextPage();
console.log("滾輪下一頁");
}
if (self.pageYOffset <= 0) {
this.toPrevPage();
console.log("滾輪上一頁");
}
}
handleKeydown(event) {
if (event.getModifierState(this.modifierKey)) {
if (event.key.toUpperCase() === this.nextPageKey.toUpperCase()) {
event.preventDefault();
this.toNextPage();
console.log("快捷鍵下一頁");
} else if (event.key.toUpperCase() === this.prevPageKey.toUpperCase()) {
event.preventDefault();
this.toPrevPage();
console.log("快捷鍵上一頁");
}
}
}
}
class MenuManager {
constructor(buttonManager,navigation) {
this.buttonManager = buttonManager;
this.navigation = navigation;
this.initMenu();
}
getMenuLabels() {
const userLang = navigator.language || navigator.userLanguage;
const labels = {
'zh-TW': {
viewAndModify: '修改上下頁的按鈕元素選取器',
showAllDomains: '顯示所有網域',
togglePageMode: '切換翻頁模式',
customizeModifierKey: '自訂啟動快捷鍵',
customizeNextPageKey: '自訂下一頁快捷鍵',
customizePrevPageKey: '自訂上一頁快捷鍵',
enterDomain: '輸入網域:',
currentButtons: '當前按鈕:',
enterNextButton: '輸入下一頁按鈕選擇器:',
enterPrevButton: '輸入上一頁按鈕選擇器:',
savedDomains: '已儲存的網域:',
enterDomainToView: '輸入要檢視的網域:',
enterModifierKey: '輸入啟動快捷鍵 (Control, Alt, Shift, CapsLock):',
enterNextPageKey: '輸入下一頁快捷鍵:',
enterPrevPageKey: '輸入上一頁快捷鍵:',
invalidInput: '無效的輸入,請重試。'
},
'en': {
viewAndModify: 'Modify Page Up/Down Button Selectors',
showAllDomains: 'Show All Domains',
togglePageMode: 'Toggle Page Mode',
customizeModifierKey: 'Customize Modifier Key',
customizeNextPageKey: 'Customize Next Page Key',
customizePrevPageKey: 'Customize Previous Page Key',
enterDomain: 'Enter the domain:',
currentButtons: 'Current buttons:',
enterNextButton: 'Enter the next page button selector:',
enterPrevButton: 'Enter the previous page button selector:',
savedDomains: 'Saved domains:',
enterDomainToView: 'Enter the domain to view:',
enterModifierKey: 'Enter modifier key (Control, Alt, Shift, CapsLock):',
enterNextPageKey: 'Enter next page key:',
enterPrevPageKey: 'Enter previous page key:',
invalidInput: 'Invalid input, please try again.'
},
'ja': {
viewAndModify: 'ページの上下ボタン要素セレクターの変更',
showAllDomains: 'すべてのドメインを表示',
togglePageMode: 'ページモードを切り替える',
customizeModifierKey: '修飾キーをカスタマイズ',
customizeNextPageKey: '次のページキーをカスタマイズ',
customizePrevPageKey: '前のページキーをカスタマイズ',
enterDomain: 'ドメインを入力してください:',
currentButtons: '現在のボタン:',
enterNextButton: '次のページボタンのセレクタを入力してください:',
enterPrevButton: '前のページボタンのセレクタを入力してください:',
savedDomains: '保存されたドメイン:',
enterDomainToView: '表示するドメインを入力してください:',
enterModifierKey: '修飾キーを入力してください(Control、Alt、Shift、CapsLock):',
enterNextPageKey: '次のページキーを入力してください:',
enterPrevPageKey: '前のページキーを入力してください:',
invalidInput: '無効な入力です。もう一度お試しください。'
},
'ko': {
viewAndModify: '페이지 위/아래 버튼 선택기 수정',
showAllDomains: '모든 도메인 보기',
togglePageMode: '페이지 모드 전환',
customizeModifierKey: '수정 키 사용자화',
customizeNextPageKey: '다음 페이지 키 사용자화',
customizePrevPageKey: '이전 페이지 키 사용자화',
enterDomain: '도메인을 입력하세요:',
currentButtons: '현재 버튼:',
enterNextButton: '다음 페이지 버튼 선택기 입력:',
enterPrevButton: '이전 페이지 버튼 선택기 입력:',
savedDomains: '저장된 도메인:',
enterDomainToView: '보기할 도메인을 입력하세요:',
enterModifierKey: '수정 키를 입력하세요 (Control, Alt, Shift, CapsLock):',
enterNextPageKey: '다음 페이지 키 입력:',
enterPrevPageKey: '이전 페이지 키 입력:',
invalidInput: '잘못된 입력입니다. 다시 시도하세요.'
},
'es': {
viewAndModify: 'Modificar Selectores de Botones de Página Arriba/Abajo',
showAllDomains: 'Mostrar Todos los Dominios',
togglePageMode: 'Alternar Modo de Página',
customizeModifierKey: 'Personalizar Tecla Modificadora',
customizeNextPageKey: 'Personalizar Tecla de Siguiente Página',
customizePrevPageKey: 'Personalizar Tecla de Página Anterior',
enterDomain: 'Ingrese el dominio:',
currentButtons: 'Botones actuales:',
enterNextButton: 'Ingrese el selector del botón de siguiente página:',
enterPrevButton: 'Ingrese el selector del botón de página anterior:',
savedDomains: 'Dominios guardados:',
enterDomainToView: 'Ingrese el dominio a visualizar:',
enterModifierKey: 'Ingrese tecla modificadora (Control, Alt, Shift, CapsLock):',
enterNextPageKey: 'Ingrese tecla de siguiente página:',
enterPrevPageKey: 'Ingrese tecla de página anterior:',
invalidInput: 'Entrada inválida, por favor intente de nuevo.'
}
};
return labels[userLang] || labels['en'];
}
initMenu() {
const labels = this.getMenuLabels();
GM_registerMenuCommand(labels.viewAndModify, this.viewAndModifyButtons.bind(this));
GM_registerMenuCommand(labels.showAllDomains, this.showAllDomains.bind(this));
GM_registerMenuCommand(labels.togglePageMode, this.inputModeSwitch.bind(this));
GM_registerMenuCommand(labels.customizeModifierKey, this.customizeModifierKey.bind(this));
GM_registerMenuCommand(labels.customizeNextPageKey, this.customizeNextPageKey.bind(this));
GM_registerMenuCommand(labels.customizePrevPageKey, this.customizePrevPageKey.bind(this));
}
async viewAndModifyButtons() {
const labels = this.getMenuLabels();
const domain = prompt(labels.enterDomain, window.location.hostname);
if (domain) {
const currentButtons = this.buttonManager.getButtonsForDomain(domain);
alert(`${labels.currentButtons}\nNext: ${currentButtons.nextButton}\nPrev: ${currentButtons.prevButton}`);
const newNextButton = prompt(labels.enterNextButton, currentButtons.nextButton);
const newPrevButton = prompt(labels.enterPrevButton, currentButtons.prevButton);
if (newNextButton && newPrevButton) {
this.buttonManager.setButtonsForDomain(domain, { nextButton: newNextButton, prevButton: newPrevButton });
alert(`Updated buttons for ${domain}`);
}
}
}
async showAllDomains() {
const labels = this.getMenuLabels();
const allDomains = this.buttonManager.getAllDomains();
const domain = prompt(`${labels.savedDomains}\n${allDomains.join('\n')}\n\n${labels.enterDomainToView}`);
if (domain) {
const buttons = this.buttonManager.getButtonsForDomain(domain);
alert(`Buttons for domain ${domain}:\nNext: ${buttons.nextButton}\nPrev: ${buttons.prevButton}`);
}
}
async inputModeSwitch() {
if (this.togglePaginationMode === 'scroll') {
this.togglePaginationMode = 'key';
self.removeEventListener("scroll", this.scrollHandler);
self.addEventListener("keydown", this.keydownHandler);
console.log("切換為按鍵翻頁模式");
} else {
this.togglePaginationMode = 'scroll';
self.addEventListener("scroll", this.scrollHandler);
self.removeEventListener("keydown", this.keydownHandler);
console.log("切換為滾輪翻頁模式");
}
this.saveSettings();
}
async customizeModifierKey() {
const labels = this.getMenuLabels();
const newModifierKey = prompt(labels.enterModifierKey, this.navigation.modifierKey);
if (['Control', 'Alt', 'Shift', 'CapsLock'].includes(newModifierKey)) {
this.navigation.modifierKey = newModifierKey;
await this.navigation.saveSettings();
} else {
alert(labels.invalidInput);
}
}
async customizeNextPageKey() {
const labels = this.getMenuLabels();
const newNextPageKey = prompt(labels.enterNextPageKey, this.navigation.nextPageKey);
if (newNextPageKey && newNextPageKey.length === 1) {
this.navigation.nextPageKey = newNextPageKey;
await this.navigation.saveSettings();
} else {
alert(labels.invalidInput);
}
}
async customizePrevPageKey() {
const labels = this.getMenuLabels();
const newPrevPageKey = prompt(labels.enterPrevPageKey, this.navigation.prevPageKey);
if (newPrevPageKey && newPrevPageKey.length === 1) {
this.navigation.prevPageKey = newPrevPageKey;
await this.navigation.saveSettings();
} else {
alert(labels.invalidInput);
}
}
}
const buttonManager = new PageButtonManager();
const Navigation = new NavigationPaginationWithInput(buttonManager);
new MenuManager(buttonManager,Navigation);