Press 1 to select block element such as paragraph, div, etc as first element
Press 2 to select block element such as paragraph, div, etc as second element
Details: Once two elements are selected, the common parent will be calculated, and mark the first element as starting point, you can repeat 1 or 2 to reset the element or re-calculate the common parent.
Shortcuts:
(j / k is the Vim default keybinding for moving cursor down/up)
Use j to navigate to the next sibling
Use k to navigate to the previous sibling
How do you feel? Hope this supports in Circle, the above "Preparation" section should not be needed when in read mode, because we can easily mark the first paragraph as the starting point.
The script is written by me, feel free to do whatever you want. The code is a mess, just gives you inspiration for what may need to improve. Currently, the code does not support navigate list items one by one.
Pros:
Don't need to move your eyes anymore, which means never lose yourself while reading
Easily skip the long image
Scroll in the middle of a line of text and scroll back a little bit manually never happens
Without using mouse to keep scrolling, and just one keystroke to go, scroll by element instead of pixels
// ==UserScript==
// @name Navigation System
// @description Navgiate page easily
// @author snowman
// @match <all_urls>
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @version 1.0
// @grant GM_addStyle
// @grant GM.getValue
// ==/UserScript==
"use strict"
function off() {
function get_page_height() {
// https://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript
let body = document.body,
html = document.documentElement
let height = Math.max(
body.scrollHeight,
body.offsetHeight,
html.clientHeight,
html.scrollHeight,
html.offsetHeight
)
return height
}
const VIEWPORT_HEIGHT = window.innerHeight
const PAGE_HEIGHT = get_page_height()
return { VIEWPORT_HEIGHT, PAGE_HEIGHT }
}
let first, second
let status
let located
let active
let scroll_to_bottom = $e => scroll_to($e, true)
let scroll_to_top = $e => scroll_to($e, false)
let getOffset = top => {
let { PAGE_HEIGHT, VIEWPORT_HEIGHT } = off()
let indicator = 0
return Math.max(0, Math.min(PAGE_HEIGHT - VIEWPORT_HEIGHT, top - indicator))
}
let scroll_to = ($e, bottom = false) => {
let height_of_element_include_margin_border = e =>
$(e).outerHeight(true) - parseInt($(e).css("marginTop"))
let offset =
$e.offset().top +
(bottom
? height_of_element_include_margin_border($e)
: -parseInt($e.css("marginTop")))
console.log(`move to offset:`, offset)
let y = getOffset(offset)
_scrollTo(y)
}
function _scrollTo(y) {
window.scrollTo({
top: y,
behavior: "smooth"
})
}
let next = () => {
let $navi_current = $(`.navi-current`)
let $navi_next = $navi_current.nextAll(":visible").slice(0, 1)
// if ($navi_current.length == 0) {
// $topics.first().addClass("navi-current")
// scroll_to_bottom($(`.navi-current`))
// }
if ($navi_next.length) {
let true_top =
$navi_current.offset().top - parseInt($navi_current.css("marginTop"))
console.log("true_top", true_top)
console.log("window.pageYOffset", window.pageYOffset)
// https://stackoverflow.com/questions/4096863/how-to-get-and-set-the-current-web-page-scroll-position
if (Math.abs(true_top - window.pageYOffset) > 48) {
console.log(`scrolling to position where current element is at top...`)
scroll_to_top($navi_current)
return
}
scroll_to_bottom($navi_current)
$navi_current.removeClass("navi-current")
$navi_next.addClass("navi-current")
}
}
let prev = () => {
let $navi_current = $(`.navi-current`)
let $navi_prev = $navi_current.prevAll(":visible").slice(0, 1)
if ($navi_prev.length) {
$navi_current.removeClass("navi-current")
$navi_prev.addClass("navi-current")
scroll_to_top($navi_prev)
}
}
;(function() {
jQuery(document).ready($ => {
document.$ = $
const internalCSS = styles =>
$(`<style type="text/css">${styles}</style>`).appendTo("head")
const styles = `
*:hover {
outline: solid 5px rgba(255, 0, 0, 0.5) !important;
}
`
// if you set class with "border-left", it will reflow text of element
// results in different height, and scroll to wrong position.
//
// and sadly, there is not style called "outline-left"
//
// so use box-shadow instead:
// https://stackoverflow.com/questions/43729480/outline-to-only-one-side-of-div
const internalStyles = `
.navi-current {
box-shadow: inset 2px 0px 0px 0px red;
background-color: let(--topic-item-hover-background-color);
}
`
internalCSS(internalStyles)
function get_common_parent_longest(e1, e2) {
return $(e1)
.parents()
.has(e2)
.first()
}
function get_direct_children_of_common_parent(e1, e2) {
e1 = $(e1)
e2 = $(e2)
let common = get_common_parent_longest(e1, e2)[0]
let chain = e1
.parents()
.add(e1)
.toArray()
for (let idx = 0; idx < chain.length; idx++) {
const element = chain[idx]
if (element == common) {
located = chain[idx + 1]
return located
}
}
}
let ctre = {
mouseover: function(e) {
if (ctre.hoveredElement != e.target) {
ctre.hoveredElement = e.target
ctre.highlightElement()
}
},
addHighlightStyle: function(elm) {
ctre.markedElement.style.setProperty(
"outline",
"solid 5px rgba(255,0,0,0.5)",
"important"
)
ctre.markedElement.style.setProperty(
"outline-offset",
"-5px",
"important"
)
},
highlightElement: function() {
if (!ctre.hoveredElement) return
if (ctre.markedElement) {
ctre.removeHighlightStyle(ctre.markedElement)
}
ctre.markedElement = ctre.hoveredElement
ctre.addHighlightStyle(ctre.markedElement)
},
removeHighlightStyle: function(elm) {
ctre.markedElement.style.outline = ""
ctre.markedElement.style.outlineOffset = ""
},
keyDown: function(e) {
if (e.keyCode == 27) {
// esc
ctre.off()
}
if (e.keyCode == 68) {
// d
ctre.init()
}
if (e.keyCode == 49) {
// 1
status = "KEY_1"
ctre.init()
}
if (e.keyCode == 50) {
// 2
status = "KEY_2"
ctre.init()
}
if (e.keyCode == 74) {
// j
next()
}
if (e.keyCode == 75) {
// k
prev()
}
},
init: function(e) {
$("body").on("mouseover", ctre.mouseover)
},
mousedown: function(e) {
if (status == "KEY_1") {
first = e.target
console.log(`set first to`, e.target)
}
if (status == "KEY_2") {
second = e.target
console.log(`set second to`, e.target)
}
if (status && first && second) {
let c = get_common_parent_longest(first, second)
console.log(`set common parent to`, c)
active = get_direct_children_of_common_parent(first, second)
console.log(`active:`, active)
$(".navi-current").removeClass("navi-current")
$(active).addClass("navi-current")
}
if (status) {
status = null
ctre.off()
e.preventDefault()
e.stopPropagation()
return false
}
},
off: function(e) {
ctre.removeHighlightStyle()
$("body").off("mouseover", ctre.mouseover)
}
}
$("body").on("keydown", ctre.keyDown)
$("body").on("click", ctre.mousedown)
})
})()
Feel free to close this feature if you think not worth it.
Usage:
Open page: https://ranhe.xyz/my-career/
Preparation:
1
to select block element such as paragraph, div, etc as first elementPress
2
to select block element such as paragraph, div, etc as second elementDetails: Once two elements are selected, the common parent will be calculated, and mark the first element as starting point, you can repeat
1
or2
to reset the element or re-calculate the common parent.Shortcuts: (
j
/k
is the Vim default keybinding for moving cursor down/up)j
to navigate to the next siblingk
to navigate to the previous siblingHow do you feel? Hope this supports in
Circle
, the above "Preparation" section should not be needed when inread mode
, because we can easily mark the first paragraph as the starting point.The script is written by me, feel free to do whatever you want. The code is a mess, just gives you inspiration for what may need to improve. Currently, the code does not support navigate list items one by one.
Pros: