Last active
March 20, 2025 16:26
-
-
Save gibson042/73dfb17bfa7d35a9fb2e4c396365c321 to your computer and use it in GitHub Desktop.
Anchors Up user script
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 Anchors Up | |
// @namespace https://github.com/gibson042 | |
// @description Navigates to in-page anchors upon {Command,Ctrl}+click or (with Shift) scrolls to arbitrary elements. | |
// @source https://gist.github.com/gibson042/73dfb17bfa7d35a9fb2e4c396365c321 | |
// @updateURL https://gist.github.com/gibson042/73dfb17bfa7d35a9fb2e4c396365c321/raw/anchors-up.user.js | |
// @downloadURL https://gist.github.com/gibson042/73dfb17bfa7d35a9fb2e4c396365c321/raw/anchors-up.user.js | |
// @version 0.5.0 | |
// @date 2023-09-08 | |
// @author Richard Gibson <@gmail.com> | |
// @include * | |
// ==/UserScript== | |
// | |
// **COPYRIGHT NOTICE** | |
// | |
// To the extent possible under law, the author(s) have dedicated all copyright | |
// and related and neighboring rights to this software to the public domain | |
// worldwide. This software is distributed without any warranty. | |
// For the CC0 Public Domain Dedication, see | |
// <https://creativecommons.org/publicdomain/zero/1.0/>. | |
// | |
// **END COPYRIGHT NOTICE** | |
// | |
// | |
// Changelog: | |
// 0.5.0 (2023-09-08) | |
// * New: CC0 Public Domain Dedication. | |
// 0.4.0 (2022-11-30) | |
// * New: Scroll to arbitrary locations with {Command,Ctrl}+Shift+click. | |
// 0.3.3 (2022-03-21) | |
// * Improved: Better OS and user script manager compatibility. | |
// 0.3.1 (2022-02-02) | |
// * Fixed: Require that Ctrl be the *only* active modifier key. | |
// 0.3.0 (2019-06-03) | |
// * Improved: Descend into single-child wrapping elements. | |
// 0.2.0 (2018-06-26) | |
// * Improved: Text node children stand in for click targets. | |
// 0.1.0 (2018-03-21) | |
// original release | |
(function() { | |
"use strict"; | |
// When traversing the DOM seeking a parent anchor, allow detours to a bounded number of previous siblings. | |
const PREV_LIMIT = 1; | |
document.addEventListener("click", function( evt ) { | |
// If Command/Control is not pressed or any other modifier key other than Shift is, abort. | |
if ( !((evt.ctrlKey ^ evt.metaKey) && !evt.altKey) ) { | |
return; | |
} | |
let anchor, | |
el = evt.target, | |
prev = 0; | |
// If Shift is pressed, scroll directly to the target. | |
if (evt.shiftKey) { | |
el.scrollIntoView(); | |
const selection = window.getSelection(); | |
selection.collapseToEnd(selection.focusNode, selection.focusOffset); | |
return; | |
} | |
// If the target has child text nodes, let the first one stand in for it. | |
if ( el.childNodes.length > el.childElementCount ) { | |
el = Array.prototype.find.call( | |
el.childNodes, | |
function(node){ return node.nodeType === document.TEXT_NODE } | |
); | |
} | |
while ( el ) { | |
// Upon finding a link ancestor, quit to allow native navigation. | |
if ( prev === 0 && el.nodeName.toLowerCase() === "a" && el.href ) { | |
return; | |
} | |
// Check for an anchor, allowing descent into single-child parents | |
// such as wrapping <p>s from Markdown rendering. | |
anchor = el.id || el.name; | |
if ( !anchor && el.childElementCount === 1 ) { | |
anchor = el.firstElementChild.id || el.firstElementChild.name; | |
} | |
// Upon finding an anchor, navigate to it and quit. | |
if ( anchor ) { | |
location.assign("#" + anchor); | |
return; | |
} | |
// Otherwise, traverse back or up. | |
el = (++prev <= PREV_LIMIT && el.previousElementSibling) || (prev = 0, el.parentNode); | |
} | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment