summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/static/js/scrape-examples.js
blob: d0fd115fd15c6d2fada74ce93e19d9f8bd34b92b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/* 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});
    });
})();