// ==UserScript==
// @name Shopping website (amazon, jd, ruten, shopee, taobao, tmall) - keyboard navigation
// @name:zh-TW 購物網 (亞馬遜, 露天, 蝦皮, 淘寶, 天貓, 京東) - 鍵盤導覽
// @name:zh-CN 购物网 (亞馬遜, 露天, 虾皮, 淘宝, 天猫, 京东) - 键盘导览
// @description [a / ←] prev page, [d / →] next page. [s / ↓] parent . Used for the product-list, image-gallery, rate-page...
// @description:zh-TW [a / ←]前一頁,[d / →]下一頁。包含產品列表、照片庫、評價頁...
// @description:zh-CN [a / ←]前一页,[d / →]下一页。包含产品列表、照片库、评价页...
// @author Evan Tseng
// @version 0.5.4
// @namespace https://gf.qytechs.cn/zh-TW/users/393133-evan-tseng
// @include *.amazon.*
// @include *.ruten.*
// @include *shopee.*
// @include *.taobao.*
// @include *.tmall.*
// @include *.jd.*
// @grant none
// ==/UserScript==
(async function() {
'use strict';
var host = window.location.hostname.toLowerCase().replace(/(\.(biz|com|edu|gov|org|net|cn|jp|tw))+$/, "").replace(/.+\.([^\.]+)$/,"$1");
// 按鍵對應元素
const elmPatt = {
'amazon': {
enter: [],
esc: ['.a-popover-modal .a-button-top-right'],
w: [],
s: ['#leftNav .s-ref-indent-neg-micro:nth-last-of-type(2) a', '#departments .a-spacing-micro:nth-last-of-type(2) a', '.a-breadcrumb li:last-of-type a'],
a: ['ul.a-pagination li:first-of-type>a', '#ivThumbs .ivThumb.selected', '#pagnPrevLink'],
d: ['ul.a-pagination li:last-of-type>a', '#ivThumbs .ivThumb.selected', '#pagnNextLink'],
arrowUp: [],
arrowDown: ['#leftNav .s-ref-indent-neg-micro:nth-last-of-type(2) a', '#departments .a-spacing-micro:nth-last-of-type(2) a', '.a-breadcrumb li:last-of-type a'],
arrowLeft: ['ul.a-pagination li:first-of-type>a', '#ivThumbs .ivThumb.selected', '#pagnPrevLink'],
arrowRight: ['ul.a-pagination li:last-of-type>a', '#ivThumbs .ivThumb.selected', '#pagnNextLink']
},
'jd': {
enter: [],
esc: [],
w: [],
s: [],
a: ['.f-pager a.fp-prev:not(.disabled)', '.ui-page a.ui-page-prev', '.preview .arrow-prev:not(.disabled)', '.comments-list .ui-pager-prev'],
d: ['.f-pager a.fp-next:not(.disabled)', '.ui-page a.ui-page-next', '.preview .arrow-next:not(.disabled)', '.comments-list .ui-pager-next'],
arrowUp: [],
arrowDown: [],
arrowLeft: ['.f-pager a.fp-prev:not(.disabled)', '.ui-page a.ui-page-prev', '.preview .arrow-prev:not(.disabled)', '.comments-list .ui-pager-prev'],
arrowRight: ['.f-pager a.fp-next:not(.disabled)', '.ui-page a.ui-page-next', '.preview .arrow-next:not(.disabled)', '.comments-list .ui-pager-next']
},
'ruten': {
enter: [".rt-jqmodal-jqmClose"],
esc: [".rt-jqmodal-jqmClose"],
w: [".item-gallery-main-image img.js-main-img"],
s: [],
a: ['.item-gallery .img-popup[style="z-index: 9999; display: block;"] .rti-chevron-left-default', '.pagination .prev', '.rt-pagination li.prev a', '.rt-store-pagination li.prev>a'],
d: ['.item-gallery .img-popup[style="z-index: 9999; display: block;"] .rti-chevron-right-default', '.pagination .next', '.rt-pagination li.next a', '.rt-store-pagination li.next>a'],
arrowUp: [".item-gallery-main-image img.js-main-img"],
arrowDown: [],
arrowLeft: ['.item-gallery .img-popup[style="z-index: 9999; display: block;"] .rti-chevron-left-default', '.pagination .prev', '.rt-pagination li.prev a', '.rt-store-pagination li.prev>a'],
arrowRight: ['.item-gallery .img-popup[style="z-index: 9999; display: block;"] .rti-chevron-right-default', '.pagination .next', '.rt-pagination li.next a', '.rt-store-pagination li.next>a']
},
'shopee': {
enter: [".shopee-alert-popup__button-horizontal-layout>button.shopee-alert-popup__btn:first-child"],
esc: [],
w: ["._2JMB9h"],
s: [],
a: ["#modal .rv7fwm", ".shopee-mini-page-controller__prev-btn", ".shopee-icon-button.shopee-icon-button--left", ".shopee-icon-button._1mHKHL"],
d: ["#modal .HhAy2u", ".shopee-mini-page-controller__next-btn", ".shopee-icon-button.shopee-icon-button--right", ".shopee-icon-button._2H6_oQ"],
arrowUp: ["._2JMB9h"],
arrowDown: [],
arrowLeft: [".shopee-mini-page-controller__prev-btn", ".shopee-icon-button.shopee-icon-button--left", ".shopee-icon-button._1mHKHL"],
arrowRight: [".shopee-mini-page-controller__next-btn", ".shopee-icon-button.shopee-icon-button--right", ".shopee-icon-button._2H6_oQ"]
},
'taobao': {
enter: [],
esc: ["#J_ViewerClose"],
w: [],
s: [],
a: ['.m-sortbar .pager a[trace="srp_select_pageup"]', '.m-page .prev>a', '.pagination a.prev', '.rate-page a[data-page]:first-child', ".rate-paginator a:first-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerPrev', '.ui-page-prev'],
d: ['.m-sortbar .pager a[trace="srp_select_pagedown"]', '.m-page .next>a', '.pagination a.next', '.rate-page a[data-page]:last-child', ".rate-paginator a:last-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerNext', '.ui-page-next'],
arrowUp: [],
arrowDown: [],
arrowLeft: ['.m-sortbar .pager a[trace="srp_select_pageup"]', '.m-page .prev>a', '.pagination a.prev', '.rate-page a[data-page]:first-child', ".rate-paginator a:first-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerPrev', '.ui-page-prev'],
arrowRight: ['.m-sortbar .pager a[trace="srp_select_pagedown"]', '.m-page .next>a', '.pagination a.next', '.rate-page a[data-page]:last-child', ".rate-paginator a:last-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerNext', '.ui-page-next']
},
'tmall': {
enter: [],
esc: ["#J_ViewerClose"],
w: [],
s: [],
a: ['.m-sortbar .pager a[trace="srp_select_pageup"]', '.m-page .prev>a', '.pagination a.prev', '.rate-page a[data-page]:first-child', ".rate-paginator a:first-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerPrev', '.ui-page-prev'],
d: ['.m-sortbar .pager a[trace="srp_select_pagedown"]', '.m-page .next>a', '.pagination a.next', '.rate-page a[data-page]:last-child', ".rate-paginator a:last-child", 'div.ks-overlay:not(.ks-overlay-hidden) #J_ViewerNext', '.ui-page-next'],
arrowUp: [],
arrowDown: [],
arrowLeft: ['.m-sortbar .pager a[trace="srp_select_pageup"]', '.m-page .prev>a', '.pagination a.prev', '.rate-page a[data-page]:first-child', '.ui-page-prev'],
arrowRight: ['.m-sortbar .pager a[trace="srp_select_pagedown"]', '.m-page .next>a', '.pagination a.next', '.rate-page a[data-page]:last-child', '.ui-page-next']
}
};
const hoverEvent = new Event('mouseover');
switch(host) { // 按鍵以外的功能
case "ruten":
if(window.location.href.indexOf('//find.ruten.com.tw/s/?') > 0) {
var watchElm = null;
const watchOpt = { 'attributes': true },
redir = function(){
if(window.location.href.search(/(area=|platform=)/) == -1){
window.location.href = window.location.href + "&platform=ruten";
}
},
observer = new MutationObserver(redir);
redir();
let waitt = window.setInterval(function(){
if(watchElm = document.querySelector("#ProdGridContainer")){
observer.observe(watchElm, watchOpt);
clearInterval(waitt);
}
}, 500);
}
break;
case "jd":
window.scrollTo = function(){};
break;
}
var fnKey = { shift: false, ctrl:false, alt:false, meta:false };
window.onfocus = function() { fnKey.shift = fnKey.ctrl = fnKey.alt = fnKey.meta = false; }
document.addEventListener("keydown", function(e) {
e = e || window.event;
switch(e.which || e.keyCode) {
case 16: // shift
fnKey.shift = true;
break;
case 17: // ctrl
fnKey.ctrl = true;
break;
case 18: // alt
fnKey.alt = true;
break;
case 91: // left Meta
case 93: // right Meta
fnKey.meta = true;
break;
}
});
document.addEventListener("keyup", function(e) {
e = e || window.event;
switch(e.which || e.keyCode) {
case 16: // shift
fnKey.shift = false;
break;
case 17: // ctrl
fnKey.ctrl = false;
break;
case 18: // alt
fnKey.alt = false;
break;
case 91: // left Meta
case 93: // right Meta
fnKey.meta = false;
break;
}
});
document.addEventListener("keydown", async function(e) {
if(document.querySelector("input:focus, textarea:focus") || (fnKey.shift | fnKey.ctrl | fnKey.alt | fnKey.meta)) return;
e = e || window.event;
var elm=null, i;
try {
switch(e.which || e.keyCode) {
case 13: // enter
for(i=0; i < elmPatt[host].enter.length; i++) if(elm = document.querySelector(elmPatt[host].enter[i])) break;
break;
case 27: // esc
for(i=0; i < elmPatt[host].esc.length; i++) if(elm = document.querySelector(elmPatt[host].esc[i])) break;
break;
case 38: // up
for(i=0; i < elmPatt[host].arrowUp.length; i++) if(elm = document.querySelector(elmPatt[host].arrowUp[i])) break;
break;
case 37: // left
for(i=0; i < elmPatt[host].arrowLeft.length; i++) if(elm = document.querySelector(elmPatt[host].arrowLeft[i])) break;
if(host == 'amazon' && i == 1){
let thumbsTotal = document.querySelectorAll('#ivThumbs .ivRow>.ivThumb').length;
let picNo = parseInt(elm.getAttribute("id").replace("ivImage_",""));
elm = document.getElementById("ivImage_"+ (picNo > 0 ? picNo-1 : thumbsTotal-1));
}
break;
case 39: // right
for(i=0; i < elmPatt[host].arrowRight.length; i++) if(elm = document.querySelector(elmPatt[host].arrowRight[i])) break;
if(host == 'amazon' && i == 1){
let thumbsTotal = document.querySelectorAll('#ivThumbs .ivRow>.ivThumb').length;
let picNo = parseInt(elm.getAttribute("id").replace("ivImage_",""));
elm = document.getElementById("ivImage_"+ (picNo == thumbsTotal-1 ? 0 : picNo+1));
}
break;
case 40: // down
for(i=0; i < elmPatt[host].arrowDown.length; i++) if(elm = document.querySelector(elmPatt[host].arrowDown[i])) break;
break;
case 65: // 'a'
for(i=0; i < elmPatt[host].a.length; i++) if(elm = document.querySelector(elmPatt[host].a[i])) break;
if(host == 'amazon' && i == 1){
let thumbsTotal = document.querySelectorAll('#ivThumbs .ivRow>.ivThumb').length;
let picNo = parseInt(elm.getAttribute("id").replace("ivImage_",""));
elm = document.getElementById("ivImage_"+ (picNo > 0 ? picNo-1 : thumbsTotal-1));
}
break;
case 68: // 'd'
for(i=0; i < elmPatt[host].d.length; i++) if(elm = document.querySelector(elmPatt[host].d[i])) break;
if(host == 'amazon' && i == 1){
let thumbsTotal = document.querySelectorAll('#ivThumbs .ivRow>.ivThumb').length;
let picNo = parseInt(elm.getAttribute("id").replace("ivImage_",""));
elm = document.getElementById("ivImage_"+ (picNo == thumbsTotal-1 ? 0 : picNo+1));
}
break;
case 83: // 's'
for(i=0; i < elmPatt[host].s.length; i++) if(elm = document.querySelector(elmPatt[host].s[i])) break;
break;
case 87: // 'w'
for(i=0; i < elmPatt[host].w.length; i++) if(elm = document.querySelector(elmPatt[host].w[i])) break;
break;
}
if(elm) elm.click();
}
catch(e) { console.log(e); }
});
})();