// ==UserScript==
// @name 字母导航
// @namespace https://www.zhihu.com/people/yin-xiao-bo-11
// @version 0.1.3
// @description 提供网页元素的字母导航
// @author Veg
// @include http://*/*
// @include https://*/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
"use strict";
let navigationTTSToken;
//TTS 函数
function navigationTTS(TTStext) {
var zhText = encodeURI(TTStext);
var parameter = "&vol=7&per=0&spd=9&pit=7";
var voicebbUrl = "https://tsn.baidu.com/text2audio?lan=zh&ctp=1&cuid=xiaobo&tok=" + navigationTTSToken + "&tex=" + zhText + parameter;
var audio = document.querySelector('audio.audio-navigation'); {
if (audio !== null) {
audio.src = voicebbUrl;
audio.volume = 0.6;
audio.playbackRate = 1.4;
audio.play();
}
}
}
(function () {
//插入播放器
var audio = document.createElement('audio');
audio.className = 'audio-navigation';
audio.volume = 0.6;
document.body.appendChild(audio);
GM_xmlhttpRequest({
method: "GET",
headers: { "Accept": "Content-Type:application/json" },
url: "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=DmRzeWmTGgwPuPrFyHPhxLFH&client_secret=iYUz9bmANfuDBhlpacObRCq4qutDHfSe",
onload: function (response) {
var data = response.responseText;
var datas = JSON.parse(data);
navigationTTSToken = datas.access_token;
}
});
})();
let fEight = true;
let element = [];
let nFES;
function textNavigation(k) {
//文本框导航
let textSubscript = [];
var textbox = textFunction(textSubscript);
var text = textbox.filter(function (n) { return n; })
//组合框导航
let comboSubscript = [];
var combobox = element.map(function (t) {
if (t.tagName == 'SELECT' ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'combobox') {
if (abilityDetection(t) == true) {
comboSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var combo = combobox.filter(function (n) { return n; })
element.length = 0;
var ef = document.activeElement;
if (ifTrue(ef) == true)
return false;
if (k.altKey && k.keyCode == 67) {
positiveJump(combo, comboSubscript);
}
if (k.shiftKey && k.keyCode == 67) {
reverseJump(combo, comboSubscript);
}
if (k.shiftKey && k.keyCode == 69) {
reverseJump(text, textSubscript);
}
if (k.altKey && k.keyCode == 87) {
positiveJump(text, textSubscript);
}
if (k.altKey || k.shiftKey || k.ctrlKey) return false;
if (k.keyCode == 67) {
positiveJump(combo, comboSubscript);
}
if (k.keyCode == 69) {
positiveJump(text, textSubscript);
}
}
document.body.addEventListener('keyup', function (k) {
if (k.keyCode !== 67 &&
k.keyCode !== 69 &&
k.keyCode !== 87) {
return false;
}
else {
var all = document.all;
for (var i = 0, l = all.length; i < l; i++) {
if (all[i].nodeType == 1) {
element.push(all[i]);
}
}
nFES = getArraySubscript(element, document.activeElement);
textNavigation(k);
}
}, null);
function switchCtrl(k) {
if (k.keyCode == 119) {
if (fEight == true) {
fEight = false;
navigationTTS('关闭字母导航');
}
else {
fEight = true;
navigationTTS('开启字母导航');
}
}
if (fEight == true)
if (k.keyCode !== 49 &&
k.keyCode !== 50 &&
k.keyCode !== 51 &&
k.keyCode !== 52 &&
k.keyCode !== 53 &&
k.keyCode !== 54 &&
k.keyCode !== 33 &&
k.keyCode !== 34 &&
k.keyCode !== 66 &&
k.keyCode !== 72 &&
k.keyCode !== 75 &&
k.keyCode !== 76 &&
k.keyCode !== 82 &&
k.keyCode !== 84 &&
k.keyCode !== 87 &&
k.keyCode !== 88 &&
k.keyCode !== 119) {
return false;
}
else {
var all = document.all;
for (var i = 0, l = all.length; i < l; i++) {
if (all[i].nodeType == 1) {
element.push(all[i]);
}
}
nFES = getArraySubscript(element, document.activeElement);
lnavigation(k);
}
}
document.body.addEventListener('keydown', function (k) {
//keydown
//keypress
//keyup
switchCtrl(k);
}, null);
function lnavigation(k) {
//链接导航
let linkSubscript = [];
var links = element.map(function (t) {
if (t.tagName == 'A' ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'link') {
if (t.getAttribute('role') !== 'button')
if (abilityDetection(t) == true) {
linkSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var link = links.filter(function (n) { return n; });
//按钮导航
let buttonSubscript = [];
var buttons = element.map(function (t) {
if (t.tagName == 'BUTTON' ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'button' ||
(t.type == 'file' || t.type == 'button' || t.type == 'submit') && t.tagName == 'INPUT') {
if (abilityDetection(t) == true) {
buttonSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var button = buttons.filter(function (n) { return n; })
//复选框导航
let checkSubscript = [];
var checkbox = formFunction('INPUT', 'checkbox', checkSubscript);
var check = checkbox.filter(function (n) { return n; })
//单选复选框导航
let radioSubscript = [];
var radios = formFunction('INPUT', 'radio', radioSubscript);
var radio = radios.filter(function (n) { return n; })
//文本框导航
let textSubscript = [];
var textbox = textFunction(textSubscript);
var text = textbox.filter(function (n) { return n; })
//标题导航
let heaSubscript = [];
var headings = element.map(function (t) {
var tag = t.tagName;
if (tag == 'H1' || tag == 'H2' || tag == 'H3' || tag == 'H4' || tag == 'H5' || tag == 'H6') {
if (abilityDetection2(t) == true) {
if (t.getAttribute('tabindex') == null) {
t.setAttribute('tabindex', '-1');
t.setAttribute('role', 'heading');
t.addEventListener('keydown', function (k) {
if (k.keyCode == 13) {
if (t.querySelector('a') !== null)
t.querySelector('a').click();
}
}, null);
}
heaSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var hea = headings.filter(function (n) { return n; })
//一级标题
let hea1Subscript = [];
var heading1 = head('H1', '1', hea1Subscript);
var hea1 = heading1.filter(function (n) { return n; })
//二级标题
let hea2Subscript = [];
var heading2 = head('H2', '2', hea2Subscript);
var hea2 = heading2.filter(function (n) { return n; })
//三级标题
let hea3Subscript = [];
var heading3 = head('H3', '3', hea3Subscript);
var hea3 = heading3.filter(function (n) { return n; })
//四级标题
let hea4Subscript = [];
var heading4 = head('H4', '4', hea4Subscript);
var hea4 = heading4.filter(function (n) { return n; })
//五级标题
let hea5Subscript = [];
var heading5 = head('H5', '5', hea5Subscript);
var hea5 = heading5.filter(function (n) { return n; })
//六级标题
let hea6Subscript = [];
var heading6 = head('H6', '6', hea6Subscript);
var hea6 = heading6.filter(function (n) { return n; })
//列表导航
let ulSubscript = [];
var uls = element.map(function (t) {
if (t.tagName == 'UL') {
if (abilityDetection2(t) == true) {
if (t.getAttribute('tabindex') == null) {
t.setAttribute('tabindex', '-1');
t.setAttribute('role', 'list');
}
ulSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var ul = uls.filter(function (n) { return n; })
//表格导航
let tableSubscript = [];
//let trs = [];
var tables = element.map(function (t) {
if (t.tagName == 'TABLE') {
if (abilityDetection2(t) == true) {
if (!t.hasAttribute('tabindex')) {
t.setAttribute('tabindex', '-1');
}
//t.setAttribute('role','grid');
//t.setAttribute('role', 'table');
//t.setAttribute('role', 'rowgroup');
//row 行
//rowgroup h 行标头
tableSubscript.push(getArraySubscript(element, t));
return t;
}
}
});
var table = tables.filter(function (n) { return n; })
/*
var trs=element.map(function(ts){
if(ts.tagName== 'TR') {
//alert('ok');
if(!ts.hasAttribute('tabindex')) {
ts.setAttribute('tabindex','0');
}
return ts;
}
});
var tr = trs.filter(function (n) { return n; })
for (var p=0; p<table.length; p++) {
table[p].addEventListener('keydown',function(k) {
var fe=document.activeElement;
if(k.altKey && k.shiftKey && k.keyCode == 38) {
if(fe.tagName == 'TR') {
var xv = getArraySubscript(tr, fe);
alert(xv);
tr[xv-1].focus();
break;
}
}
if(k.altKey && k.shiftKey && k.keyCode == 40) {
if(fe.tagName == 'TR') {
var xv = getArraySubscript(trs, fe);
alert(xv);
tr[xv+1].focus();
break;
}
}
},null);
}
*/
element.length = 0;
var ef = document.activeElement;
if (ifTrue(ef) == true)
return false;
//反向切换
if (k.shiftKey && k.keyCode == 66) {
reverseJump(button, buttonSubscript);
}
if (k.shiftKey && k.keyCode == 75) {
reverseJump(link, linkSubscript);
}
if (k.shiftKey && k.keyCode == 76) {
reverseJump(ul, ulSubscript);
}
if (k.shiftKey && k.keyCode == 82) {
reverseJump(radio, radioSubscript);
}
if (k.shiftKey && k.keyCode == 84) {
reverseJump(table, tableSubscript);
tableSupport();
}
if (k.shiftKey && k.keyCode == 88) {
reverseJump(check, checkSubscript);
}
if (k.shiftKey && k.keyCode == 72) {
reverseJump(hea, heaSubscript);
}
if (k.shiftKey && k.keyCode == 49) {
reverseJump(hea1, hea1Subscript);
}
if (k.shiftKey && k.keyCode == 50) {
reverseJump(hea2, hea2Subscript);
}
if (k.shiftKey && k.keyCode == 51) {
reverseJump(hea3, hea3Subscript);
}
if (k.shiftKey && k.keyCode == 52) {
reverseJump(hea4, hea4Subscript);
}
if (k.shiftKey && k.keyCode == 53) {
reverseJump(hea5, hea5Subscript);
}
if (k.shiftKey && k.keyCode == 54) {
reverseJump(hea6, hea6Subscript);
}
//正向切换
if (k.altKey || k.ctrlKey || k.shiftKey) return false;
if (k.keyCode == 66) {
positiveJump(button, buttonSubscript);
}
if (k.keyCode == 75) {
positiveJump(link, linkSubscript);
}
if (k.keyCode == 76) {
positiveJump(ul, ulSubscript);
}
if (k.keyCode == 82) {
positiveJump(radio, radioSubscript);
}
if (k.keyCode == 84) {
positiveJump(table, tableSubscript);
tableSupport();
}
if (k.keyCode == 88) {
positiveJump(check, checkSubscript);
}
if (k.keyCode == 72) {
positiveJump(hea, heaSubscript);
}
if (k.keyCode == 49) {
positiveJump(hea1, hea1Subscript);
}
if (k.keyCode == 50) {
positiveJump(hea2, hea2Subscript);
}
if (k.keyCode == 51) {
positiveJump(hea3, hea3Subscript);
}
if (k.keyCode == 52) {
positiveJump(hea4, hea4Subscript);
}
if (k.keyCode == 53) {
positiveJump(hea5, hea5Subscript);
}
if (k.keyCode == 54) {
positiveJump(hea6, hea6Subscript);
}
}
//正向导航函数
function positiveJump(a, b) {
for (var i = 0, l = a.length || b.length; i < l; i++) {
if (nFES < b[i]) {
var xv = getArraySubscript(a, a[i]);
a[xv].focus();
var ev = a[xv].innerText;
while (ev !== document.activeElement.innerText) {
xv++
a[xv].focus();
ev = a[xv].innerText;
}
break;
}
else {
if (nFES < b[0] || nFES >= b[l - 1]) {
a[0].focus();
break;
}
}
}
}
//反向导航函数
function reverseJump(a, b) {
for (var i = 0, l = a.length || b.length; i < l; i++) {
if (nFES > b[l - 1] || nFES <= b[0]) {
a[l - 1].focus();
break;
}
else {
if (nFES <= b[i]) {
var xv = getArraySubscript(a, a[i]);
a[xv - 1].focus();
var ev = a[xv - 1].innerText;
while (ev !== document.activeElement.innerText) {
xv--
a[xv - 1].focus();
ev = a[xv - 1].innerText;
}
break;
}
}
}
}
//获取数组下标
function getArraySubscript(arrays, obj) {
var i = arrays.length;
while (i--) {
if (arrays[i] === obj) {
return i;
}
}
return false;
}
//分级标题函数
function head(a, b, c) {
var d = element.map(function (t) {
if (t.tagName == a) {
if (abilityDetection2(t) == true) {
if (t.getAttribute('aria-level') == null) {
t.setAttribute('aria-level', b);
t.setAttribute('title', a);
}
c.push(getArraySubscript(element, t));
return t;
}
}
});
return d;
}
//文本框函数
function textFunction(c) {
var d = element.map(function (t) {
if (ifTrue(t) == true) {
if (abilityDetection(t) == true) {
c.push(getArraySubscript(element, t));
return t;
}
}
});
return d;
}
//部分表单函数
function formFunction(a, b, c) {
var d = element.map(function (t) {
if (t.tagName == a && t.getAttribute('type') == b ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == b) {
if (abilityDetection(t) == true) {
c.push(getArraySubscript(element, t));
return t;
}
}
});
return d;
}
function ifTrue(t) {
if ((t.type == 'text' || t.type == 'password' || t.type == 'email' || t.type == 'number' || t.type == 'search' || t.type == 'tel' || t.type == 'url') && t.tagName == 'INPUT' ||
t.tagName == 'PRE' ||
t.tagName == 'TEXTAREA' ||
t.tagName == 'INPUT' && t.getAttribute('type') == null ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'textbox')
return true;
}
function abilityDetection(t) {
if ((t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') &&
!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true' &&
t.offsetParent !== null)
return true;
}
function abilityDetection2(t) {
if (!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true' &&
t.offsetParent !== null)
return true;
}
/*
*/
function tableSupport() {
var fes = document.activeElement;
if (fes.tagName == 'TABLE') {
let trs = [];
//let tds = [];
fes.addEventListener('keydown', function (k) {
trs.length = 0;
//tds.length = 0;
var tr = this.querySelectorAll('tr');
for (var i = 0, l = tr.length; i < l; i++) {
if (!tr[i].hasAttribute('tabindex')) {
tr[i].setAttribute('tabindex', '0');
}
trs.push(tr[i]);
/*
var td = tr[i].querySelectorAll('td');
for (var j = 0, w = td.length; j < w; j++) {
if (!td[j].hasAttribute('tabindex')) {
td[j].setAttribute('tabindex', '0');
}
tds.push(td[j]);
}
*/
}
var fe = document.activeElement;
if (k.altKey && k.shiftKey && k.keyCode == 33) {
if (fe.tagName == 'TABLE') {
var len = trs.length;
trs[len - 1].focus();
}
else if (fe.tagName == 'TR') {
var xv = getArraySubscript(trs, fe);
trs[xv - 1].focus();
}
else if (fe.tagName !== 'TR') {
while (fe.parentNode.tagName !== 'TR') {
fe = fe.parentNode;
var ttr = fe.parentNode;
if (ttr.tagName == 'TR') {
var xv = getArraySubscript(trs, ttr);
trs[xv].focus();
}
}
}
}
if (k.altKey && k.shiftKey && k.keyCode == 34) {
if (fe.tagName == 'TABLE') {
trs[0].focus();
}
else if (fe.tagName == 'TR') {
var xv = getArraySubscript(trs, fe);
trs[xv + 1].focus();
}
else if (fe.tagName !== 'TR') {
while (fe.parentNode.tagName !== 'TR') {
fe = fe.parentNode;
var ttr = fe.parentNode;
if (ttr.tagName == 'TR') {
var xv = getArraySubscript(trs, ttr);
trs[xv + 1].focus();
}
}
}
}
/*
if (k.altKey && k.shiftKey && k.keyCode == 37) {
}
if (k.altKey && k.shiftKey && k.keyCode == 39) {
}
*/
}, null);
}
}