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