// ==UserScript==
// @name 字母导航
// @namespace https://www.zhihu.com/people/yin-xiao-bo-11
// @version 0.1
// @description 提供网页元素的字母导航
// @author Veg
// @include http://*/*
// @include https://*/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
//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.playbackRate = 1.4;
audio.play();
}
}
}
let fEight = true;
let element = [];
function switchCtrl(k) {
if (k.keyCode == 119) {
if (fEight == true) {
fEight = false;
navigationTTS('关闭字母导航');
}
else {
fEight = true;
navigationTTS('开启字母导航');
}
}
if (fEight == true)
if (k.keyCode !== 66 &&
k.keyCode !== 67 &&
k.keyCode !== 69 &&
k.keyCode !== 75 &&
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
//keyup
switchCtrl(k);
}, null);
//获取数组下标
function getArraySubscript(arrays, obj) {
var i = arrays.length;
while (i--) {
if (arrays[i] === obj) {
return i;
}
}
return false;
}
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.hasAttribute('disabled') &&
t.getAttribute('role') !== 'button' &&
t.getAttribute('aria-hidden') !== 'true')
if (t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') {
if (t.offsetParent !== null) {
var targetSubscript = getArraySubscript(element, t);
linkSubscript.push(targetSubscript);
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.getAttribute('type') == 'button' || t.getAttribute('type') == 'submit') && t.tagName == 'INPUT') {
if (!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true')
if (t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') {
if (t.offsetParent !== null) {
//var style = window.getComputedStyle(t);
//if (style.width !== 0 && style.height !== 0 && style.opacity !== 0 && style.display !== 'none' && style.visibility !== 'hidden')
var targetSubscript = getArraySubscript(element, t);
buttonSubscript.push(targetSubscript);
return t;
}
}
}
});
var button = buttons.filter(function (n) { return n; })
//复选框导航
let checkSubscript = [];
var checkbox = element.map(function (t) {
if (t.tagName == 'INPUT' && t.getAttribute('type') == 'checkbox' ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'checkbox') {
if (!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true')
if (t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') {
if (t.offsetParent !== null) {
var targetSubscript = getArraySubscript(element, t);
checkSubscript.push(targetSubscript);
return t;
}
}
}
});
var check = checkbox.filter(function (n) { return n; })
//文本框导航
let textSubscript = [];
var textbox = element.map(function (t) {
if (t.tagName == 'INPUT' && t.getAttribute('type') == 'text' ||
t.tagName == 'INPUT' && t.getAttribute('type') == null ||
t.tagName == 'TEXTAREA' ||
t.hasAttribute && t.hasAttribute('role') && t.getAttribute('role') == 'textbox') {
if (!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true')
if (t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') {
if (t.offsetParent !== null) {
var targetSubscript = getArraySubscript(element, t);
textSubscript.push(targetSubscript);
return t;
}
}
}
});
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 (!t.hasAttribute('disabled') &&
t.getAttribute('aria-hidden') !== 'true')
if (t.tabIndex >= 0 || t.hasAttribute && t.hasAttribute('tabindex') && t.getAttribute('tabindex') == '-1') {
if (t.offsetParent !== null) {
var targetSubscript = getArraySubscript(element, t);
comboSubscript.push(targetSubscript);
return t;
}
}
}
});
var combo = combobox.filter(function (n) { return n; })
element.length = 0;
//反向切换
if (k.shiftKey && k.keyCode == 75) {
for (var i = 0, l = link.length || linkSubscript.length; i < l; i++) {
if (nFES > linkSubscript[l - 1] || nFES <= linkSubscript[0]) {
link[l - 1].focus();
break;
}
else {
if (nFES <= linkSubscript[i]) {
var xv = getArraySubscript(link, link[i]);
link[xv - 1].focus();
reverseAccident(link, xv);
break;
}
}
}
}
if (k.shiftKey && k.keyCode == 66) {
for (var i = 0, l = button.length || buttonSubscript.length; i < l; i++) {
if (nFES > buttonSubscript[l - 1] || nFES <= buttonSubscript[0]) {
button[l - 1].focus();
break;
}
else {
if (nFES <= buttonSubscript[i]) {
var xv = getArraySubscript(button, button[i]);
button[xv - 1].focus();
reverseAccident(button, xv);
break;
}
}
}
}
if (k.shiftKey && k.keyCode == 88) {
for (var i = 0, l = check.length || checkSubscript.length; i < l; i++) {
if (nFES > checkSubscript[l - 1] || nFES <= checkSubscript[0]) {
check[l - 1].focus();
break;
}
else {
if (nFES <= checkSubscript[i]) {
var xv = getArraySubscript(check, check[i]);
check[xv - 1].focus();
reverseAccident(check, xv);
break;
}
}
}
}
if (k.shiftKey && k.keyCode == 69) {
for (var i = 0, l = text.length || textSubscript.length; i < l; i++) {
if (nFES > textSubscript[l - 1] || nFES <= textSubscript[0]) {
text[l - 1].focus();
break;
}
else {
if (nFES <= textSubscript[i]) {
var xv = getArraySubscript(text, text[i]);
text[xv - 1].focus();
reverseAccident(text, xv);
break;
}
}
}
}
if (k.shiftKey && k.keyCode == 67) {
for (var i = 0, l = combo.length || comboSubscript.length; i < l; i++) {
if (nFES > comboSubscript[l - 1] || nFES <= comboSubscript[0]) {
combo[l - 1].focus();
break;
}
else {
if (nFES <= comboSubscript[i]) {
var xv = getArraySubscript(combo, combo[i]);
combo[xv - 1].focus();
reverseAccident(combo, xv);
break;
}
}
}
}
//正向切换
if (k.altKey || k.ctrlKey || k.shiftKey) return false;
if (k.keyCode == 75) {
for (var i = 0, l = link.length || linkSubscript.length; i < l; i++) {
if (nFES < linkSubscript[i]) {
var xv = getArraySubscript(link, link[i]);
link[xv].focus();
positiveAccident(link, xv);
break;
}
else {
if (nFES < linkSubscript[0] || nFES >= linkSubscript[l - 1]) {
link[0].focus();
break;
}
}
}
}
if (k.keyCode == 66) {
for (var i = 0, l = button.length || buttonSubscript.length; i < l; i++) {
if (nFES < buttonSubscript[i]) {
var xv = getArraySubscript(button, button[i]);
button[xv].focus();
positiveAccident(button, xv);
break;
}
else {
if (nFES < buttonSubscript[0] || nFES >= buttonSubscript[l - 1]) {
button[0].focus();
break;
}
}
}
}
if (k.keyCode == 88) {
for (var i = 0, l = check.length || checkSubscript.length; i < l; i++) {
if (nFES < checkSubscript[i]) {
var xv = getArraySubscript(check, check[i]);
check[xv].focus();
positiveAccident(check, xv);
break;
}
else {
if (nFES < checkSubscript[0] || nFES >= checkSubscript[l - 1]) {
check[0].focus();
break;
}
}
}
}
if (k.keyCode == 69) {
for (var i = 0, l = text.length || textSubscript.length; i < l; i++) {
if (nFES < textSubscript[i]) {
var xv = getArraySubscript(text, text[i]);
text[xv].focus();
positiveAccident(text, xv);
break;
}
else {
if (nFES < textSubscript[0] || nFES >= textSubscript[l - 1]) {
text[0].focus();
break;
}
}
}
}
if (k.keyCode == 67) {
for (var i = 0, l = combo.length || comboSubscript.length; i < l; i++) {
if (nFES < comboSubscript[i]) {
var xv = getArraySubscript(combo, combo[i]);
combo[xv].focus();
positiveAccident(combo, xv);
break;
}
else {
if (nFES < comboSubscript[0] || nFES >= comboSubscript[l - 1]) {
combo[0].focus();
break;
}
}
}
}
}
(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;
setTimeout(function () {
//navigationTTS('字母导航准备好了');
}, 50);
}
});
})();
function reverseAccident(e, xv) {
var ev = e[xv - 1].innerText;
while (ev !== document.activeElement.innerText) {
xv--
e[xv - 1].focus();
ev = e[xv - 1].innerText;
}
}
function positiveAccident(e, xv) {
var ev = e[xv].innerText;
while (ev !== document.activeElement.innerText) {
xv++
e[xv].focus();
ev = e[xv].innerText;
}
}
var audio = new Audio("https://veg.ink/music/sound.mp3");
audio.volume = 0.15;
audio.play();