greenelab/deep-review

View on GitHub
build/plugins/anchors.html

Summary

Maintainability
Test Coverage
<!-- anchors plugin -->

<script>
    (function() {
        // /////////////////////////
        // DESCRIPTION
        // /////////////////////////

        // This Manubot plugin adds an anchor next to each of a certain type
        // of element that provides a human-readable url to that specific
        // item/position in the document (eg "manuscript.html#abstract"). It
        // also makes it such that scrolling out of view of a target removes
        // its identifier from the url.

        // /////////////////////////
        // OPTIONS
        // /////////////////////////

        // plugin name prefix for url parameters
        const pluginName = 'anchors';

        // default plugin options
        const options = {
            // which types of elements to add anchors next to, in
            // "document.querySelector" format
            typesQuery: 'h1, h2, h3, [id^="fig:"], [id^="tbl:"], [id^="eq:"]',
            // whether plugin is on or not
            enabled: 'true'
        };

        // change options above, or override with url parameter, eg:
        // 'manuscript.html?pluginName-enabled=false'

        // /////////////////////////
        // SCRIPT
        // /////////////////////////

        // start script
        function start() {
            // add anchor to each element of specified types
            const elements = document.querySelectorAll(options.typesQuery);
            for (const element of elements)
                addAnchor(element);

            // attach scroll listener to window
            window.addEventListener('scroll', onScroll);
        }

        // when window is scrolled
        function onScroll() {
            // if url has hash and user has scrolled out of view of hash
            // target, remove hash from url
            const tolerance = 100;
            const target = getHashTarget();
            if (target) {
                if (
                    target.getBoundingClientRect().top >
                        window.innerHeight + tolerance ||
                    target.getBoundingClientRect().bottom < 0 - tolerance
                )
                    history.pushState(null, null, ' ');
            }
        }

        // add anchor to element
        function addAnchor(element) {
            let addTo; // element to add anchor button to

            // if figure or table, modify withId and addTo to get expected
            // elements
            if (element.id.indexOf('fig:') === 0) {
                addTo = element.querySelector('figcaption');
            } else if (element.id.indexOf('tbl:') === 0) {
                addTo = element.querySelector('caption');
            } else if (element.id.indexOf('eq:') === 0) {
                addTo = element.querySelector('.eqnos-number');
            }

            addTo = addTo || element;
            const id = element.id || null;

            // do not add anchor if element doesn't have assigned id.
            // id is generated by pandoc and is assumed to be unique and
            // human-readable
            if (!id)
                return;

            // create anchor button
            const anchor = document.createElement('a');
            anchor.innerHTML = document.querySelector('.icon_link').innerHTML;
            anchor.title = 'Link to this part of the document';
            anchor.classList.add('icon_button', 'anchor');
            anchor.dataset.ignore = 'true';
            anchor.href = '#' + id;
            addTo.appendChild(anchor);
        }

        // get element that is target of link or url hash
        function getHashTarget() {
            const hash = window.location.hash;
            const id = hash.slice(1);
            let target = document.querySelector('[id="' + id + '"]');
            if (!target)
                return;

            // if figure or table, modify target to get expected element
            if (id.indexOf('fig:') === 0)
                target = target.querySelector('figure');
            if (id.indexOf('tbl:') === 0)
                target = target.querySelector('table');

            return target;
        }

        // load options from url parameters
        function loadOptions() {
            const url = window.location.search;
            const params = new URLSearchParams(url);
            for (const optionName of Object.keys(options)) {
                const paramName = pluginName + '-' + optionName;
                const param = params.get(paramName);
                if (param !== '' && param !== null)
                    options[optionName] = param;
            }
        }
        loadOptions();

        // start script when document is finished loading
        if (options.enabled === 'true')
            window.addEventListener('load', start);
    })();
</script>

<!-- link icon -->

<template class="icon_link">
    <!-- modified from: https://fontawesome.com/icons/link -->
    <svg width="16" height="16" viewBox="0 0 512 512">
        <path
            fill="currentColor"
            d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"
        ></path>
    </svg>
</template>