About scraped examples

/* global addClass, hasClass, removeClass, onEachLazy */

“use strict”;

(function() { // Number of lines shown when code viewer is not expanded const MAX_LINES = 10;

// Scroll code block to the given code location
function scrollToLoc(elt, loc) {
    const lines = elt.querySelector(".src-line-numbers");
    let scrollOffset;

    // If the block is greater than the size of the viewer,
    // then scroll to the top of the block. Otherwise scroll
    // to the middle of the block.
    if (loc[1] - loc[0] > MAX_LINES) {
        const line = Math.max(0, loc[0] - 1);
        scrollOffset = lines.children[line].offsetTop;
    } else {
        const wrapper = elt.querySelector(".code-wrapper");
        const halfHeight = wrapper.offsetHeight / 2;
        const offsetMid = (lines.children[loc[0]].offsetTop
                         + lines.children[loc[1]].offsetTop) / 2;
        scrollOffset = offsetMid - halfHeight;
    }

    lines.scrollTo(0, scrollOffset);
    elt.querySelector(".rust").scrollTo(0, scrollOffset);
}

function updateScrapedExample(example) {
    const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
    let locIndex = 0;
    const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
    const link = example.querySelector(".scraped-example-title a");

    if (locs.length > 1) {
        // Toggle through list of examples in a given file
        const onChangeLoc = changeIndex => {
            removeClass(highlights[locIndex], "focus");
            changeIndex();
            scrollToLoc(example, locs[locIndex][0]);
            addClass(highlights[locIndex], "focus");

            const url = locs[locIndex][1];
            const title = locs[locIndex][2];

            link.href = url;
            link.innerHTML = title;
        };

        example.querySelector(".prev")
            .addEventListener("click", () => {
                onChangeLoc(() => {
                    locIndex = (locIndex - 1 + locs.length) % locs.length;
                });
            });

        example.querySelector("next")
            .addEventListener("click", () => {
                onChangeLoc(() => {
                    locIndex = (locIndex + 1) % locs.length;
                });
            });
    }

    const expandButton = example.querySelector(".expand");
    if (expandButton) {
        expandButton.addEventListener("click", () => {
            if (hasClass(example, "expanded")) {
                removeClass(example, "expanded");
                scrollToLoc(example, locs[0][0]);
            } else {
                addClass(example, "expanded");
            }
        });
    }

    // Start with the first example in view
    scrollToLoc(example, locs[0][0]);
}

const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
onEachLazy(firstExamples, updateScrapedExample);
onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
    // Allow users to click the left border of the <details> section to close it,
    // since the section can be large and finding the [+] button is annoying.
    onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"), button => {
        button.addEventListener("click", () => {
            toggle.open = false;
        });
    });

    const moreExamples = toggle.querySelectorAll(".scraped-example");
    toggle.querySelector("summary").addEventListener("click", () => {
        // Wrapping in setTimeout ensures the update happens after the elements are actually
        // visible. This is necessary since updateScrapedExample calls scrollToLoc which
        // depends on offsetHeight, a property that requires an element to be visible to
        // compute correctly.
        setTimeout(() => {
            onEachLazy(moreExamples, updateScrapedExample);
        });
    }, {once: true});
});

})();

More information

If you want more information about this feature, please read the corresponding chapter in the Rustdoc book.