Hello, Christian Hahn's easy links for surf is very outdated and doesn't work anymore, so I wrote another version called keyboard buttons. It provides several improvements/features: - It adds the labels to the end of the DOM, to avoid messing with the website's code - It not only works for <a> elements, but also <button> elements - It uses letters instead of numbers 1-5 so it is easier to reach - modkey+r is a reserved combination for reloading the positions of the labels - While holding down modkey, pressing escape cancels the current input
Other than that, it works the same as easy links. It also has a few unavoidable flaws; sometimes the keyboard shortcuts used conflict with the website's, a good example of that is that on Wikipedia alt+e is used to start editing the page, but can also appear as a label. As a workaround you can disable the use of the letter 'e' when generating the labels, or you can automatically redirect to the mobile site of Wikipedia which doesn't have keyboard shortcuts. Regards, Kai
/* keyboard buttons for surf */ /* Christian hahn <ch radamanthys de> wrote the original code */ function keyboardButtons() { const modKey = "Alt"; /* used to initiate keyboardButtons mode */ const escKey = "Escape"; /* used to escape keyboardButtons mode (you can also release alt) */ const labelStyle = ` box-sizing: border-box; position: absolute; display: inline; width: auto; height: auto; margin: 0; z-index: 99999; padding: 2px; border: 1px solid black; border-radius: 0; color: black; font-size: 10px; font-weight: normal; font-family: sans-serif; font-decoration: none; text-transform: none; `; const normalColor = "yellow"; const highlightColor = "red"; var labels = {}; var input = ""; function updateLabelColor() { for (let id in labels) { if (input && id.startsWith(input)) labels[id].elem.style.backgroundColor = highlightColor; else labels[id].elem.style.backgroundColor = normalColor; } } /* by default, this function chooses some sequence of letters, change it to what you like */ function numberToLabel(n) { ++n; const alphabet = "abcdefghijklmnopqstuvwxyz"; /* r is removed as it reloads keyboardButtons */ var str = ""; for (;n; n = Math.floor(n/alphabet.length)) { str += alphabet[n%alphabet.length]; } return str; } function Label(button, text) { this.button = button; this.elem = document.createElement("span"); this.elem.innerHTML = text; this.elem.style = labelStyle; this.elem.style.visibility = "hidden"; const pos = this.button.getBoundingClientRect(); this.elem.style.left = pos.left + scrollX + "px"; this.elem.style.top = pos.top + scrollY + "px"; document.body.appendChild(this.elem); } function createLabels() { for (let id in labels) labels[id].elem.parentNode.removeChild(labels[id].elem); labels = {}; var buttons = Array.from(document.getElementsByTagName("a")) .concat(Array.from(document.getElementsByTagName("button"))); for (let i = 0; i < buttons.length; i++) { const text = numberToLabel(i); labels[text] = new Label(buttons[i], text); } updateLabelColor(); } /* main */ createLabels(); /* set key handlers */ addEventListener("keydown", function (e) { if (e.key === modKey) { input = ""; for (let id in labels) labels[id].elem.style.visibility = "visible"; updateLabelColor(); } else if (e.getModifierState(modKey)) { if (e.key === escKey || e.key === 'r') { if (e.key === 'r') createLabels(); /* reload labels */ input = ""; for (let id in labels) labels[id].elem.style.visibility = "hidden"; } else if (e.key.length === 1) { input += e.key; } updateLabelColor(); } }); addEventListener("keyup", function (e) { if (e.key === modKey) { if (labels[input] !== undefined) { labels[input].button.click(); } input = ""; for (let id in labels) labels[id].elem.style.visibility = "hidden"; } }); } if (document.readyState === "complete") keyboardButtons(); else document.addEventListener("readystatechange", function (e) { if (e.target.readyState === "complete") keyboardButtons(); });