Last active
May 23, 2018 15:37
-
-
Save keriati/ec61795abd34908c92c09bd5555b3234 to your computer and use it in GitHub Desktop.
Keybindings for Hacker news for tampermonkey
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name HackerNews Keyboard Shortcuts | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Adds j,k,o,c keybindings to navigate hackernews. | |
// @author Attila Kerekes | |
// @match https://news.ycombinator.com/news | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
var CLASS_NAME_ARTICLE = 'athing'; | |
var CLASS_NAME_SELECTED = 'selected'; | |
var SELECTOR_SELECTED_ARTICLE_LINK = '.athing.selected .storylink'; | |
createSelectedStyle(); | |
addKeyBindings(); | |
function createSelectedStyle() { | |
var node = document.createElement('style'); | |
node.innerHTML = '.athing.selected { background-color: rgba(0,0,0,0.1) }'; | |
document.body.appendChild(node); | |
} | |
function addKeyBindings() { | |
var actions = { | |
j: selectNextArticle, | |
k: selectPrevArticle, | |
o: openSelectedArticle, | |
c: openSelectedArticleComments | |
}; | |
document.addEventListener('keydown', function (event) { | |
try { | |
actions[event.key](); | |
} catch (e) { | |
} | |
}); | |
} | |
function selectNextArticle() { | |
var allArticles = getAllArticles(); | |
var selectedArticle = getSelectedArticle(); | |
deselectArticle(allArticles, selectedArticle); | |
addSelectedClassToNextArticle(allArticles, selectedArticle); | |
} | |
function getAllArticles() { | |
return getNodeArrayBySelector('.' + CLASS_NAME_ARTICLE); | |
} | |
function getNodeArrayBySelector(selector) { | |
return [].slice.call(document.querySelectorAll(selector)) | |
} | |
function getSelectedArticle() { | |
return document.querySelectorAll('.' + CLASS_NAME_ARTICLE + '.' + CLASS_NAME_SELECTED)[0]; | |
} | |
function deselectArticle(allArticles, selectedArticle) { | |
if (!selectedArticle) { | |
return; | |
} | |
selectedArticle.classList.remove(CLASS_NAME_SELECTED); | |
} | |
function addSelectedClassToNextArticle(allArticles, selectedArticle) { | |
if (isLastArticle(allArticles, selectedArticle)) { | |
selectFirstArticle(allArticles); | |
return; | |
} | |
allArticles[allArticles.indexOf(selectedArticle) + 1].classList.add(CLASS_NAME_SELECTED); | |
} | |
function isLastArticle(allArticles, selectedArticle) { | |
return allArticles.indexOf(selectedArticle) >= allArticles.length - 1; | |
} | |
function selectFirstArticle(allArticles) { | |
allArticles[0].classList.add(CLASS_NAME_SELECTED); | |
} | |
function selectPrevArticle() { | |
var allArticles = getAllArticles(); | |
var selectedArticle = getSelectedArticle(); | |
deselectArticle(allArticles, selectedArticle); | |
addSelectedClassToPrevArticle(allArticles, selectedArticle); | |
} | |
function addSelectedClassToPrevArticle(allArticles, selectedArticle) { | |
if (isFirstArticle(allArticles, selectedArticle) | |
|| isUnselected(allArticles, selectedArticle)) { | |
selectLastArticle(allArticles); | |
return; | |
} | |
allArticles[allArticles.indexOf(selectedArticle) - 1].classList.add(CLASS_NAME_SELECTED); | |
} | |
function isFirstArticle(allArticles, selectedArticle) { | |
return allArticles.indexOf(selectedArticle) === 0; | |
} | |
function isUnselected(allArticles, selectedArticle) { | |
return allArticles.indexOf(selectedArticle) === -1; | |
} | |
function selectLastArticle(allArticles) { | |
allArticles[allArticles.length - 1].classList.add(CLASS_NAME_SELECTED); | |
} | |
function openSelectedArticle() { | |
window.open(getSelectedArticleAnchor().href, "_self"); | |
} | |
function getSelectedArticleAnchor() { | |
return document.querySelectorAll(SELECTOR_SELECTED_ARTICLE_LINK)[0]; | |
} | |
function openSelectedArticleComments() { | |
var selectedArticle = getSelectedArticle(); | |
var commentAnchor = getCommentAnchorForArticle(selectedArticle); | |
window.open(commentAnchor.href, "_self"); | |
} | |
function getCommentAnchorForArticle(selectedArticle) { | |
return selectedArticle.nextSibling.querySelectorAll('a')[3]; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment