]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static/js/scrape-examples.js
Rollup merge of #103104 - SUPERCILEX:sep-ref, r=dtolnay
[rust.git] / src / librustdoc / html / static / js / scrape-examples.js
1 /* global addClass, hasClass, removeClass, onEachLazy */
2
3 "use strict";
4
5 (function() {
6     // Number of lines shown when code viewer is not expanded.
7     // DEFAULT is the first example shown by default, while HIDDEN is
8     // the examples hidden beneath the "More examples" toggle.
9     //
10     // NOTE: these values MUST be synchronized with certain rules in rustdoc.css!
11     const DEFAULT_MAX_LINES = 5;
12     const HIDDEN_MAX_LINES = 10;
13
14     // Scroll code block to the given code location
15     function scrollToLoc(elt, loc, isHidden) {
16         const lines = elt.querySelector(".src-line-numbers");
17         let scrollOffset;
18
19         // If the block is greater than the size of the viewer,
20         // then scroll to the top of the block. Otherwise scroll
21         // to the middle of the block.
22         const maxLines = isHidden ? HIDDEN_MAX_LINES : DEFAULT_MAX_LINES;
23         if (loc[1] - loc[0] > maxLines) {
24             const line = Math.max(0, loc[0] - 1);
25             scrollOffset = lines.children[line].offsetTop;
26         } else {
27             const wrapper = elt.querySelector(".code-wrapper");
28             const halfHeight = wrapper.offsetHeight / 2;
29             const offsetTop = lines.children[loc[0]].offsetTop;
30             const lastLine = lines.children[loc[1]];
31             const offsetBot = lastLine.offsetTop + lastLine.offsetHeight;
32             const offsetMid = (offsetTop + offsetBot) / 2;
33             scrollOffset = offsetMid - halfHeight;
34         }
35
36         lines.scrollTo(0, scrollOffset);
37         elt.querySelector(".rust").scrollTo(0, scrollOffset);
38     }
39
40     function updateScrapedExample(example, isHidden) {
41         const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
42         let locIndex = 0;
43         const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
44         const link = example.querySelector(".scraped-example-title a");
45
46         if (locs.length > 1) {
47             // Toggle through list of examples in a given file
48             const onChangeLoc = changeIndex => {
49                 removeClass(highlights[locIndex], "focus");
50                 changeIndex();
51                 scrollToLoc(example, locs[locIndex][0], isHidden);
52                 addClass(highlights[locIndex], "focus");
53
54                 const url = locs[locIndex][1];
55                 const title = locs[locIndex][2];
56
57                 link.href = url;
58                 link.innerHTML = title;
59             };
60
61             example.querySelector(".prev")
62                 .addEventListener("click", () => {
63                     onChangeLoc(() => {
64                         locIndex = (locIndex - 1 + locs.length) % locs.length;
65                     });
66                 });
67
68             example.querySelector(".next")
69                 .addEventListener("click", () => {
70                     onChangeLoc(() => {
71                         locIndex = (locIndex + 1) % locs.length;
72                     });
73                 });
74         }
75
76         const expandButton = example.querySelector(".expand");
77         if (expandButton) {
78             expandButton.addEventListener("click", () => {
79                 if (hasClass(example, "expanded")) {
80                     removeClass(example, "expanded");
81                     scrollToLoc(example, locs[0][0], isHidden);
82                 } else {
83                     addClass(example, "expanded");
84                 }
85             });
86         }
87
88         // Start with the first example in view
89         scrollToLoc(example, locs[0][0], isHidden);
90     }
91
92     const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
93     onEachLazy(firstExamples, el => updateScrapedExample(el, false));
94     onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
95         // Allow users to click the left border of the <details> section to close it,
96         // since the section can be large and finding the [+] button is annoying.
97         onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"), button => {
98             button.addEventListener("click", () => {
99                 toggle.open = false;
100             });
101         });
102
103         const moreExamples = toggle.querySelectorAll(".scraped-example");
104         toggle.querySelector("summary").addEventListener("click", () => {
105             // Wrapping in setTimeout ensures the update happens after the elements are actually
106             // visible. This is necessary since updateScrapedExample calls scrollToLoc which
107             // depends on offsetHeight, a property that requires an element to be visible to
108             // compute correctly.
109             setTimeout(() => {
110                 onEachLazy(moreExamples, el => updateScrapedExample(el, true));
111             });
112         }, {once: true});
113     });
114 })();