forked from AmineB/ycombinator-keys
Compare commits
No commits in common. "main" and "main" have entirely different histories.
54
keyboard-watcher.js
Normal file
54
keyboard-watcher.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
let selectedId = -1;
|
||||||
|
|
||||||
|
document.onkeypress = function(evt) {
|
||||||
|
evt = evt || window.event;
|
||||||
|
var charCode = evt.keyCode || evt.which;
|
||||||
|
var charStr = String.fromCharCode(charCode);
|
||||||
|
switch(charStr) {
|
||||||
|
case 'j':
|
||||||
|
handlePrevious()
|
||||||
|
selectedId = selectedId + 1;
|
||||||
|
highlightSelected();
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
if (selectedId > 0) {
|
||||||
|
handlePrevious()
|
||||||
|
selectedId = selectedId - 1;
|
||||||
|
}
|
||||||
|
highlightSelected();
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
document.querySelectorAll(".itemlist tbody tr td.subtext .clicky")[selectedId].click();
|
||||||
|
highlightSelected();
|
||||||
|
break
|
||||||
|
case 'r':
|
||||||
|
location.reload()
|
||||||
|
case 'o':
|
||||||
|
targetBlankClickAndReset(document.querySelectorAll(".itemlist tbody tr.athing td.title a")[selectedId])
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
targetBlankClickAndReset(document.querySelectorAll(".itemlist tbody tr td.subtext a:not(.clicky):not(.hnuser)")[selectedId]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function highlightSelected() {
|
||||||
|
if (selectedId != -1) {
|
||||||
|
document.querySelectorAll(".itemlist tbody tr.athing")[selectedId].style.boxShadow = "0px 0px 10px 4px rgba(0,0,0,0.73)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePrevious() {
|
||||||
|
if (selectedId != -1) {
|
||||||
|
document.querySelectorAll(".itemlist tbody tr.athing")[selectedId].style.boxShadow = "initial";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function targetBlankClickAndReset(el) {
|
||||||
|
el.target = "_blank";
|
||||||
|
setTimeout(() => {
|
||||||
|
el.click();
|
||||||
|
el.target = "";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,103 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name ycombinator-keys
|
|
||||||
// @namespace https://gitea.amine-bouabdallaoui.fr/AmineB/ycombinator-keys
|
|
||||||
// @license gpl-3.0-only
|
|
||||||
// @match http*://news.ycombinator.com/*
|
|
||||||
// @icon https://gitea.amine-bouabdallaoui.fr/AmineB/ycombinator-keys/raw/branch/main/icons/48.png
|
|
||||||
// @grant none
|
|
||||||
// @version 5
|
|
||||||
// @author AmineB
|
|
||||||
// @description Ycombinator keyboard nav.
|
|
||||||
// @downloadURL https://gitea.amine-bouabdallaoui.fr/brian6932/ycombinator-keys/raw/branch/main/keyboard-watcher.user.js
|
|
||||||
// @updateURL https://gitea.amine-bouabdallaoui.fr/brian6932/ycombinator-keys/raw/branch/main/keyboard-watcher.user.js
|
|
||||||
// ==/UserScript==
|
|
||||||
// jshint esversion: 11
|
|
||||||
|
|
||||||
globalThis.document.styleSheets[0].insertRule('tbody tr.athing>td.title>span.titleline>a:focus,tbody tr.athing.comtr a.togg.clicky:focus{outline: none}')
|
|
||||||
|
|
||||||
const requery = () => globalThis.document.querySelectorAll('tbody tr.athing')
|
|
||||||
let
|
|
||||||
query = requery(),
|
|
||||||
selected = -1
|
|
||||||
const
|
|
||||||
// This is a Firefox only option. For some reason older versions of Firefox can't set outline: none.
|
|
||||||
focusInvisible = { __proto__: null, focusVisible: false },
|
|
||||||
isComment = () => query[selected].classList.contains('comtr'),
|
|
||||||
highlightSelected = () => {
|
|
||||||
query[selected].style.boxShadow = '0px 0px 10px 4px rgba(0,0,0,0.73)'
|
|
||||||
|
|
||||||
isComment() ?
|
|
||||||
// Drawing the boxShadow on this selector isn't visible enough.
|
|
||||||
query[selected].querySelector('a.togg.clicky')?.focus(focusInvisible)
|
|
||||||
:
|
|
||||||
// Focuses link without re-query.
|
|
||||||
query[selected].lastChild.firstChild.firstChild.focus(focusInvisible)
|
|
||||||
},
|
|
||||||
keydown = event => {
|
|
||||||
switch (event.key) {
|
|
||||||
case 'j':
|
|
||||||
if (selected + 1 === query.length)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (selected !== -1)
|
|
||||||
query[selected].style.boxShadow = ''
|
|
||||||
|
|
||||||
while (selected < query.length && query[++selected].classList.contains('noshow'));
|
|
||||||
highlightSelected()
|
|
||||||
return
|
|
||||||
case 'k':
|
|
||||||
if (selected <= 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
query[selected].style.boxShadow = ''
|
|
||||||
while (selected >= 0 && query[--selected].classList.contains('noshow'));
|
|
||||||
highlightSelected()
|
|
||||||
return
|
|
||||||
case 'h':
|
|
||||||
if (globalThis.location.pathname === '/hidden')
|
|
||||||
for (const selector of query[selected].nextSibling.querySelectorAll('a'))
|
|
||||||
if (selector.innerText === 'un-hide') {
|
|
||||||
selector.click()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
else
|
|
||||||
query[selected].nextSibling.querySelector('a.clicky.hider')?.click()
|
|
||||||
if (selected + 1 <= query.length)
|
|
||||||
highlightSelected()
|
|
||||||
return
|
|
||||||
case 'c':
|
|
||||||
globalThis.open('https://news.ycombinator.com/item?id=' + query[selected].id, '_self')
|
|
||||||
return
|
|
||||||
case 'C':
|
|
||||||
globalThis.open('https://news.ycombinator.com/item?id=' + query[selected].id)
|
|
||||||
return
|
|
||||||
case 'r':
|
|
||||||
if (!isComment())
|
|
||||||
return
|
|
||||||
globalThis.open(query[selected].querySelector('div.reply a').href, '_self')
|
|
||||||
return
|
|
||||||
case 'R':
|
|
||||||
if (!isComment())
|
|
||||||
return
|
|
||||||
globalThis.open(query[selected].querySelector('div.reply a').href)
|
|
||||||
return
|
|
||||||
case 'u':
|
|
||||||
globalThis.open((isComment() ? query[selected] : query[selected].nextSibling).querySelector('a.hnuser').href, '_self')
|
|
||||||
return
|
|
||||||
case 'U':
|
|
||||||
globalThis.open((isComment() ? query[selected] : query[selected].nextSibling).querySelector('a.hnuser').href)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
listen = () => globalThis.document.addEventListener('keydown', keydown)
|
|
||||||
|
|
||||||
listen()
|
|
||||||
|
|
||||||
// This allows for compatibility with automatic pagination scripts.
|
|
||||||
new globalThis.MutationObserver(mutations => {
|
|
||||||
for (const mutation of mutations)
|
|
||||||
if (mutation.type === 'childList') {
|
|
||||||
globalThis.document.removeEventListener('keydown', keydown)
|
|
||||||
query = requery()
|
|
||||||
return listen()
|
|
||||||
}
|
|
||||||
}).observe(globalThis.document.body, { __proto__: null, childList: true, subtree: true })
|
|
@ -1,24 +1,21 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
|
||||||
"name": "Ycombinator keyboard navigation",
|
"manifest_version": 2,
|
||||||
"version": "4",
|
"name": "Ycombinator keyboard navigation",
|
||||||
"description": "Navigate ycombinator with your keyboard",
|
"version": "1",
|
||||||
"icons": {
|
|
||||||
"48": "icons/48.png"
|
"description": "Navigate ycombinator with your keyboard",
|
||||||
},
|
|
||||||
"content_scripts": [
|
"icons": {
|
||||||
{
|
"48": "icons/48.png"
|
||||||
"matches": [
|
},
|
||||||
"*://news.ycombinator.com/*"
|
|
||||||
],
|
"content_scripts": [
|
||||||
"js": [
|
{
|
||||||
"keyboard-watcher.user.js"
|
"matches": ["*://*.ycombinator.com/*"],
|
||||||
]
|
"js": ["keyboard-watcher.js"]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"browser_specific_settings": {
|
|
||||||
"gecko": {
|
|
||||||
"id": "{8baac415-d606-422e-89a6-2122747c54dc}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
export default {
|
|
||||||
__proto__: null,
|
|
||||||
ignoreFiles: [
|
|
||||||
"README.md",
|
|
||||||
"LICENSE"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user