您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
针对知乎的屏幕阅读器可访问性优化
当前为
// ==UserScript== // @name accessibility_知乎键盘访问优化 // @namespace https://www.zhihu.com/people/yin-xiao-bo-11 // @version 0.7 // @description 针对知乎的屏幕阅读器可访问性优化 // @author Veg // @include https://*.zhihu.com/* // @include https://zhuanlan.zhihu.com/* // @grant none // ==/UserScript== (function () { 'use strict'; let exclude = ':not(.veg-mark)'; let mo = new MutationObserver((mutationRecord) => { middleFunction(); }); mo.observe(document.body, { 'childList': true, 'subtree': true }); function middleFunction() { globalShortcutKey(); middlewareFunction(); proc(); } function middlewareFunction() { let token = window.location.href.substring(20).split('/'); if (token[1] == 'follow' || token[1] == 'hot' || token[1] == '') { let aside = document.querySelector('div.TopstoryPageHeader-aside' + exclude); if (aside) { aside.classList.add('veg-mark'); aside.parentNode.setAttribute('style', 'display:none'); } } if (token[1] == 'topic') { // } if (token[1] == 'question') { let title = document.querySelector('h1.QuestionHeader-title'); if (title) { title.setAttribute('style', 'display:none'); } let expandable = document.querySelector('div.QuestionRichText'); if (expandable) { expandable.setAttribute('tabindex', '-1'); let more = expandable.querySelector('button.QuestionRichText-more'); if (more) { more.addEventListener('click', () => { expandable.focus(); }, null); } } } if (token[1] == 'people' || token[1] == 'org') { let profile = document.querySelector('ul.ProfileMain-tabs'); if (profile) { profile.setAttribute('style', 'display:none'); } } if (token[3] === 'log' || token[3] === 'logs' || token[3] === 'topic_logs') { insdel(); } //endFunction } //内容快捷键 function globalShortcutKey() { let timelineStr = 'div.TopstoryItem' + exclude + ', div.QuestionAnswer-content' + exclude + ', div.List-item' + exclude + ', section.HotItem' + exclude + ', div.TopstoryItem-isFollow' + exclude; let timeline = document.querySelectorAll(timelineStr); for (let i = 0, l = timeline.length; i < l; i++) { timeline[i].classList.add('veg-mark'); if (!timeline[i].classList.contains('hotkey-AZ') && timeline[i].hasAttribute('tabindex')) { timeline[i].classList.add('hotkey-AZ'); } let modalWrap = timeline[i].querySelector('div.ModalWrap'); if (modalWrap) { modalWrap.style = 'display:none'; } } // end } //细节优化 function proc() { let videoPackage = document.querySelectorAll('div.ZVideo-video' + exclude + ', div.VideoCard-player' + exclude); for (let i = 0, l = videoPackage.length; i < l; i++) { if (!videoPackage[i].classList.contains('veg-mark')) { videoPackage[i].classList.add('veg-mark'); let button = document.createElement('button'); button.innerHTML = '播放'; button.style = 'background:#FFA500;'; button.addEventListener('click', function () { let iframe = this.parentNode.querySelector('iframe'); if (iframe) window.open(iframe.src); }, null); videoPackage[i].insertBefore(button, videoPackage[i].firstChild); } } //选项卡 let tab = document.querySelectorAll('[role="tab"]' + exclude + ', [role="tablist"]' + exclude); for (let i = 0, l = tab.length; i < l; i++) { tab[i].classList.add('veg-mark'); tab[i].removeAttribute('role'); } let tooltip = document.querySelectorAll('[data-tooltip]' + exclude); for (let i = 0, l = tooltip.length; i < l; i++) { tooltip[i].classList.add('veg-mark'); let label = tooltip[i].getAttribute('data-tooltip'); tooltip[i].setAttribute('aria-label', label); } //搜索 let search = document.querySelector('label.SearchBar-input' + exclude); if (search) { search.classList.add('veg-mark') search.querySelector('input[placeholder]').setAttribute('aria-label', '知乎搜索'); } //优化一些菜单项 let hdxx = document.querySelectorAll('button[aria-haspopup]' + exclude); for (let i = 0, l = hdxx.length; i < l; i++) { hdxx[i].classList.add('veg-mark'); hdxx[i].removeAttribute('role'); hdxx[i].removeAttribute('aria-haspopup'); } /* //补货通知 let notice = document.querySelector('div.Notification-textSection' + exclude); if (notice) { notice.classList.add('veg-mark') let text = notice.innerText; chrome.runtime.sendMessage({ ttsState: "speak", text: text, enqueue: false }); } */ //公共编辑理由、上传视频、上传文档 //注册、登录 //发视频、写想法 let lyStr = 'div.css-stef5c' + exclude + ', div.SignFlow-tab' + exclude + ', div.Login-socialButton' + exclude + ', div.Editable-docModal-uploader-text' + exclude + ',div.Editable-videoModal-uploader-text' + exclude + ', div.NewGlobalWrite-topTitle' + exclude; let ly = document.querySelectorAll(lyStr); for (let i = 0, l = ly.length; i < l; i++) { ly[i].classList.add('veg-mark') ly[i].classList.add('zhihu-click'); ly[i].setAttribute('role', 'button'); ly[i].setAttribute('tabindex', '0'); } // 隐藏选择语言、用户头像、匿名用户头像、动态中的原点 let hiddenElementStr = 'span.Footer-dot' + exclude + ', img[alt="匿名用户"]' + exclude + ', a.UserLink-link' + exclude + ', input[placeholder="选择语言"]' + exclude + ', span.Bull' + exclude; let hiddenElement = document.querySelectorAll(hiddenElementStr); for (let i = 0, l = hiddenElement.length; i < l; i++) { hiddenElement[i].classList.add('veg-mark') if (hiddenElement[i].hasAttribute('alt') || hiddenElement[i].hasAttribute('placeholder') || hiddenElement[i].querySelector('img[src]') || hiddenElement[i].classList.contains('Bull') || hiddenElement[i].classList.contains('Footer-dot') ) { hiddenElement[i].setAttribute('style', 'display:none'); } } // 优化对话框访问 (function () { setTimeout(function () { let dhk = document.querySelectorAll("div.Modal" + exclude); for (let i = 0, l = dhk.length; i < l; i++) { dhk[i].classList.add('veg-mark') dhk[i].setAttribute("role", "dialog"); dhk[i].setAttribute("aria-labelledby", ":1"); let dhks = dhk[i].querySelectorAll("h3.Modal-title,div.Topbar-title,.CommentTopbar-title"); for (let i = 0, l = dhks.length; i < l; i++) { dhks[i].setAttribute("id", ":1"); } let yc = dhk[i].querySelectorAll("button.Tag-remove"); for (let i = 0, l = yc.length; i < l; i++) { yc[i].setAttribute('aria-label', '移除'); } } }, 80); })(); //给匿名用户文本增加焦点 let users = document.querySelectorAll('span.UserLink' + exclude); for (let i = 0; i < users.length; i++) { users[i].classList.add('veg-mark') let names = users[i].innerText; if (names == '匿名用户') { users[i].setAttribute('tabindex', '0'); users[i].setAttribute('role', 'link'); } } //处理评论 let plButton = document.querySelectorAll('div.CommentItem-footer' + exclude + ',div.CommentItemV2-footer' + exclude); for (let i = 0, l = plButton.length; i < l; i++) { plButton[i].classList.add('veg-mark') plButton[i].setAttribute('tabindex', '-1'); plButton[i].setAttribute('role', 'link'); } // endFunction } document.body.addEventListener("keydown", function (k) { shareShortcutKey(k); //键盘点击 let t = k.target; if (t.classList.contains('hotkey-AZ')) { if (k.altKey && k.keyCode == 13) { let text = ClearBr(t.innerText); navigator.clipboard.writeText(text); } } if (t.classList.contains('zhihu-click')) { if (k.keyCode == 13 || k.keyCode == 32) { t.click(); } } }, null); // 阅读全文和收起的焦点管理 document.body.addEventListener('click', (e) => { let t = e.target; if (t.classList.contains('ContentItem-more') || t.classList.contains('ContentItem-expandButton') || t.classList.contains('ContentItem-action')) { let parent = t.parentNode; while (!parent.classList.contains('hotkey-AZ')) { parent = parent.parentNode; } if (parent.classList.contains('hotkey-AZ')) { let heading = parent.querySelector('h2.ContentItem-title'); if (heading) { heading.querySelector('a').focus(); } else { parent.focus(); } } } }, null); //全局快捷键函数 function shareShortcutKey(k) { let hotkey = document.querySelectorAll('.hotkey-AZ'); for (let i=0, l=hotkey.length; i<l; i++) { if (k.altKey && k.keyCode == 65) { hotkey[0].focus(); } if (k.altKey && k.keyCode == 90) { hotkey[l - 1].focus(); } } //获取页面代码 if (k.altKey && k.keyCode == 66) { console.log(document.body.innerHTML); var input = document.createElement('input'); input.value = document.body.innerHTML; document.body.appendChild(input); } if (k.altKey && k.keyCode == 82) { document.querySelector('button[aria-label="更多"]').focus(); } if (k.keyCode == 113) { let Comment = document.querySelector('div.CommentItemV2'); if (Comment !== null) { Comment.setAttribute('tabindex', '-1'); Comment.focus(); } else { let pinComment = document.querySelector('div.CommentItem'); if (pinComment !== null) pinComment.setAttribute('tabindex', '-1'); pinComment.focus(); } } if (k.altKey && k.keyCode == 81) { var gb = document.querySelectorAll("button.ContentItem-action"); for (var i = 0; i < gb.length; i++) { var gbName = gb[i].innerText; var gbNames = gbName.substring(2, 6); if (gbName == '收起评论' || gbNames == '收起评论') { gb[i].click(); gb[i].focus(); } } } if (k.altKey && k.keyCode == 49) { var f = document.querySelectorAll('a.QuestionMainAction,a.NumberBoard-item,a[href="/lives"],button.follow-button,button.NumberBoard-itemWrapper'); for (var i = 0; i < f.length; i++) { //a.zg-btn-white, f[0].focus(); } } if (k.altKey && k.keyCode == 50) { document.querySelector("button.PaginationButton-prev").focus(); } if (k.altKey && k.keyCode == 51) { document.querySelector("button.PaginationButton-next").focus(); } if (k.altKey && k.keyCode == 52) { var more = document.querySelector('a.zu-button-more'); { more.setAttribute('tabindex', '0'); more.focus(); } } if (k.ctrlKey && k.keyCode == 81) { document.querySelector('a[href="/community"]').focus(); } if (k.altKey && k.keyCode == 88) { if (document.querySelector('button.QuestionHeader-edit') !== null) { document.querySelector('button.QuestionHeader-edit').focus(); } else { document.querySelector('button.NumberBoard-item').focus(); } } } function insdel() { let ins = document.querySelectorAll('ins' + exclude); for (let i = 0, l = ins.length; i < l; i++) { if (!ins[i].classList.contains('veg-mark')) { ins[i].classList.add('veg-mark'); let parent = ins[i].parentNode; let div1 = document.createElement("div"); div1.innerHTML = "「已插入:"; parent.insertBefore(div1, ins[i]); div1.appendChild(ins[i]); let div2 = document.createElement("span"); div2.innerHTML = ":插入结束」"; ins[i].appendChild(div2); } } let del = document.querySelectorAll('del' + exclude); for (let i = 0, l = del.length; i < l; i++) { if (!del[i].classList.contains('veg-mark')) { del[i].classList.add('veg-mark'); let parent = del[i].parentNode; let div1 = document.createElement("div"); div1.innerHTML = "「已删除:"; parent.insertBefore(div1, del[i]); div1.appendChild(del[i]); let div2 = document.createElement("span"); div2.innerHTML = ":删除结束」"; del[i].appendChild(div2); } } let fh = document.querySelectorAll('span.zg-bull' + exclude); for (let i = 0, l = fh.length; i < l; i++) { fh[i].classList.add('veg-mark'); let name = fh[i].innerText; if (name == '•') { fh[i].setAttribute('style', 'display:none'); } } let gly = document.querySelectorAll('a' + exclude); for (let i = 0; i < gly.length; i++) { gly[i].classList.add('veg-mark'); let name = gly[i].innerText; if (name == '知乎管理员') { gly[i].setAttribute('href', 'javascript:;'); } } } function ClearBr(key) { key = key.replace( /\n(\n)*( )*(\n)*\n/g, "\n"); return key; } //判断是否有可被 focus 的能力 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; } })();