]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static/js/source-script.js
Rollup merge of #98692 - camelid:more-fixmes, r=GuillaumeGomez
[rust.git] / src / librustdoc / html / static / js / source-script.js
1 // From rust:
2 /* global sourcesIndex */
3
4 // Local js definitions:
5 /* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
6 /* global updateLocalStorage */
7
8 "use strict";
9
10 (function() {
11
12 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
13 let oldScrollPosition = 0;
14
15 function closeSidebarIfMobile() {
16     if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
17         updateLocalStorage("source-sidebar-show", "false");
18     }
19 }
20
21 function createDirEntry(elem, parent, fullPath, hasFoundFile) {
22     const dirEntry = document.createElement("details");
23     const summary = document.createElement("summary");
24
25     dirEntry.className = "dir-entry";
26
27     fullPath += elem["name"] + "/";
28
29     summary.innerText = elem["name"];
30     dirEntry.appendChild(summary);
31
32     const folders = document.createElement("div");
33     folders.className = "folders";
34     if (elem.dirs) {
35         for (const dir of elem.dirs) {
36             if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
37                 dirEntry.open = true;
38                 hasFoundFile = true;
39             }
40         }
41     }
42     dirEntry.appendChild(folders);
43
44     const files = document.createElement("div");
45     files.className = "files";
46     if (elem.files) {
47         for (const file_text of elem.files) {
48             const file = document.createElement("a");
49             file.innerText = file_text;
50             file.href = rootPath + "src/" + fullPath + file_text + ".html";
51             file.addEventListener("click", closeSidebarIfMobile);
52             const w = window.location.href.split("#")[0];
53             if (!hasFoundFile && w === file.href) {
54                 file.className = "selected";
55                 dirEntry.open = true;
56                 hasFoundFile = true;
57             }
58             files.appendChild(file);
59         }
60     }
61     dirEntry.appendChild(files);
62     parent.appendChild(dirEntry);
63     return hasFoundFile;
64 }
65
66 function toggleSidebar() {
67     const child = this.parentNode.children[0];
68     if (child.innerText === ">") {
69         if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
70             // This is to keep the scroll position on mobile.
71             oldScrollPosition = window.scrollY;
72             document.body.style.position = "fixed";
73             document.body.style.top = `-${oldScrollPosition}px`;
74         }
75         addClass(document.documentElement, "source-sidebar-expanded");
76         child.innerText = "<";
77         updateLocalStorage("source-sidebar-show", "true");
78     } else {
79         if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
80             // This is to keep the scroll position on mobile.
81             document.body.style.position = "";
82             document.body.style.top = "";
83             // The scroll position is lost when resetting the style, hence why we store it in
84             // `oldScroll`.
85             window.scrollTo(0, oldScrollPosition);
86         }
87         removeClass(document.documentElement, "source-sidebar-expanded");
88         child.innerText = ">";
89         updateLocalStorage("source-sidebar-show", "false");
90     }
91 }
92
93 function createSidebarToggle() {
94     const sidebarToggle = document.createElement("div");
95     sidebarToggle.id = "sidebar-toggle";
96
97     const inner = document.createElement("button");
98
99     if (getCurrentValue("source-sidebar-show") === "true") {
100         inner.innerText = "<";
101     } else {
102         inner.innerText = ">";
103     }
104     inner.onclick = toggleSidebar;
105
106     sidebarToggle.appendChild(inner);
107     return sidebarToggle;
108 }
109
110 // This function is called from "source-files.js", generated in `html/render/mod.rs`.
111 // eslint-disable-next-line no-unused-vars
112 function createSourceSidebar() {
113     const container = document.querySelector("nav.sidebar");
114
115     const sidebarToggle = createSidebarToggle();
116     container.insertBefore(sidebarToggle, container.firstChild);
117
118     const sidebar = document.createElement("div");
119     sidebar.id = "source-sidebar";
120
121     let hasFoundFile = false;
122
123     const title = document.createElement("div");
124     title.className = "title";
125     title.innerText = "Files";
126     sidebar.appendChild(title);
127     Object.keys(sourcesIndex).forEach(key => {
128         sourcesIndex[key].name = key;
129         hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
130             hasFoundFile);
131     });
132
133     container.appendChild(sidebar);
134     // Focus on the current file in the source files sidebar.
135     const selected_elem = sidebar.getElementsByClassName("selected")[0];
136     if (typeof selected_elem !== "undefined") {
137         selected_elem.focus();
138     }
139 }
140
141 const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
142
143 function highlightSourceLines(match) {
144     if (typeof match === "undefined") {
145         match = window.location.hash.match(lineNumbersRegex);
146     }
147     if (!match) {
148         return;
149     }
150     let from = parseInt(match[1], 10);
151     let to = from;
152     if (typeof match[2] !== "undefined") {
153         to = parseInt(match[2], 10);
154     }
155     if (to < from) {
156         const tmp = to;
157         to = from;
158         from = tmp;
159     }
160     let elem = document.getElementById(from);
161     if (!elem) {
162         return;
163     }
164     const x = document.getElementById(from);
165     if (x) {
166         x.scrollIntoView();
167     }
168     onEachLazy(document.getElementsByClassName("line-numbers"), e => {
169         onEachLazy(e.getElementsByTagName("span"), i_e => {
170             removeClass(i_e, "line-highlighted");
171         });
172     });
173     for (let i = from; i <= to; ++i) {
174         elem = document.getElementById(i);
175         if (!elem) {
176             break;
177         }
178         addClass(elem, "line-highlighted");
179     }
180 }
181
182 const handleSourceHighlight = (function() {
183     let prev_line_id = 0;
184
185     const set_fragment = name => {
186         const x = window.scrollX,
187             y = window.scrollY;
188         if (browserSupportsHistoryApi()) {
189             history.replaceState(null, null, "#" + name);
190             highlightSourceLines();
191         } else {
192             location.replace("#" + name);
193         }
194         // Prevent jumps when selecting one or many lines
195         window.scrollTo(x, y);
196     };
197
198     return ev => {
199         let cur_line_id = parseInt(ev.target.id, 10);
200         // It can happen when clicking not on a line number span.
201         if (isNaN(cur_line_id)) {
202             return;
203         }
204         ev.preventDefault();
205
206         if (ev.shiftKey && prev_line_id) {
207             // Swap selection if needed
208             if (prev_line_id > cur_line_id) {
209                 const tmp = prev_line_id;
210                 prev_line_id = cur_line_id;
211                 cur_line_id = tmp;
212             }
213
214             set_fragment(prev_line_id + "-" + cur_line_id);
215         } else {
216             prev_line_id = cur_line_id;
217
218             set_fragment(cur_line_id);
219         }
220     };
221 }());
222
223 window.addEventListener("hashchange", () => {
224     const match = window.location.hash.match(lineNumbersRegex);
225     if (match) {
226         return highlightSourceLines(match);
227     }
228 });
229
230 onEachLazy(document.getElementsByClassName("line-numbers"), el => {
231     el.addEventListener("click", handleSourceHighlight);
232 });
233
234 highlightSourceLines();
235
236 window.createSourceSidebar = createSourceSidebar;
237 })();