Browse Source

v1.4 better support for different stylesheets, better scrolling, refresh hotkey

pull/40/head
Joakim Almgren 7 years ago
parent
commit
b51172d573
  1. 203
      js/keyboard-shortcuts.js

203
js/keyboard-shortcuts.js

@ -1,55 +1,61 @@
// author: joakimoa // author: joakimoa
// keyboard navigation option // keyboard navigation
// v1.2 // v1.4
$(document).on("ready", function() { $(document).on("ready", function() {
// adding checkbox for turning on/off // adding keyboard navigation to options menu
if (window.Options && Options.get_tab('general')) { if (window.Options && Options.get_tab('general')) {
Options.extend_tab("general", Options.extend_tab("general",
"<fieldset><legend> Keyboard Navigation </legend>" + "<fieldset><legend> Keyboard Navigation </legend>" +
("<label class='keyboardnav' id='keyboardnav' style='padding:0px;'><input type='checkbox' /> Enable Keyboard Navigation</label>") + ("<label class='keyboardnav' id='keyboardnav' style='padding:0px;'><input type='checkbox' /> Enable Keyboard Navigation</label>") +
"<table><tr><td>Action</td><td>Key (a-z)</td></tr>" + "<table><tr><td>Action</td><td>Key (a-z)</td></tr>" +
"<tr><td>Next Reply</td><td><input class='field' name='next-reply' spellcheck='false'></td></tr>" + "<tr><td>Next Reply</td><td><input class='field' name='next-reply-input' spellcheck='false'></td></tr>" +
"<tr><td>Previous Reply</td><td><input class='field' name='previous-reply' spellcheck='false'></td></tr>" + "<tr><td>Previous Reply</td><td><input class='field' name='previous-reply-input' spellcheck='false'></td></tr>" +
"<tr><td>Expand File</td><td><input class='field' name='expando' spellcheck='false'></td></tr>" + "<tr><td>Expand File</td><td><input class='field' name='expando-input' spellcheck='false'></td></tr>" +
"<tr><td>Refresh Thread</td><td><input class='field' name='refresh-thread-input' spellcheck='false'></td></tr>" +
"</table></fieldset>"); "</table></fieldset>");
} }
$('.keyboardnav').on('change', function(){ $('.keyboardnav').on('change', function(){
var setting = $(this).attr('id'); var setting = $(this).attr('id');
localStorage[setting] = $(this).children('input').is(':checked'); localStorage[setting] = $(this).children('input').is(':checked');
}); });
var nextReplyKeycode = 74; // j
var previousReplyKeycode = 75; // k
var expandoKeycode = 69; // e
var refreshThreadKeycode = 82; // r
if (!localStorage.keyboardnav) { if (!localStorage.keyboardnav) {
localStorage.keyboardnav = 'false'; localStorage.keyboardnav = 'false';
} }
if (!localStorage["next.reply.key"]) { if (!localStorage["next.reply.key"]) {
localStorage["next.reply.key"] = 74; localStorage["next.reply.key"] = nextReplyKeycode;
} }
if (!localStorage["previous.reply.key"]) { if (!localStorage["previous.reply.key"]) {
localStorage["previous.reply.key"] = 75; localStorage["previous.reply.key"] = previousReplyKeycode;
} }
if (!localStorage["expando.key"]) { if (!localStorage["expando.key"]) {
localStorage["expando.key"] = 69; localStorage["expando.key"] = expandoKeycode;
}
if (!localStorage["refresh.thread.key"]) {
localStorage["refresh.thread.key"] = refreshThreadKeycode;
} }
// getting locally stored setting // getting locally stored setting
function getSetting(key) { function getSetting(key) {
return (localStorage[key] == 'true'); return (localStorage[key] == 'true');
} }
function isKeySet(key) { function isKeySet(key) {
return (localStorage[key] !== false); return (localStorage[key] !== false);
} }
var nextReplyInput = document.getElementsByName("next-reply")[0]; var nextReplyInput = document.getElementsByName("next-reply-input")[0];
var previousReplyInput = document.getElementsByName("previous-reply")[0]; var previousReplyInput = document.getElementsByName("previous-reply-input")[0];
var expandoInput = document.getElementsByName("expando")[0]; var expandoInput = document.getElementsByName("expando-input")[0];
var refreshThreadInput = document.getElementsByName("refresh-thread-input")[0];
var nextReplyKeycode = 74; // j
var previousReplyKeycode = 75; // k
var expandoKeycode = 69; // e
if (getSetting('keyboardnav')) $('#keyboardnav>input').prop('checked', 'checked'); if (getSetting('keyboardnav')) $('#keyboardnav>input').prop('checked', 'checked');
if (isKeySet('next.reply.key')) { if (isKeySet('next.reply.key')) {
@ -64,14 +70,20 @@ if (isKeySet('expando.key')) {
expandoKeycode = localStorage["expando.key"]; expandoKeycode = localStorage["expando.key"];
expandoInput.value = expandoKeycode; expandoInput.value = expandoKeycode;
} }
if (isKeySet('refresh.thread.key')) {
refreshThreadKeycode = localStorage["refresh.thread.key"];
refreshThreadInput.value = refreshThreadKeycode;
}
document.getElementsByName("next-reply")[0].value = String.fromCharCode(nextReplyKeycode); nextReplyInput.value = String.fromCharCode(nextReplyKeycode);
document.getElementsByName("previous-reply")[0].value = String.fromCharCode(previousReplyKeycode); previousReplyInput.value = String.fromCharCode(previousReplyKeycode);
document.getElementsByName("expando")[0].value = String.fromCharCode(expandoKeycode); expandoInput.value = String.fromCharCode(expandoKeycode);
refreshThreadInput.value = String.fromCharCode(refreshThreadKeycode);
nextReplyInput.addEventListener("keyup", changeNextReplyKey, false); nextReplyInput.addEventListener("keyup", changeNextReplyKey, false);
previousReplyInput.addEventListener("keyup", changePreviousReplyKey, false); previousReplyInput.addEventListener("keyup", changePreviousReplyKey, false);
expandoInput.addEventListener("keyup", changeExpandoKey, false); expandoInput.addEventListener("keyup", changeExpandoKey, false);
refreshThreadInput.addEventListener("keyup", changeRefreshThreadKey, false);
function changeNextReplyKey(e) { function changeNextReplyKey(e) {
nextReplyInput.value = ""; nextReplyInput.value = "";
@ -97,31 +109,88 @@ function changeExpandoKey(e) {
} }
} }
function changeRefreshThreadKey(e) {
refreshThreadInput.value = "";
if (e.keyCode >= 65 && e.keyCode <= 90) {
refreshThreadInput.value = String.fromCharCode(e.keyCode);
localStorage["refresh.thread.key"] = e.keyCode;
}
}
// loads the main function // loads the main function
function loadKeyboardNav() { function loadKeyboardNav() {
var replies = document.getElementsByClassName("post reply"); var replies = document.getElementsByClassName("post reply");
var current_file = null; var current_file = null;
var default_color = "#333";
var highlight_color = "#555"; var highlight_color = "#555";
var default_color = "black";
if (replies.length > 0) default_color = window.getComputedStyle(replies[0], null).getPropertyValue("background-color");
var reply_indexx = 0; // grabs base and highlight colors
if (replies.length > 0) {
if (replies[0].classList.contains("highlighted")) {
replies[0].classList.remove('highlighted');
default_color = window.getComputedStyle(replies[0], null).getPropertyValue("background-color");
replies[0].classList.add('highlighted');
highlight_color = window.getComputedStyle(replies[0], null).getPropertyValue("background-color");
} else {
default_color = window.getComputedStyle(replies[0], null).getPropertyValue("background-color");
replies[0].classList.add('highlighted');
highlight_color = window.getComputedStyle(replies[0], null).getPropertyValue("background-color");
replies[0].classList.remove('highlighted');
}
}
// check if user is in textareas where hotkeys needs to be disabled
var text_input_focused = false;
function checkFocused () {
var el = document.activeElement;
if (el && (el.tagName.toLowerCase() == 'input' && el.type == 'text' ||
el.tagName.toLowerCase() == 'textarea')) {
text_input_focused = true;
} else {
text_input_focused = false;
}
}
document.addEventListener('focus',function(e){
checkFocused();
}, true);
document.addEventListener('blur',function(e){
text_input_focused = false;
}, true);
// strips out <a href="" class="file"> tags
function getFileList(e) {
var arr = [];
var e = e.getElementsByClassName("file");
if (e.length > 0) {
for (i = 0; i < e.length; i++) {
if (e[i].tagName === "DIV") {
arr.push(e[i]);
}
}
}
return arr;
}
var reply_indexx = -1; // might change back to 0
var image_indexx = -1; var image_indexx = -1;
function focusNextReply() { function focusNextReply() {
if (reply_indexx < replies.length-1) { if (reply_indexx < replies.length-1) {
reply_indexx++; reply_indexx++;
image_indexx = -1; image_indexx = -1;
var images = replies[reply_indexx].getElementsByClassName("file"); var images = getFileList(replies[reply_indexx]);
if (images.length !== 0) { if (images.length !== 0) {
focusNextImage(); focusNextImage();
} else { } else {
scrollTo(replies[reply_indexx]); scrollTo(replies[reply_indexx], true);
} }
} }
} }
function focusNextImage() { function focusNextImage() {
var images = replies[reply_indexx].getElementsByClassName("file"); var images = getFileList(replies[reply_indexx]);
if (images.length === 0) { if (images.length === 0) {
focusNextReply(); focusNextReply();
} else { } else {
@ -130,7 +199,11 @@ function loadKeyboardNav() {
image_indexx = 0; image_indexx = 0;
focusNextReply(); focusNextReply();
} else { } else {
scrollTo(images[image_indexx]); var im = images[image_indexx].getElementsByClassName("full-image");
if (im.length === 0) {
im = images[image_indexx].getElementsByClassName("post-image");
}
scrollTo(im[0], true);
} }
} }
} }
@ -138,19 +211,19 @@ function loadKeyboardNav() {
function focusPreviousReply() { function focusPreviousReply() {
if (reply_indexx > 0) { if (reply_indexx > 0) {
reply_indexx--; reply_indexx--;
var images = replies[reply_indexx].getElementsByClassName("file"); var images = getFileList(replies[reply_indexx]);
image_indexx = images.length; image_indexx = images.length;
if (images.length !== 0) { if (images.length !== 0) {
focusPreviousImage(); focusPreviousImage();
} else { } else {
image_indexx = -1; image_indexx = -1;
scrollTo(replies[reply_indexx]); scrollTo(replies[reply_indexx], false);
} }
} }
} }
function focusPreviousImage() { function focusPreviousImage() {
var images = replies[reply_indexx].getElementsByClassName("file"); var images = getFileList(replies[reply_indexx]);
if (images.length === 0) { if (images.length === 0) {
focusPreviousReply(); focusPreviousReply();
} else { } else {
@ -159,17 +232,42 @@ function loadKeyboardNav() {
image_indexx = 0; image_indexx = 0;
focusPreviousReply(); focusPreviousReply();
} else { } else {
scrollTo(images[image_indexx]); var im = images[image_indexx].getElementsByClassName("full-image");
if (im.length === 0) {
im = images[image_indexx].getElementsByClassName("post-image")
}
scrollTo(im[0], false);
} }
} }
} }
function scrollTo(e) { // from https://gist.github.com/jjmu15/8646226
if (current_file !== null) { function isInViewport(element) {
var rect = element.getBoundingClientRect();
var html = document.documentElement;
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || html.clientHeight) &&
rect.right <= (window.innerWidth || html.clientWidth)
);
}
function scrollTo(e, direction_down) {
if (current_file !== null && !current_file.classList.contains("highlighted")) {
current_file.style.backgroundColor = default_color; current_file.style.backgroundColor = default_color;
} }
current_file = e; current_file = e;
e.scrollIntoView(); if (!isInViewport(e)) {
if (direction_down) {
e.scrollIntoView(false);
window.scrollBy(0, 30);
} else {
e.scrollIntoView();
window.scrollBy(0, -30);
}
}
e.style.backgroundColor = highlight_color; e.style.backgroundColor = highlight_color;
} }
@ -184,12 +282,21 @@ function loadKeyboardNav() {
window.addEventListener("keydown", checkKeyPressed, false); window.addEventListener("keydown", checkKeyPressed, false);
function checkKeyPressed(e) { function checkKeyPressed(e) {
if (e.keyCode == nextReplyKeycode) { if (!text_input_focused) {
focusNextImage(); replies = document.getElementsByClassName("post reply"); // if new ones via AJAX
} else if (e.keyCode == previousReplyKeycode) { if (e.keyCode == nextReplyKeycode) {
focusPreviousImage(); if (reply_indexx === -1) { // needed for initial condition
} else if (e.keyCode == expandoKeycode) { focusNextReply();
expandFile(); } else {
focusNextImage();
}
} else if (e.keyCode == previousReplyKeycode) {
focusPreviousImage();
} else if (e.keyCode == expandoKeycode) {
expandFile();
} else if (e.keyCode == refreshThreadKeycode) {
document.getElementById("update_thread").click();
}
} }
} }
} }
@ -199,4 +306,4 @@ if (getSetting('keyboardnav') && document.getElementsByClassName("thread").lengt
loadKeyboardNav(); loadKeyboardNav();
} }
}); });
Loading…
Cancel
Save