Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lunamoth/5f341c355a3f4b56e57f806d087a125c to your computer and use it in GitHub Desktop.
Save lunamoth/5f341c355a3f4b56e57f806d087a125c to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name 좌고우면 키보드 페이지 이동 유저스크립트
// @namespace http://tampermonkey.net/
// @version 5.0
// @description 게시판 등 URL에 페이지 있을 시 좌우 방향키로 페이지 이동하게 해주는 유저스크립트
// @author Claude & ChatGPT
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const CONFIG = {
patterns: [
/page=(\d+)/i,
/\?p=(\d+)/i,
/&po=(\d+)/i,
/\/page\/(\d+)/i,
/\/(\d+)\/$/,
/pagingIndex=(\d+)/i
],
prevKey: 'ArrowLeft',
nextKey: 'ArrowRight',
cacheSize: 50,
cacheTimeout: 300000 // 5 minutes
};
class Cache {
constructor(capacity, timeout) {
this.capacity = capacity;
this.timeout = timeout;
this.cache = new Map();
}
get(key) {
const item = this.cache.get(key);
if (!item || Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}
return item.value;
}
set(key, value) {
if (this.cache.size >= this.capacity) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
this.cache.set(key, { value, expiry: Date.now() + this.timeout });
}
}
const cache = new Cache(CONFIG.cacheSize, CONFIG.cacheTimeout);
function findMatchingPattern(url) {
const cached = cache.get(url);
if (cached) return cached;
for (let pattern of CONFIG.patterns) {
const match = url.match(pattern);
if (match) {
const result = { pattern, currentPage: parseInt(match[1], 10) };
cache.set(url, result);
return result;
}
}
return null;
}
function updatePageInUrl(url, { pattern, currentPage }, direction) {
const newPage = Math.max(currentPage + direction, 1);
return url.replace(pattern, (match) =>
match.replace(currentPage.toString(), newPage.toString())
);
}
function findNavigationLinks() {
return {
nextLink: document.querySelector('a[rel="next"]'),
prevLink: document.querySelector('a[rel="prev"]')
};
}
function navigatePage(direction) {
const currentUrl = window.location.href;
const patternInfo = findMatchingPattern(currentUrl);
let newUrl;
if (patternInfo) {
newUrl = updatePageInUrl(currentUrl, patternInfo, direction);
} else {
const { nextLink, prevLink } = findNavigationLinks();
newUrl = direction > 0 ? nextLink?.href : prevLink?.href;
}
if (newUrl && newUrl !== currentUrl) {
window.location.href = newUrl;
}
}
function handleKeydown(event) {
const activeElement = document.activeElement;
const isInputFocused = ['INPUT', 'TEXTAREA'].includes(activeElement.tagName) ||
activeElement.isContentEditable;
if (!isInputFocused) {
if (event.key === CONFIG.prevKey) {
navigatePage(-1);
} else if (event.key === CONFIG.nextKey) {
navigatePage(1);
}
}
}
document.addEventListener('keydown', handleKeydown);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment