Skip to content

Instantly share code, notes, and snippets.

@keriati
Last active May 23, 2018 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keriati/ec61795abd34908c92c09bd5555b3234 to your computer and use it in GitHub Desktop.
Save keriati/ec61795abd34908c92c09bd5555b3234 to your computer and use it in GitHub Desktop.
Keybindings for Hacker news for tampermonkey
// ==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