TableOfContents

Create a table of contents for the page. ctrl+alt(command)+t to show; click an item to jump; escape or click outside to close.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         TableOfContents
// @namespace    com.gmail.fujifruity.greasemonkey
// @version      1.4
// @description  Create a table of contents for the page. ctrl+alt(command)+t to show; click an item to jump; escape or click outside to close.
// @author       fujifruity
// @match        *://*/*
// @grant        none
// ==/UserScript==

{
    const modalId = 'fujifruity-toc'
    const createModal = () => {
        const modalHTML = `
            <div id=${modalId} style="z-index:99999; width:auto; max-height:90%; position:fixed;
                padding:1em; margin:1em; border-radius: 8px; overflow-y:auto; cursor:pointer;
                box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; background-color:white" >
            </div> `
        document.body.innerHTML = modalHTML + document.body.innerHTML
        const modal = document.getElementById(modalId)
        // Add headdings to the modal
        const headdings = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6"))
        const clickableHeaddings = headdings.map((e, i) => {
            e = e.cloneNode(true)
            modal.appendChild(e)
            e.style.color = 'black'
            e.style.backgroundColor = 'white'
            e.addEventListener('click', event => headdings[i].scrollIntoView({ behavior: "smooth" }))
            return e
        })
        return modal
    }
    const getModal = () => document.getElementById(modalId) ?? createModal()
    const closeModal = () => { getModal().style.display = 'none' }
    window.addEventListener('keydown', event => {
        if (!event.altKey && !event.metaKey || !event.ctrlKey || event.key != 't') return
        // Show modal
        getModal().style.display = 'block'
        // Set shortcut to close modal
        const onKeydown = event => {
            if (event.key != 'Escape') return
            closeModal()
            window.removeEventListener('keydown', onKeydown)
        }
        const onClick = event => {
            closeModal()
            window.removeEventListener('click', onClick)
        }
        window.addEventListener('keydown', onKeydown)
        window.addEventListener('click', onClick)
    })
}