findlink: Links combined with ctrl+f.

An idea for an extension/link format I had a while ago and just wrote up quickly today:

Lots of web pages have sections and headings you want to link to directly, but you can’t because the author didn’t give proper anchoring IDs to nearby elements. I wanted to be able to do the equivalent of click on the link, then ctrl+f for "some phrase". With findlink, you can!

Examples: http://senocular.com/flash/tutorials/versions/#find(flash lite)

Senocular’s articles are nice because he put in lots of document structure. But for smaller sections than are in the outline at the top, you can’t link directly to things like the Flash Lite section.

http://www.kirupa.com/html5/sprite_sheet_animations_using_only_css.htm#find(actual implementation)

Wow, it jumps right to the implementation!

The code is pretty simple, it’s mostly just this:

tryFindScroll()
document.addEventListener(`DOMContentLoaded`, tryFindScroll)
document.addEventListener(`load`, tryFindScroll)

function tryFindScroll(){
    if(location.hash){
        const query = parse(decodeURIComponent(location.hash.substring(1)))
        if(query){
            scrollToMatchingTextNode(query)
        }
    }
}

`
    Parses a URI fragment to find an occurrence of find(some search text)
`
function parse(fragment){
    const match = fragment.match(/find\((.*)\)/i)
    return match ? match[1] : undefined
}

`
    Takes a find query string and looks for text in the page matching it.
    If the query string is on the page, this function scrolls to the first match.
`
function scrollToMatchingTextNode(query){
    const textNodes = document.evaluate(`//text()`, document)

    for(let node of xpathIterator(textNodes)){
        if(node.wholeText.match(new RegExp(query, `i`))){
            `don't use Ranges yet because they're buggy`
            /*const range = document.createRange()
            range.selectNodeContents(node)

            const textBounds = range.getBoundingClientRect()*/
            document.body.scrollTop = /*textBounds.top*/ node.parentNode.getBoundingClientRect().top
            return true
        }
    }
    return false
}

`
    I don't think that XPathResults conform to the ES6 for..of iteration protocol,
    so this bridges the gap.
`
function* xpathIterator(xpathResult){
    let next
    while(next = xpathResult.iterateNext()) yield next
}


You can even install the extension in Chrome (once it appears in the web store in an hour or so…)

1 Like

wow, great idea! When I first started reading through the thread, I was thinking, “Hmm, I bet quite a few of my tutorials do a pretty poor job at this…” and then there’s the call out hahaha. But it wasn’t so bad. :wink:

Is there a way to capture a link from a heading you found and want to link to?

My extension doesn’t do that yet, but yeah, it’d be a good thing to add (in a context-menu-like thing). The other thing would be a little JS library that site owners could add to their page so that it’d work among people without the extension.

1 Like