]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/html/static/main.js
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / librustdoc / html / static / main.js
CommitLineData
6a06907d 1// ignore-tidy-filelength
0731742a 2// Local js definitions:
5869c6ff
XL
3/* global addClass, getSettingValue, hasClass */
4/* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
29967ef6 5/* global hideThemeButtonState, showThemeButtonState */
1a4d82fc 6
a1dfa0c6
XL
7if (!String.prototype.startsWith) {
8 String.prototype.startsWith = function(searchString, position) {
9 position = position || 0;
10 return this.indexOf(searchString, position) === position;
11 };
12}
13if (!String.prototype.endsWith) {
14 String.prototype.endsWith = function(suffix, length) {
15 var l = length || this.length;
16 return this.indexOf(suffix, l - suffix.length) !== -1;
17 };
18}
19
0731742a
XL
20if (!DOMTokenList.prototype.add) {
21 DOMTokenList.prototype.add = function(className) {
22 if (className && !hasClass(this, className)) {
23 if (this.className && this.className.length > 0) {
24 this.className += " " + className;
25 } else {
26 this.className = className;
27 }
28 }
29 };
30}
31
32if (!DOMTokenList.prototype.remove) {
33 DOMTokenList.prototype.remove = function(className) {
34 if (className && this.className) {
35 this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
36 .trim();
37 }
38 };
39}
40
5869c6ff
XL
41(function () {
42 var rustdocVars = document.getElementById("rustdoc-vars");
43 if (rustdocVars) {
44 window.rootPath = rustdocVars.attributes["data-root-path"].value;
45 window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
6a06907d 46 window.searchJS = rustdocVars.attributes["data-search-js"].value;
5869c6ff
XL
47 }
48 var sidebarVars = document.getElementById("sidebar-vars");
49 if (sidebarVars) {
50 window.sidebarCurrent = {
51 name: sidebarVars.attributes["data-name"].value,
52 ty: sidebarVars.attributes["data-ty"].value,
53 relpath: sidebarVars.attributes["data-relpath"].value,
54 };
55 }
56}());
fc512014
XL
57
58// Gets the human-readable string for the virtual-key code of the
59// given KeyboardEvent, ev.
60//
61// This function is meant as a polyfill for KeyboardEvent#key,
62// since it is not supported in IE 11 or Chrome for Android. We also test for
63// KeyboardEvent#keyCode because the handleShortcut handler is
64// also registered for the keydown event, because Blink doesn't fire
65// keypress on hitting the Escape key.
66//
67// So I guess you could say things are getting pretty interoperable.
68function getVirtualKey(ev) {
69 if ("key" in ev && typeof ev.key != "undefined") {
70 return ev.key;
71 }
72
73 var c = ev.charCode || ev.keyCode;
74 if (c == 27) {
75 return "Escape";
76 }
77 return String.fromCharCode(c);
78}
79
e1599b0c
XL
80function getSearchInput() {
81 return document.getElementsByClassName("search-input")[0];
82}
83
84function getSearchElement() {
85 return document.getElementById("search");
86}
87
29967ef6
XL
88function getThemesElement() {
89 return document.getElementById("theme-choices");
90}
91
92function getThemePickerElement() {
93 return document.getElementById("theme-picker");
94}
95
5869c6ff
XL
96// Returns the current URL without any query parameter or hash.
97function getNakedUrl() {
98 return window.location.href.split("?")[0].split("#")[0];
99}
100
f9f354fc
XL
101// Sets the focus on the search bar at the top of the page
102function focusSearchBar() {
103 getSearchInput().focus();
104}
105
6a06907d 106// Removes the focus from the search bar.
f9f354fc
XL
107function defocusSearchBar() {
108 getSearchInput().blur();
109}
110
1a4d82fc
JJ
111(function() {
112 "use strict";
1a4d82fc 113
c34b1796
AL
114 // This mapping table should match the discriminants of
115 // `rustdoc::html::item_type::ItemType` type in Rust.
116 var itemTypes = ["mod",
117 "externcrate",
118 "import",
119 "struct",
120 "enum",
121 "fn",
122 "type",
123 "static",
124 "trait",
125 "impl",
126 "tymethod",
127 "method",
128 "structfield",
129 "variant",
130 "macro",
131 "primitive",
132 "associatedtype",
d9579d0f 133 "constant",
9e0c209e 134 "associatedconstant",
abe05a73 135 "union",
94b46f34 136 "foreigntype",
0bf4aa26
XL
137 "keyword",
138 "existential",
139 "attr",
9fa01778
XL
140 "derive",
141 "traitalias"];
abe05a73 142
29967ef6 143 var disableShortcuts = getSettingValue("disable-shortcuts") === "true";
e1599b0c 144 var search_input = getSearchInput();
f9f354fc 145 var searchTimeout = null;
1b1a35ee 146 var toggleAllDocsId = "toggle-all-docs";
83c7162d 147
abe05a73
XL
148 // On the search screen, so you remain on the last tab you opened.
149 //
ff7c6d11
XL
150 // 0 for "In Names"
151 // 1 for "In Parameters"
152 // 2 for "In Return Types"
abe05a73 153 var currentTab = 0;
c34b1796 154
f035d41b
XL
155 var mouseMovedAfterSearch = true;
156
b7449926 157 var titleBeforeSearch = document.title;
29967ef6 158 var searchTitle = null;
b7449926 159
f9f354fc
XL
160 function clearInputTimeout() {
161 if (searchTimeout !== null) {
162 clearTimeout(searchTimeout);
163 searchTimeout = null;
164 }
165 }
166
83c7162d 167 function getPageId() {
f035d41b
XL
168 if (window.location.hash) {
169 var tmp = window.location.hash.replace(/^#/, "");
170 if (tmp.length > 0) {
171 return tmp;
172 }
83c7162d
XL
173 }
174 return null;
175 }
176
ff7c6d11
XL
177 function showSidebar() {
178 var elems = document.getElementsByClassName("sidebar-elems")[0];
179 if (elems) {
180 addClass(elems, "show-it");
181 }
0731742a 182 var sidebar = document.getElementsByClassName("sidebar")[0];
ff7c6d11 183 if (sidebar) {
0731742a 184 addClass(sidebar, "mobile");
ff7c6d11
XL
185 var filler = document.getElementById("sidebar-filler");
186 if (!filler) {
187 var div = document.createElement("div");
188 div.id = "sidebar-filler";
189 sidebar.appendChild(div);
190 }
191 }
ff7c6d11
XL
192 }
193
194 function hideSidebar() {
195 var elems = document.getElementsByClassName("sidebar-elems")[0];
196 if (elems) {
197 removeClass(elems, "show-it");
198 }
0731742a
XL
199 var sidebar = document.getElementsByClassName("sidebar")[0];
200 removeClass(sidebar, "mobile");
ff7c6d11
XL
201 var filler = document.getElementById("sidebar-filler");
202 if (filler) {
203 filler.remove();
204 }
0731742a 205 document.getElementsByTagName("body")[0].style.marginTop = "";
ff7c6d11
XL
206 }
207
dfeec247
XL
208 function showSearchResults(search) {
209 if (search === null || typeof search === 'undefined') {
210 search = getSearchElement();
211 }
212 addClass(main, "hidden");
213 removeClass(search, "hidden");
f035d41b 214 mouseMovedAfterSearch = false;
29967ef6 215 document.title = searchTitle;
dfeec247
XL
216 }
217
218 function hideSearchResults(search) {
219 if (search === null || typeof search === 'undefined') {
220 search = getSearchElement();
221 }
222 addClass(search, "hidden");
223 removeClass(main, "hidden");
29967ef6 224 document.title = titleBeforeSearch;
6a06907d
XL
225 // We also remove the query parameter from the URL.
226 if (browserSupportsHistoryApi()) {
227 history.replaceState("", window.currentCrate + " - Rust",
228 getNakedUrl() + window.location.hash);
229 }
dfeec247
XL
230 }
231
62682a34
SL
232 // used for special search precedence
233 var TY_PRIMITIVE = itemTypes.indexOf("primitive");
94b46f34 234 var TY_KEYWORD = itemTypes.indexOf("keyword");
62682a34 235
1a4d82fc
JJ
236 function getQueryStringParams() {
237 var params = {};
238 window.location.search.substring(1).split("&").
239 map(function(s) {
240 var pair = s.split("=");
241 params[decodeURIComponent(pair[0])] =
ff7c6d11 242 typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
1a4d82fc
JJ
243 });
244 return params;
245 }
246
247 function browserSupportsHistoryApi() {
9fa01778 248 return window.history && typeof window.history.pushState === "function";
1a4d82fc
JJ
249 }
250
60c5eb7d
XL
251 function isHidden(elem) {
252 return elem.offsetHeight === 0;
253 }
254
0731742a 255 var main = document.getElementById("main");
60c5eb7d 256 var savedHash = "";
0731742a 257
60c5eb7d 258 function handleHashes(ev) {
f9f354fc 259 var elem;
e1599b0c 260 var search = getSearchElement();
60c5eb7d
XL
261 if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
262 // This block occurs when clicking on an element in the navbar while
263 // in a search.
dfeec247 264 hideSearchResults(search);
60c5eb7d
XL
265 var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
266 if (browserSupportsHistoryApi()) {
5869c6ff
XL
267 // `window.location.search`` contains all the query parameters, not just `search`.
268 history.replaceState(hash, "",
269 getNakedUrl() + window.location.search + "#" + hash);
dc9dc135 270 }
f9f354fc 271 elem = document.getElementById(hash);
60c5eb7d
XL
272 if (elem) {
273 elem.scrollIntoView();
dc9dc135 274 }
60c5eb7d
XL
275 }
276 // This part is used in case an element is not visible.
277 if (savedHash !== window.location.hash) {
278 savedHash = window.location.hash;
279 if (savedHash.length === 0) {
1a4d82fc
JJ
280 return;
281 }
f9f354fc 282 elem = document.getElementById(savedHash.slice(1)); // we remove the '#'
60c5eb7d
XL
283 if (!elem || !isHidden(elem)) {
284 return;
abe05a73 285 }
60c5eb7d
XL
286 var parent = elem.parentNode;
287 if (parent && hasClass(parent, "impl-items")) {
288 // In case this is a trait implementation item, we first need to toggle
289 // the "Show hidden undocumented items".
290 onEachLazy(parent.getElementsByClassName("collapsed"), function(e) {
291 if (e.parentNode === parent) {
292 // Only click on the toggle we're looking for.
293 e.click();
294 return true;
295 }
7cac9316 296 });
60c5eb7d
XL
297 if (isHidden(elem)) {
298 // The whole parent is collapsed. We need to click on its toggle as well!
299 if (hasClass(parent.lastElementChild, "collapse-toggle")) {
300 parent.lastElementChild.click();
301 }
dc9dc135 302 }
1a4d82fc 303 }
60c5eb7d
XL
304 }
305 }
306
307 function highlightSourceLines(match, ev) {
308 if (typeof match === "undefined") {
309 // If we're in mobile mode, we should hide the sidebar in any case.
310 hideSidebar();
311 match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
312 }
313 if (!match) {
314 return;
315 }
316 var from = parseInt(match[1], 10);
317 var to = from;
318 if (typeof match[2] !== "undefined") {
319 to = parseInt(match[2], 10);
320 }
321 if (to < from) {
322 var tmp = to;
323 to = from;
324 from = tmp;
325 }
326 var elem = document.getElementById(from);
327 if (!elem) {
328 return;
329 }
330 if (!ev) {
331 var x = document.getElementById(from);
332 if (x) {
333 x.scrollIntoView();
abe05a73 334 }
60c5eb7d
XL
335 }
336 onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
337 onEachLazy(e.getElementsByTagName("span"), function(i_e) {
338 removeClass(i_e, "line-highlighted");
339 });
340 });
341 for (var i = from; i <= to; ++i) {
342 elem = document.getElementById(i);
343 if (!elem) {
344 break;
abe05a73 345 }
60c5eb7d
XL
346 addClass(elem, "line-highlighted");
347 }
348 }
349
350 function onHashChange(ev) {
351 // If we're in mobile mode, we should hide the sidebar in any case.
352 hideSidebar();
353 var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
354 if (match) {
355 return highlightSourceLines(match, ev);
1a4d82fc 356 }
60c5eb7d 357 handleHashes(ev);
1a4d82fc 358 }
b7449926
XL
359
360 function expandSection(id) {
361 var elem = document.getElementById(id);
362 if (elem && isHidden(elem)) {
0731742a
XL
363 var h3 = elem.parentNode.previousElementSibling;
364 if (h3 && h3.tagName !== "H3") {
365 h3 = h3.previousElementSibling; // skip div.docblock
b7449926
XL
366 }
367
368 if (h3) {
369 var collapses = h3.getElementsByClassName("collapse-toggle");
370 if (collapses.length > 0) {
371 // The element is not visible, we need to make it appear!
372 collapseDocs(collapses[0], "show");
373 }
374 }
375 }
376 }
377
6a06907d
XL
378 function getHelpElement(build) {
379 if (build !== false) {
380 buildHelperPopup();
381 }
e1599b0c
XL
382 return document.getElementById("help");
383 }
384
9fa01778 385 function displayHelp(display, ev, help) {
abe05a73 386 if (display === true) {
6a06907d 387 help = help ? help : getHelpElement(true);
abe05a73
XL
388 if (hasClass(help, "hidden")) {
389 ev.preventDefault();
390 removeClass(help, "hidden");
391 addClass(document.body, "blur");
392 }
6a06907d
XL
393 } else {
394 // No need to build the help popup if we want to hide it in case it hasn't been
395 // built yet...
396 help = help ? help : getHelpElement(false);
397 if (help && hasClass(help, "hidden") === false) {
398 ev.preventDefault();
399 addClass(help, "hidden");
400 removeClass(document.body, "blur");
401 }
abe05a73
XL
402 }
403 }
404
e1599b0c 405 function handleEscape(ev) {
6a06907d 406 var help = getHelpElement(false);
e1599b0c 407 var search = getSearchElement();
0731742a 408 if (hasClass(help, "hidden") === false) {
9fa01778 409 displayHelp(false, ev, help);
0731742a 410 } else if (hasClass(search, "hidden") === false) {
f9f354fc 411 clearInputTimeout();
0531ce1d 412 ev.preventDefault();
dfeec247 413 hideSearchResults(search);
0531ce1d
XL
414 }
415 defocusSearchBar();
29967ef6 416 hideThemeButtonState();
0531ce1d 417 }
1a4d82fc 418
0531ce1d 419 function handleShortcut(ev) {
92a42be0 420 // Don't interfere with browser shortcuts
e74abb32 421 if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) {
92a42be0 422 return;
0531ce1d 423 }
92a42be0 424
0531ce1d
XL
425 if (document.activeElement.tagName === "INPUT") {
426 switch (getVirtualKey(ev)) {
427 case "Escape":
e1599b0c 428 handleEscape(ev);
0531ce1d 429 break;
9346a6ac 430 }
0531ce1d
XL
431 } else {
432 switch (getVirtualKey(ev)) {
433 case "Escape":
e1599b0c 434 handleEscape(ev);
0531ce1d 435 break;
c1a9b12d 436
0531ce1d
XL
437 case "s":
438 case "S":
e1599b0c 439 displayHelp(false, ev);
0531ce1d
XL
440 ev.preventDefault();
441 focusSearchBar();
442 break;
c1a9b12d 443
0531ce1d
XL
444 case "+":
445 case "-":
446 ev.preventDefault();
447 toggleAllDocs();
448 break;
a7813a04 449
0531ce1d 450 case "?":
3dfed10e 451 displayHelp(true, ev);
0531ce1d 452 break;
29967ef6
XL
453
454 case "t":
455 case "T":
456 displayHelp(false, ev);
457 ev.preventDefault();
458 var themePicker = getThemePickerElement();
459 themePicker.click();
460 themePicker.focus();
461 break;
462
463 default:
464 var themePicker = getThemePickerElement();
465 if (themePicker.parentNode.contains(ev.target)) {
466 handleThemeKeyDown(ev);
467 }
468 }
469 }
470 }
471
472 function handleThemeKeyDown(ev) {
473 var active = document.activeElement;
474 var themes = getThemesElement();
475 switch (getVirtualKey(ev)) {
476 case "ArrowUp":
477 ev.preventDefault();
478 if (active.previousElementSibling && ev.target.id !== "theme-picker") {
479 active.previousElementSibling.focus();
480 } else {
481 showThemeButtonState();
482 themes.lastElementChild.focus();
483 }
484 break;
485 case "ArrowDown":
486 ev.preventDefault();
487 if (active.nextElementSibling && ev.target.id !== "theme-picker") {
488 active.nextElementSibling.focus();
489 } else {
490 showThemeButtonState();
491 themes.firstElementChild.focus();
492 }
493 break;
494 case "Enter":
495 case "Return":
496 case "Space":
497 if (ev.target.id === "theme-picker" && themes.style.display === "none") {
498 ev.preventDefault();
499 showThemeButtonState();
500 themes.firstElementChild.focus();
1a4d82fc 501 }
29967ef6
XL
502 break;
503 case "Home":
504 ev.preventDefault();
505 themes.firstElementChild.focus();
506 break;
507 case "End":
508 ev.preventDefault();
509 themes.lastElementChild.focus();
510 break;
511 // The escape key is handled in handleEscape, not here,
512 // so that pressing escape will close the menu even if it isn't focused
1a4d82fc 513 }
c1a9b12d
SL
514 }
515
b7449926
XL
516 function findParentElement(elem, tagName) {
517 do {
518 if (elem && elem.tagName === tagName) {
519 return elem;
520 }
0731742a
XL
521 elem = elem.parentNode;
522 } while (elem);
b7449926
XL
523 return null;
524 }
525
dfeec247
XL
526 document.addEventListener("keypress", handleShortcut);
527 document.addEventListener("keydown", handleShortcut);
7cac9316 528
5869c6ff 529 document.addEventListener("mousemove", function() { mouseMovedAfterSearch = true; });
f035d41b 530
60c5eb7d
XL
531 var handleSourceHighlight = (function() {
532 var prev_line_id = 0;
533
534 var set_fragment = function(name) {
535 var x = window.scrollX,
536 y = window.scrollY;
537 if (browserSupportsHistoryApi()) {
538 history.replaceState(null, null, "#" + name);
539 highlightSourceLines();
540 } else {
541 location.replace("#" + name);
542 }
543 // Prevent jumps when selecting one or many lines
544 window.scrollTo(x, y);
545 };
7cac9316 546
60c5eb7d
XL
547 return function(ev) {
548 var cur_line_id = parseInt(ev.target.id, 10);
549 ev.preventDefault();
7cac9316 550
60c5eb7d
XL
551 if (ev.shiftKey && prev_line_id) {
552 // Swap selection if needed
553 if (prev_line_id > cur_line_id) {
554 var tmp = prev_line_id;
555 prev_line_id = cur_line_id;
556 cur_line_id = tmp;
7cac9316 557 }
1a4d82fc 558
60c5eb7d 559 set_fragment(prev_line_id + "-" + cur_line_id);
7cac9316 560 } else {
60c5eb7d 561 prev_line_id = cur_line_id;
1a4d82fc 562
60c5eb7d 563 set_fragment(cur_line_id);
1a4d82fc 564 }
f9f354fc
XL
565 };
566 }());
60c5eb7d 567
dfeec247 568 document.addEventListener("click", function(ev) {
6a06907d 569 var helpElem = getHelpElement(false);
3dfed10e
XL
570 if (hasClass(ev.target, "help-button")) {
571 displayHelp(true, ev);
572 } else if (hasClass(ev.target, "collapse-toggle")) {
60c5eb7d
XL
573 collapseDocs(ev.target, "toggle");
574 } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
575 collapseDocs(ev.target.parentNode, "toggle");
576 } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
577 handleSourceHighlight(ev);
6a06907d
XL
578 } else if (helpElem && hasClass(helpElem, "hidden") === false) {
579 var is_inside_help_popup = ev.target !== helpElem && helpElem.contains(ev.target);
e74abb32 580 if (is_inside_help_popup === false) {
6a06907d 581 addClass(helpElem, "hidden");
e74abb32
XL
582 removeClass(document.body, "blur");
583 }
b7449926
XL
584 } else {
585 // Making a collapsed element visible on onhashchange seems
586 // too late
0731742a 587 var a = findParentElement(ev.target, "A");
b7449926 588 if (a && a.hash) {
0731742a 589 expandSection(a.hash.replace(/^#/, ""));
b7449926 590 }
1a4d82fc 591 }
dfeec247 592 });
1a4d82fc 593
f9f354fc
XL
594 (function() {
595 var x = document.getElementsByClassName("version-selector");
596 if (x.length > 0) {
597 x[0].onchange = function() {
598 var i, match,
599 url = document.location.href,
600 stripped = "",
5869c6ff 601 len = window.rootPath.match(/\.\.\//g).length + 1;
1a4d82fc 602
f9f354fc
XL
603 for (i = 0; i < len; ++i) {
604 match = url.match(/\/[^\/]*$/);
605 if (i < len - 1) {
606 stripped = match[0] + stripped;
607 }
608 url = url.substring(0, url.length - match[0].length);
7cac9316 609 }
7cac9316 610
f9f354fc
XL
611 var selectedVersion = document.getElementsByClassName("version-selector")[0].value;
612 url += "/" + selectedVersion + stripped;
7cac9316 613
f9f354fc
XL
614 document.location.href = url;
615 };
616 }
617 }());
c1a9b12d 618
1a4d82fc
JJ
619 /**
620 * A function to compute the Levenshtein distance between two strings
621 * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
622 * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
623 * This code is an unmodified version of the code written by Marco de Wit
624 * and was found at http://stackoverflow.com/a/18514751/745719
625 */
2c00a5a8
XL
626 var levenshtein_row2 = [];
627 function levenshtein(s1, s2) {
628 if (s1 === s2) {
629 return 0;
630 }
631 var s1_len = s1.length, s2_len = s2.length;
632 if (s1_len && s2_len) {
633 var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2;
634 while (i1 < s1_len) {
635 row[i1] = ++i1;
62682a34 636 }
2c00a5a8
XL
637 while (i2 < s2_len) {
638 c2 = s2.charCodeAt(i2);
639 a = i2;
640 ++i2;
641 b = i2;
642 for (i1 = 0; i1 < s1_len; ++i1) {
643 c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
644 a = row[i1];
645 b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
646 row[i1] = b;
1a4d82fc
JJ
647 }
648 }
2c00a5a8
XL
649 return b;
650 }
651 return s1_len + s2_len;
652 }
1a4d82fc 653
f9f354fc 654 window.initSearch = function(rawSearchIndex) {
1a4d82fc 655 var MAX_LEV_DISTANCE = 3;
abe05a73 656 var MAX_RESULTS = 200;
8faf50e0
XL
657 var GENERICS_DATA = 1;
658 var NAME = 0;
659 var INPUTS_DATA = 0;
660 var OUTPUT_DATA = 1;
ba9703b0
XL
661 var NO_TYPE_FILTER = -1;
662 var currentResults, index, searchIndex;
f9f354fc 663 var ALIASES = {};
1a4d82fc
JJ
664 var params = getQueryStringParams();
665
666 // Populate search bar with query string search term when provided,
667 // but only if the input bar is empty. This avoid the obnoxious issue
668 // where you start trying to do a search, and the index loads, and
669 // suddenly your search is gone!
83c7162d 670 if (search_input.value === "") {
0731742a 671 search_input.value = params.search || "";
1a4d82fc
JJ
672 }
673
674 /**
675 * Executes the query and builds an index of results
0731742a
XL
676 * @param {[Object]} query [The user query]
677 * @param {[type]} searchWords [The list of search words to query
678 * against]
679 * @param {[type]} filterCrates [Crate to search in if defined]
680 * @return {[type]} [A search index of results]
1a4d82fc 681 */
0731742a 682 function execQuery(query, searchWords, filterCrates) {
2c00a5a8 683 function itemTypeFromName(typename) {
5869c6ff 684 for (var i = 0, len = itemTypes.length; i < len; ++i) {
2c00a5a8
XL
685 if (itemTypes[i] === typename) {
686 return i;
687 }
688 }
ba9703b0 689 return NO_TYPE_FILTER;
2c00a5a8
XL
690 }
691
1a4d82fc
JJ
692 var valLower = query.query.toLowerCase(),
693 val = valLower,
694 typeFilter = itemTypeFromName(query.type),
abe05a73 695 results = {}, results_in_args = {}, results_returned = {},
1a4d82fc
JJ
696 split = valLower.split("::");
697
5869c6ff 698 split = split.filter(function(segment) { return segment !== ""; });
abe05a73
XL
699
700 function transformResults(results, isType) {
701 var out = [];
5869c6ff 702 for (var i = 0, len = results.length; i < len; ++i) {
abe05a73
XL
703 if (results[i].id > -1) {
704 var obj = searchIndex[results[i].id];
705 obj.lev = results[i].lev;
706 if (isType !== true || obj.type) {
94b46f34
XL
707 var res = buildHrefAndPath(obj);
708 obj.displayPath = pathSplitter(res[0]);
709 obj.fullPath = obj.displayPath + obj.name;
710 // To be sure than it some items aren't considered as duplicate.
0731742a 711 obj.fullPath += "|" + obj.ty;
94b46f34 712 obj.href = res[1];
abe05a73 713 out.push(obj);
94b46f34
XL
714 if (out.length >= MAX_RESULTS) {
715 break;
716 }
abe05a73
XL
717 }
718 }
abe05a73
XL
719 }
720 return out;
721 }
722
723 function sortResults(results, isType) {
724 var ar = [];
725 for (var entry in results) {
f9f354fc 726 if (hasOwnProperty(results, entry)) {
abe05a73
XL
727 ar.push(results[entry]);
728 }
729 }
730 results = ar;
5869c6ff
XL
731 var i, len, result;
732 for (i = 0, len = results.length; i < len; ++i) {
733 result = results[i];
734 result.word = searchWords[result.id];
735 result.item = searchIndex[result.id] || {};
abe05a73
XL
736 }
737 // if there are no results then return to default and fail
738 if (results.length === 0) {
739 return [];
740 }
741
742 results.sort(function(aaa, bbb) {
743 var a, b;
744
e1599b0c
XL
745 // sort by exact match with regard to the last word (mismatch goes later)
746 a = (aaa.word !== val);
747 b = (bbb.word !== val);
748 if (a !== b) { return a - b; }
749
abe05a73
XL
750 // Sort by non levenshtein results and then levenshtein results by the distance
751 // (less changes required to match means higher rankings)
752 a = (aaa.lev);
753 b = (bbb.lev);
754 if (a !== b) { return a - b; }
755
756 // sort by crate (non-current crate goes later)
757 a = (aaa.item.crate !== window.currentCrate);
758 b = (bbb.item.crate !== window.currentCrate);
759 if (a !== b) { return a - b; }
760
abe05a73
XL
761 // sort by item name length (longer goes later)
762 a = aaa.word.length;
763 b = bbb.word.length;
764 if (a !== b) { return a - b; }
765
766 // sort by item name (lexicographically larger goes later)
767 a = aaa.word;
768 b = bbb.word;
769 if (a !== b) { return (a > b ? +1 : -1); }
770
771 // sort by index of keyword in item name (no literal occurrence goes later)
772 a = (aaa.index < 0);
773 b = (bbb.index < 0);
774 if (a !== b) { return a - b; }
775 // (later literal occurrence, if any, goes later)
776 a = aaa.index;
777 b = bbb.index;
778 if (a !== b) { return a - b; }
779
94b46f34
XL
780 // special precedence for primitive and keyword pages
781 if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
782 (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
abe05a73
XL
783 return -1;
784 }
94b46f34
XL
785 if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
786 (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
abe05a73
XL
787 return 1;
788 }
789
790 // sort by description (no description goes later)
0731742a
XL
791 a = (aaa.item.desc === "");
792 b = (bbb.item.desc === "");
abe05a73
XL
793 if (a !== b) { return a - b; }
794
795 // sort by type (later occurrence in `itemTypes` goes later)
796 a = aaa.item.ty;
797 b = bbb.item.ty;
798 if (a !== b) { return a - b; }
799
800 // sort by path (lexicographically larger goes later)
801 a = aaa.item.path;
802 b = bbb.item.path;
803 if (a !== b) { return (a > b ? +1 : -1); }
804
805 // que sera, sera
806 return 0;
807 });
808
5869c6ff 809 for (i = 0, len = results.length; i < len; ++i) {
abe05a73
XL
810 var result = results[i];
811
812 // this validation does not make sense when searching by types
813 if (result.dontValidate) {
814 continue;
815 }
816 var name = result.item.name.toLowerCase(),
817 path = result.item.path.toLowerCase(),
818 parent = result.item.parent;
819
820 if (isType !== true &&
821 validateResult(name, path, split, parent) === false)
822 {
823 result.id = -1;
824 }
825 }
826 return transformResults(results);
827 }
828
829 function extractGenerics(val) {
830 val = val.toLowerCase();
0731742a
XL
831 if (val.indexOf("<") !== -1) {
832 var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
abe05a73 833 return {
0731742a 834 name: val.substring(0, val.indexOf("<")),
abe05a73
XL
835 generics: values.split(/\s*,\s*/),
836 };
837 }
838 return {
839 name: val,
840 generics: [],
841 };
842 }
843
6a06907d 844 function getObjectNameFromId(id) {
ba9703b0 845 if (typeof id === "number") {
6a06907d 846 return searchIndex[id].name;
ba9703b0 847 }
6a06907d 848 return id;
ba9703b0
XL
849 }
850
abe05a73
XL
851 function checkGenerics(obj, val) {
852 // The names match, but we need to be sure that all generics kinda
853 // match as well.
6a06907d 854 var tmp_lev, elem_name;
abe05a73 855 if (val.generics.length > 0) {
8faf50e0
XL
856 if (obj.length > GENERICS_DATA &&
857 obj[GENERICS_DATA].length >= val.generics.length) {
6a06907d
XL
858 var elems = Object.create(null);
859 var elength = object[GENERICS_DATA].length;
860 for (var x = 0; x < elength; ++x) {
861 elems[getObjectNameFromId(obj[GENERICS_DATA][x])] += 1;
862 }
abe05a73
XL
863 var total = 0;
864 var done = 0;
865 // We need to find the type that matches the most to remove it in order
866 // to move forward.
0731742a 867 var vlength = val.generics.length;
6a06907d
XL
868 for (x = 0; x < vlength; ++x) {
869 var lev = MAX_LEV_DISTANCE + 1;
870 var firstGeneric = getObjectNameFromId(val.generics[x]);
871 var match = null;
872 if (elems[firstGeneric]) {
873 match = firstGeneric;
874 lev = 0;
875 } else {
876 for (elem_name in elems) {
877 tmp_lev = levenshtein(elem_name, firstGeneric);
878 if (tmp_lev < lev) {
879 lev = tmp_lev;
880 match = elem_name;
881 }
abe05a73
XL
882 }
883 }
6a06907d
XL
884 if (match !== null) {
885 elems[match] -= 1;
886 if (elems[match] == 0) {
887 delete elems[match];
888 }
889 total += lev;
abe05a73
XL
890 done += 1;
891 } else {
892 return MAX_LEV_DISTANCE + 1;
893 }
894 }
9fa01778 895 return Math.ceil(total / done);
abe05a73
XL
896 }
897 }
898 return MAX_LEV_DISTANCE + 1;
899 }
900
901 // Check for type name and type generics (if any).
902 function checkType(obj, val, literalSearch) {
903 var lev_distance = MAX_LEV_DISTANCE + 1;
6a06907d 904 var len, x, firstGeneric;
8faf50e0 905 if (obj[NAME] === val.name) {
abe05a73 906 if (literalSearch === true) {
2c00a5a8 907 if (val.generics && val.generics.length !== 0) {
8faf50e0
XL
908 if (obj.length > GENERICS_DATA &&
909 obj[GENERICS_DATA].length >= val.generics.length) {
6a06907d
XL
910 var elems = Object.create(null);
911 len = obj[GENERICS_DATA].length;
912 for (x = 0; x < len; ++x) {
913 elems[getObjectNameFromId(obj[GENERICS_DATA][x])] += 1;
914 }
abe05a73 915
6a06907d 916 var allFound = true;
5869c6ff 917 len = val.generics.length;
6a06907d
XL
918 for (x = 0; x < len; ++x) {
919 firstGeneric = getObjectNameFromId(val.generics[x]);
920 if (elems[firstGeneric]) {
921 elems[firstGeneric] -= 1;
922 } else {
923 allFound = false;
924 break;
abe05a73
XL
925 }
926 }
927 if (allFound === true) {
928 return true;
929 }
930 } else {
931 return false;
932 }
933 }
934 return true;
935 }
936 // If the type has generics but don't match, then it won't return at this point.
937 // Otherwise, `checkGenerics` will return 0 and it'll return.
8faf50e0 938 if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
abe05a73
XL
939 var tmp_lev = checkGenerics(obj, val);
940 if (tmp_lev <= MAX_LEV_DISTANCE) {
941 return tmp_lev;
942 }
943 } else {
944 return 0;
945 }
946 }
947 // Names didn't match so let's check if one of the generic types could.
948 if (literalSearch === true) {
8faf50e0 949 if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
5869c6ff
XL
950 return obj[GENERICS_DATA].some(
951 function(name) {
952 return name === val.name;
953 });
abe05a73
XL
954 }
955 return false;
956 }
0731742a 957 lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
abe05a73 958 if (lev_distance <= MAX_LEV_DISTANCE) {
532ac7d7
XL
959 // The generics didn't match but the name kinda did so we give it
960 // a levenshtein distance value that isn't *this* good so it goes
961 // into the search results but not too high.
962 lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
8faf50e0 963 } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
abe05a73 964 // We can check if the type we're looking for is inside the generics!
0731742a
XL
965 var olength = obj[GENERICS_DATA].length;
966 for (x = 0; x < olength; ++x) {
8faf50e0 967 lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
abe05a73
XL
968 lev_distance);
969 }
970 }
971 // Now whatever happens, the returned distance is "less good" so we should mark it
972 // as such, and so we add 1 to the distance to make it "less good".
973 return lev_distance + 1;
974 }
975
ba9703b0 976 function findArg(obj, val, literalSearch, typeFilter) {
abe05a73
XL
977 var lev_distance = MAX_LEV_DISTANCE + 1;
978
ba9703b0 979 if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
0731742a
XL
980 var length = obj.type[INPUTS_DATA].length;
981 for (var i = 0; i < length; i++) {
ba9703b0
XL
982 var tmp = obj.type[INPUTS_DATA][i];
983 if (typePassesFilter(typeFilter, tmp[1]) === false) {
984 continue;
985 }
986 tmp = checkType(tmp, val, literalSearch);
987 if (literalSearch === true) {
988 if (tmp === true) {
989 return true;
990 }
991 continue;
abe05a73
XL
992 }
993 lev_distance = Math.min(tmp, lev_distance);
994 if (lev_distance === 0) {
995 return 0;
996 }
997 }
998 }
999 return literalSearch === true ? false : lev_distance;
1000 }
1001
ba9703b0 1002 function checkReturned(obj, val, literalSearch, typeFilter) {
abe05a73
XL
1003 var lev_distance = MAX_LEV_DISTANCE + 1;
1004
8faf50e0 1005 if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
532ac7d7 1006 var ret = obj.type[OUTPUT_DATA];
ba9703b0 1007 if (typeof ret[0] === "string") {
532ac7d7 1008 ret = [ret];
abe05a73 1009 }
5869c6ff 1010 for (var x = 0, len = ret.length; x < len; ++x) {
ba9703b0
XL
1011 var tmp = ret[x];
1012 if (typePassesFilter(typeFilter, tmp[1]) === false) {
1013 continue;
532ac7d7 1014 }
ba9703b0 1015 tmp = checkType(tmp, val, literalSearch);
532ac7d7
XL
1016 if (literalSearch === true) {
1017 if (tmp === true) {
1018 return true;
1019 }
1020 continue;
1021 }
1022 lev_distance = Math.min(tmp, lev_distance);
1023 if (lev_distance === 0) {
1024 return 0;
1025 }
abe05a73
XL
1026 }
1027 }
1028 return literalSearch === true ? false : lev_distance;
1029 }
1030
b7449926
XL
1031 function checkPath(contains, lastElem, ty) {
1032 if (contains.length === 0) {
ff7c6d11
XL
1033 return 0;
1034 }
abe05a73
XL
1035 var ret_lev = MAX_LEV_DISTANCE + 1;
1036 var path = ty.path.split("::");
1037
1038 if (ty.parent && ty.parent.name) {
1039 path.push(ty.parent.name.toLowerCase());
1040 }
1041
0731742a
XL
1042 var length = path.length;
1043 var clength = contains.length;
1044 if (clength > length) {
abe05a73
XL
1045 return MAX_LEV_DISTANCE + 1;
1046 }
0731742a
XL
1047 for (var i = 0; i < length; ++i) {
1048 if (i + clength > length) {
abe05a73
XL
1049 break;
1050 }
1051 var lev_total = 0;
1052 var aborted = false;
0731742a 1053 for (var x = 0; x < clength; ++x) {
b7449926 1054 var lev = levenshtein(path[i + x], contains[x]);
abe05a73
XL
1055 if (lev > MAX_LEV_DISTANCE) {
1056 aborted = true;
1057 break;
1058 }
1059 lev_total += lev;
1060 }
1061 if (aborted === false) {
0731742a 1062 ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
abe05a73 1063 }
1a4d82fc 1064 }
abe05a73 1065 return ret_lev;
1a4d82fc
JJ
1066 }
1067
e9174d1e
SL
1068 function typePassesFilter(filter, type) {
1069 // No filter
ba9703b0 1070 if (filter <= NO_TYPE_FILTER) return true;
e9174d1e
SL
1071
1072 // Exact match
1073 if (filter === type) return true;
1074
1075 // Match related items
1076 var name = itemTypes[type];
1077 switch (itemTypes[filter]) {
1078 case "constant":
ba9703b0 1079 return name === "associatedconstant";
e9174d1e 1080 case "fn":
ba9703b0 1081 return name === "method" || name === "tymethod";
e9174d1e 1082 case "type":
ba9703b0
XL
1083 return name === "primitive" || name === "associatedtype";
1084 case "trait":
1085 return name === "traitalias";
e9174d1e
SL
1086 }
1087
1088 // No match
1089 return false;
1090 }
1091
f9f354fc
XL
1092 function createAliasFromItem(item) {
1093 return {
1094 crate: item.crate,
1095 name: item.name,
1096 path: item.path,
1097 desc: item.desc,
1098 ty: item.ty,
1099 parent: item.parent,
1100 type: item.type,
1101 is_alias: true,
1102 };
1103 }
1104
1105 function handleAliases(ret, query, filterCrates) {
1106 // We separate aliases and crate aliases because we want to have current crate
1107 // aliases to be before the others in the displayed results.
1108 var aliases = [];
1109 var crateAliases = [];
f9f354fc
XL
1110 if (filterCrates !== undefined) {
1111 if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
5869c6ff
XL
1112 var query_aliases = ALIASES[filterCrates][query.search];
1113 var len = query_aliases.length;
1114 for (var i = 0; i < len; ++i) {
1115 aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
f9f354fc
XL
1116 }
1117 }
1118 } else {
1119 Object.keys(ALIASES).forEach(function(crate) {
1120 if (ALIASES[crate][query.search]) {
1121 var pushTo = crate === window.currentCrate ? crateAliases : aliases;
5869c6ff
XL
1122 var query_aliases = ALIASES[crate][query.search];
1123 var len = query_aliases.length;
1124 for (var i = 0; i < len; ++i) {
1125 pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
f9f354fc
XL
1126 }
1127 }
1128 });
1129 }
1130
1131 var sortFunc = function(aaa, bbb) {
1132 if (aaa.path < bbb.path) {
1133 return 1;
1134 } else if (aaa.path === bbb.path) {
1135 return 0;
1136 }
1137 return -1;
1138 };
1139 crateAliases.sort(sortFunc);
1140 aliases.sort(sortFunc);
1141
1142 var pushFunc = function(alias) {
1143 alias.alias = query.raw;
1144 var res = buildHrefAndPath(alias);
1145 alias.displayPath = pathSplitter(res[0]);
1146 alias.fullPath = alias.displayPath + alias.name;
1147 alias.href = res[1];
1148
1149 ret.others.unshift(alias);
1150 if (ret.others.length > MAX_RESULTS) {
1151 ret.others.pop();
1152 }
1153 };
1154 onEach(aliases, pushFunc);
1155 onEach(crateAliases, pushFunc);
1156 }
1157
1a4d82fc
JJ
1158 // quoted values mean literal search
1159 var nSearchWords = searchWords.length;
5869c6ff 1160 var i, it;
0731742a
XL
1161 var ty;
1162 var fullId;
1163 var returned;
1164 var in_args;
5869c6ff 1165 var len;
1a4d82fc
JJ
1166 if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
1167 val.charAt(val.length - 1) === val.charAt(0))
1168 {
abe05a73 1169 val = extractGenerics(val.substr(1, val.length - 2));
0731742a
XL
1170 for (i = 0; i < nSearchWords; ++i) {
1171 if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1172 continue;
1173 }
ba9703b0
XL
1174 in_args = findArg(searchIndex[i], val, true, typeFilter);
1175 returned = checkReturned(searchIndex[i], val, true, typeFilter);
0731742a 1176 ty = searchIndex[i];
6a06907d 1177 fullId = ty.id;
abe05a73 1178
ba9703b0
XL
1179 if (searchWords[i] === val.name
1180 && typePassesFilter(typeFilter, searchIndex[i].ty)
1181 && results[fullId] === undefined) {
1182 results[fullId] = {
1183 id: i,
1184 index: -1,
1185 dontValidate: true,
1186 };
1187 }
1188 if (in_args === true && results_in_args[fullId] === undefined) {
1189 results_in_args[fullId] = {
1190 id: i,
1191 index: -1,
1192 dontValidate: true,
1193 };
1194 }
1195 if (returned === true && results_returned[fullId] === undefined) {
1196 results_returned[fullId] = {
1197 id: i,
1198 index: -1,
1199 dontValidate: true,
1200 };
1a4d82fc
JJ
1201 }
1202 }
abe05a73
XL
1203 query.inputs = [val];
1204 query.output = val;
1205 query.search = val;
c34b1796
AL
1206 // searching by type
1207 } else if (val.search("->") > -1) {
83c7162d 1208 var trimmer = function(s) { return s.trim(); };
c34b1796
AL
1209 var parts = val.split("->").map(trimmer);
1210 var input = parts[0];
1211 // sort inputs so that order does not matter
abe05a73 1212 var inputs = input.split(",").map(trimmer).sort();
5869c6ff 1213 for (i = 0, len = inputs.length; i < len; ++i) {
abe05a73
XL
1214 inputs[i] = extractGenerics(inputs[i]);
1215 }
1216 var output = extractGenerics(parts[1]);
c34b1796 1217
0731742a
XL
1218 for (i = 0; i < nSearchWords; ++i) {
1219 if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1220 continue;
1221 }
c34b1796 1222 var type = searchIndex[i].type;
0731742a 1223 ty = searchIndex[i];
c34b1796
AL
1224 if (!type) {
1225 continue;
1226 }
6a06907d 1227 fullId = ty.id;
c34b1796 1228
ba9703b0 1229 returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
abe05a73 1230 if (output.name === "*" || returned === true) {
0731742a 1231 in_args = false;
48663c56 1232 var is_module = false;
abe05a73
XL
1233
1234 if (input === "*") {
48663c56 1235 is_module = true;
abe05a73
XL
1236 } else {
1237 var allFound = true;
5869c6ff 1238 for (it = 0, len = inputs.length; allFound === true && it < len; it++) {
abe05a73 1239 allFound = checkType(type, inputs[it], true);
1a4d82fc 1240 }
abe05a73 1241 in_args = allFound;
1a4d82fc 1242 }
abe05a73
XL
1243 if (in_args === true) {
1244 results_in_args[fullId] = {
1245 id: i,
1246 index: -1,
1247 dontValidate: true,
1248 };
1249 }
1250 if (returned === true) {
1251 results_returned[fullId] = {
1252 id: i,
1253 index: -1,
1254 dontValidate: true,
1255 };
1256 }
48663c56 1257 if (is_module === true) {
abe05a73
XL
1258 results[fullId] = {
1259 id: i,
1260 index: -1,
1261 dontValidate: true,
1262 };
1a4d82fc
JJ
1263 }
1264 }
1265 }
abe05a73
XL
1266 query.inputs = inputs.map(function(input) {
1267 return input.name;
1268 });
1269 query.output = output.name;
1270 } else {
1271 query.inputs = [val];
1272 query.output = val;
1273 query.search = val;
1274 // gather matching search results up to a certain maximum
1275 val = val.replace(/\_/g, "");
1a4d82fc 1276
abe05a73 1277 var valGenerics = extractGenerics(val);
1a4d82fc 1278
abe05a73
XL
1279 var paths = valLower.split("::");
1280 var j;
5869c6ff 1281 for (j = 0, len = paths.length; j < len; ++j) {
abe05a73
XL
1282 if (paths[j] === "") {
1283 paths.splice(j, 1);
1284 j -= 1;
1285 }
b039eaaf 1286 }
abe05a73 1287 val = paths[paths.length - 1];
b7449926 1288 var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
1a4d82fc 1289
60c5eb7d 1290 var lev;
abe05a73 1291 for (j = 0; j < nSearchWords; ++j) {
0731742a
XL
1292 ty = searchIndex[j];
1293 if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
abe05a73
XL
1294 continue;
1295 }
1296 var lev_add = 0;
1297 if (paths.length > 1) {
0731742a 1298 lev = checkPath(contains, paths[paths.length - 1], ty);
abe05a73
XL
1299 if (lev > MAX_LEV_DISTANCE) {
1300 continue;
1301 } else if (lev > 0) {
e1599b0c 1302 lev_add = lev / 10;
abe05a73
XL
1303 }
1304 }
1a4d82fc 1305
0731742a
XL
1306 returned = MAX_LEV_DISTANCE + 1;
1307 in_args = MAX_LEV_DISTANCE + 1;
abe05a73
XL
1308 var index = -1;
1309 // we want lev results to go lower than others
0731742a 1310 lev = MAX_LEV_DISTANCE + 1;
6a06907d 1311 fullId = ty.id;
abe05a73
XL
1312
1313 if (searchWords[j].indexOf(split[i]) > -1 ||
1314 searchWords[j].indexOf(val) > -1 ||
6a06907d 1315 ty.normalizedName.indexOf(val) > -1)
abe05a73
XL
1316 {
1317 // filter type: ... queries
1318 if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
6a06907d 1319 index = ty.normalizedName.indexOf(val);
abe05a73
XL
1320 }
1321 }
1322 if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
1323 if (typePassesFilter(typeFilter, ty.ty) === false) {
1324 lev = MAX_LEV_DISTANCE + 1;
1325 } else {
1326 lev += 1;
1327 }
1328 }
ba9703b0
XL
1329 in_args = findArg(ty, valGenerics, false, typeFilter);
1330 returned = checkReturned(ty, valGenerics, false, typeFilter);
1a4d82fc 1331
abe05a73 1332 lev += lev_add;
b7449926 1333 if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
ff7c6d11
XL
1334 if (val.length < 6) {
1335 lev -= 1;
1336 } else {
1337 lev = 0;
1338 }
1339 }
abe05a73
XL
1340 if (in_args <= MAX_LEV_DISTANCE) {
1341 if (results_in_args[fullId] === undefined) {
1342 results_in_args[fullId] = {
1343 id: j,
1344 index: index,
1345 lev: in_args,
1346 };
1347 }
1348 results_in_args[fullId].lev =
1349 Math.min(results_in_args[fullId].lev, in_args);
1350 }
1351 if (returned <= MAX_LEV_DISTANCE) {
1352 if (results_returned[fullId] === undefined) {
1353 results_returned[fullId] = {
1354 id: j,
1355 index: index,
1356 lev: returned,
1357 };
1358 }
1359 results_returned[fullId].lev =
1360 Math.min(results_returned[fullId].lev, returned);
1361 }
1362 if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
94b46f34 1363 if (index !== -1 && paths.length < 2) {
abe05a73
XL
1364 lev = 0;
1365 }
1366 if (results[fullId] === undefined) {
1367 results[fullId] = {
1368 id: j,
1369 index: index,
1370 lev: lev,
1371 };
1372 }
1373 results[fullId].lev = Math.min(results[fullId].lev, lev);
1374 }
1a4d82fc
JJ
1375 }
1376 }
c34b1796 1377
83c7162d 1378 var ret = {
0731742a
XL
1379 "in_args": sortResults(results_in_args, true),
1380 "returned": sortResults(results_returned, true),
1381 "others": sortResults(results),
abe05a73 1382 };
f9f354fc 1383 handleAliases(ret, query, filterCrates);
83c7162d 1384 return ret;
1a4d82fc
JJ
1385 }
1386
1387 /**
1388 * Validate performs the following boolean logic. For example:
1389 * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
1390 * exists in (name || path || parent) OR => ("file" && "open") exists in
1391 * (name || path )
1392 *
1393 * This could be written functionally, but I wanted to minimise
1394 * functions on stack.
1395 *
1396 * @param {[string]} name [The name of the result]
1397 * @param {[string]} path [The path of the result]
1398 * @param {[string]} keys [The keys to be used (["file", "open"])]
1399 * @param {[object]} parent [The parent of the result]
1400 * @return {[boolean]} [Whether the result is valid or not]
1401 */
1402 function validateResult(name, path, keys, parent) {
5869c6ff 1403 for (var i = 0, len = keys.length; i < len; ++i) {
1a4d82fc
JJ
1404 // each check is for validation so we negate the conditions and invalidate
1405 if (!(
1406 // check for an exact name match
abe05a73 1407 name.indexOf(keys[i]) > -1 ||
1a4d82fc 1408 // then an exact path match
abe05a73 1409 path.indexOf(keys[i]) > -1 ||
1a4d82fc 1410 // next if there is a parent, check for exact parent match
60c5eb7d 1411 (parent !== undefined && parent.name !== undefined &&
1a4d82fc
JJ
1412 parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
1413 // lastly check to see if the name was a levenshtein match
abe05a73 1414 levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
1a4d82fc
JJ
1415 return false;
1416 }
1417 }
1418 return true;
1419 }
1420
2c00a5a8
XL
1421 function getQuery(raw) {
1422 var matches, type, query;
1a4d82fc
JJ
1423 query = raw;
1424
e9174d1e 1425 matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1a4d82fc 1426 if (matches) {
0731742a 1427 type = matches[1].replace(/^const$/, "constant");
1a4d82fc
JJ
1428 query = query.substring(matches[0].length);
1429 }
1430
1431 return {
1432 raw: raw,
1433 query: query,
1434 type: type,
62682a34 1435 id: query + type
1a4d82fc
JJ
1436 };
1437 }
1438
1439 function initSearchNav() {
7cac9316 1440 var hoverTimeout;
1a4d82fc 1441
7cac9316
XL
1442 var click_func = function(e) {
1443 var el = e.target;
1444 // to retrieve the real "owner" of the event.
0731742a 1445 while (el.tagName !== "TR") {
7cac9316
XL
1446 el = el.parentNode;
1447 }
0731742a 1448 var dst = e.target.getElementsByTagName("a");
7cac9316
XL
1449 if (dst.length < 1) {
1450 return;
1451 }
1452 dst = dst[0];
62682a34 1453 if (window.location.pathname === dst.pathname) {
dfeec247 1454 hideSearchResults();
1a4d82fc
JJ
1455 document.location.href = dst.href;
1456 }
7cac9316
XL
1457 };
1458 var mouseover_func = function(e) {
f035d41b
XL
1459 if (mouseMovedAfterSearch) {
1460 var el = e.target;
1461 // to retrieve the real "owner" of the event.
1462 while (el.tagName !== "TR") {
1463 el = el.parentNode;
1464 }
1465 clearTimeout(hoverTimeout);
1466 hoverTimeout = setTimeout(function() {
1467 onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1468 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1469 removeClass(i_e, "highlighted");
1470 });
7cac9316 1471 });
f035d41b
XL
1472 addClass(el, "highlighted");
1473 }, 20);
1474 }
7cac9316 1475 };
0731742a
XL
1476 onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1477 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
7cac9316
XL
1478 i_e.onclick = click_func;
1479 i_e.onmouseover = mouseover_func;
1480 });
1a4d82fc
JJ
1481 });
1482
7cac9316 1483 search_input.onkeydown = function(e) {
abe05a73
XL
1484 // "actives" references the currently highlighted item in each search tab.
1485 // Each array in "actives" represents a tab.
1486 var actives = [[], [], []];
1487 // "current" is used to know which tab we're looking into.
1488 var current = 0;
9fa01778 1489 onEachLazy(document.getElementById("results").childNodes, function(e) {
1b1a35ee
XL
1490 onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) {
1491 actives[current].push(h_e);
7cac9316 1492 });
abe05a73 1493 current += 1;
7cac9316 1494 });
1a4d82fc
JJ
1495
1496 if (e.which === 38) { // up
fc512014
XL
1497 if (e.ctrlKey) { // Going through result tabs.
1498 printTab(currentTab > 0 ? currentTab - 1 : 2);
1499 } else {
1500 if (!actives[currentTab].length ||
1501 !actives[currentTab][0].previousElementSibling) {
1502 return;
1503 }
1504 addClass(actives[currentTab][0].previousElementSibling, "highlighted");
1505 removeClass(actives[currentTab][0], "highlighted");
1a4d82fc 1506 }
f035d41b 1507 e.preventDefault();
1a4d82fc 1508 } else if (e.which === 40) { // down
fc512014
XL
1509 if (e.ctrlKey) { // Going through result tabs.
1510 printTab(currentTab > 1 ? 0 : currentTab + 1);
1511 } else if (!actives[currentTab].length) {
9fa01778 1512 var results = document.getElementById("results").childNodes;
7cac9316 1513 if (results.length > 0) {
0731742a 1514 var res = results[currentTab].getElementsByClassName("result");
7cac9316 1515 if (res.length > 0) {
0731742a 1516 addClass(res[0], "highlighted");
7cac9316
XL
1517 }
1518 }
abe05a73 1519 } else if (actives[currentTab][0].nextElementSibling) {
0731742a
XL
1520 addClass(actives[currentTab][0].nextElementSibling, "highlighted");
1521 removeClass(actives[currentTab][0], "highlighted");
1a4d82fc 1522 }
f035d41b 1523 e.preventDefault();
1a4d82fc 1524 } else if (e.which === 13) { // return
abe05a73
XL
1525 if (actives[currentTab].length) {
1526 document.location.href =
0731742a 1527 actives[currentTab][0].getElementsByTagName("a")[0].href;
abe05a73 1528 }
abe05a73
XL
1529 } else if (e.which === 16) { // shift
1530 // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1531 } else if (actives[currentTab].length > 0) {
0731742a 1532 removeClass(actives[currentTab][0], "highlighted");
1a4d82fc 1533 }
7cac9316 1534 };
1a4d82fc
JJ
1535 }
1536
83c7162d
XL
1537 function buildHrefAndPath(item) {
1538 var displayPath;
1539 var href;
1540 var type = itemTypes[item.ty];
1541 var name = item.name;
74b04a01 1542 var path = item.path;
83c7162d 1543
0731742a 1544 if (type === "mod") {
74b04a01 1545 displayPath = path + "::";
5869c6ff 1546 href = window.rootPath + path.replace(/::/g, "/") + "/" +
0731742a 1547 name + "/index.html";
94b46f34 1548 } else if (type === "primitive" || type === "keyword") {
83c7162d 1549 displayPath = "";
5869c6ff 1550 href = window.rootPath + path.replace(/::/g, "/") +
0731742a 1551 "/" + type + "." + name + ".html";
83c7162d
XL
1552 } else if (type === "externcrate") {
1553 displayPath = "";
5869c6ff 1554 href = window.rootPath + name + "/index.html";
83c7162d
XL
1555 } else if (item.parent !== undefined) {
1556 var myparent = item.parent;
0731742a 1557 var anchor = "#" + type + "." + name;
83c7162d 1558 var parentType = itemTypes[myparent.ty];
74b04a01
XL
1559 var pageType = parentType;
1560 var pageName = myparent.name;
1561
83c7162d 1562 if (parentType === "primitive") {
0731742a 1563 displayPath = myparent.name + "::";
74b04a01
XL
1564 } else if (type === "structfield" && parentType === "variant") {
1565 // Structfields belonging to variants are special: the
1566 // final path element is the enum name.
6a06907d
XL
1567 var enumNameIdx = item.path.lastIndexOf("::");
1568 var enumName = item.path.substr(enumNameIdx + 2);
1569 path = item.path.substr(0, enumNameIdx);
74b04a01
XL
1570 displayPath = path + "::" + enumName + "::" + myparent.name + "::";
1571 anchor = "#variant." + myparent.name + ".field." + name;
1572 pageType = "enum";
1573 pageName = enumName;
83c7162d 1574 } else {
74b04a01 1575 displayPath = path + "::" + myparent.name + "::";
83c7162d 1576 }
5869c6ff 1577 href = window.rootPath + path.replace(/::/g, "/") +
74b04a01
XL
1578 "/" + pageType +
1579 "." + pageName +
0731742a 1580 ".html" + anchor;
83c7162d 1581 } else {
0731742a 1582 displayPath = item.path + "::";
5869c6ff 1583 href = window.rootPath + item.path.replace(/::/g, "/") +
0731742a 1584 "/" + type + "." + name + ".html";
83c7162d
XL
1585 }
1586 return [displayPath, href];
1587 }
1588
94b46f34 1589 function escape(content) {
0731742a 1590 var h1 = document.createElement("h1");
94b46f34
XL
1591 h1.textContent = content;
1592 return h1.innerHTML;
1593 }
1594
1595 function pathSplitter(path) {
0731742a 1596 var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
94b46f34
XL
1597 if (tmp.endsWith("<span>")) {
1598 return tmp.slice(0, tmp.length - 6);
1599 }
1600 return tmp;
1601 }
1602
abe05a73 1603 function addTab(array, query, display) {
0731742a 1604 var extraStyle = "";
abe05a73 1605 if (display === false) {
0731742a 1606 extraStyle = " style=\"display: none;\"";
abe05a73 1607 }
1a4d82fc 1608
0731742a 1609 var output = "";
94b46f34
XL
1610 var duplicates = {};
1611 var length = 0;
abe05a73 1612 if (array.length > 0) {
0731742a 1613 output = "<table class=\"search-results\"" + extraStyle + ">";
1a4d82fc 1614
abe05a73 1615 array.forEach(function(item) {
94b46f34 1616 var name, type;
1a4d82fc 1617
1a4d82fc
JJ
1618 name = item.name;
1619 type = itemTypes[item.ty];
1620
94b46f34
XL
1621 if (item.is_alias !== true) {
1622 if (duplicates[item.fullPath]) {
1623 return;
1624 }
1625 duplicates[item.fullPath] = true;
1626 }
1627 length += 1;
1a4d82fc 1628
0731742a
XL
1629 output += "<tr class=\"" + type + " result\"><td>" +
1630 "<a href=\"" + item.href + "\">" +
94b46f34 1631 (item.is_alias === true ?
0731742a
XL
1632 ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
1633 "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
1634 item.displayPath + "<span class=\"" + type + "\">" +
1635 name + "</span></a></td><td>" +
1636 "<a href=\"" + item.href + "\">" +
fc512014 1637 "<span class=\"desc\">" + item.desc +
0731742a 1638 "&nbsp;</span></a></td></tr>";
1a4d82fc 1639 });
0731742a 1640 output += "</table>";
1a4d82fc 1641 } else {
0731742a
XL
1642 output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
1643 "Try on <a href=\"https://duckduckgo.com/?q=" +
1644 encodeURIComponent("rust " + query.query) +
1645 "\">DuckDuckGo</a>?<br/><br/>" +
1646 "Or try looking in one of these:<ul><li>The <a " +
1647 "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
1648 " for technical details about the language.</li><li><a " +
1649 "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
1650 "Example</a> for expository code examples.</a></li><li>The <a " +
1651 "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
1652 "introductions to language features and the language itself.</li><li><a " +
1653 "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
1654 " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
1a4d82fc 1655 }
94b46f34 1656 return [output, length];
abe05a73
XL
1657 }
1658
1659 function makeTabHeader(tabNb, text, nbElems) {
1660 if (currentTab === tabNb) {
fc512014
XL
1661 return "<button class=\"selected\">" + text +
1662 " <div class=\"count\">(" + nbElems + ")</div></button>";
abe05a73 1663 }
fc512014 1664 return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
abe05a73
XL
1665 }
1666
1667 function showResults(results) {
1b1a35ee
XL
1668 var search = getSearchElement();
1669 if (results.others.length === 1
29967ef6 1670 && getSettingValue("go-to-only-result") === "true"
1b1a35ee
XL
1671 // By default, the search DOM element is "empty" (meaning it has no children not
1672 // text content). Once a search has been run, it won't be empty, even if you press
1673 // ESC or empty the search input (which also "cancels" the search).
1674 && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText()))
1675 {
0731742a
XL
1676 var elem = document.createElement("a");
1677 elem.href = results.others[0].href;
1678 elem.style.display = "none";
83c7162d
XL
1679 // For firefox, we need the element to be in the DOM so it can be clicked.
1680 document.body.appendChild(elem);
1681 elem.click();
1b1a35ee 1682 return;
83c7162d 1683 }
94b46f34 1684 var query = getQuery(search_input.value);
abe05a73
XL
1685
1686 currentResults = query.id;
94b46f34 1687
0731742a
XL
1688 var ret_others = addTab(results.others, query);
1689 var ret_in_args = addTab(results.in_args, query, false);
1690 var ret_returned = addTab(results.returned, query, false);
94b46f34 1691
5869c6ff
XL
1692 // Navigate to the relevant tab if the current tab is empty, like in case users search
1693 // for "-> String". If they had selected another tab previously, they have to click on
1694 // it again.
1695 if ((currentTab === 0 && ret_others[1] === 0) ||
1696 (currentTab === 1 && ret_in_args[1] === 0) ||
1697 (currentTab === 2 && ret_returned[1] === 0)) {
1698 if (ret_others[1] !== 0) {
1699 currentTab = 0;
1700 } else if (ret_in_args[1] !== 0) {
1701 currentTab = 1;
1702 } else if (ret_returned[1] !== 0) {
1703 currentTab = 2;
1704 }
1705 }
1706
0731742a
XL
1707 var output = "<h1>Results for " + escape(query.query) +
1708 (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
1709 "<div id=\"titles\">" +
94b46f34
XL
1710 makeTabHeader(0, "In Names", ret_others[1]) +
1711 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
1712 makeTabHeader(2, "In Return Types", ret_returned[1]) +
0731742a
XL
1713 "</div><div id=\"results\">" +
1714 ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
1a4d82fc 1715
7cac9316 1716 search.innerHTML = output;
dfeec247 1717 showSearchResults(search);
1a4d82fc 1718 initSearchNav();
0731742a 1719 var elems = document.getElementById("titles").childNodes;
abe05a73
XL
1720 elems[0].onclick = function() { printTab(0); };
1721 elems[1].onclick = function() { printTab(1); };
1722 elems[2].onclick = function() { printTab(2); };
1723 printTab(currentTab);
1a4d82fc
JJ
1724 }
1725
0731742a
XL
1726 function execSearch(query, searchWords, filterCrates) {
1727 function getSmallest(arrays, positions, notDuplicates) {
1728 var start = null;
83c7162d 1729
5869c6ff 1730 for (var it = 0, len = positions.length; it < len; ++it) {
0731742a
XL
1731 if (arrays[it].length > positions[it] &&
1732 (start === null || start > arrays[it][positions[it]].lev) &&
1733 !notDuplicates[arrays[it][positions[it]].fullPath]) {
1734 start = arrays[it][positions[it]].lev;
83c7162d 1735 }
83c7162d 1736 }
0731742a
XL
1737 return start;
1738 }
83c7162d 1739
0731742a
XL
1740 function mergeArrays(arrays) {
1741 var ret = [];
1742 var positions = [];
1743 var notDuplicates = {};
83c7162d 1744
5869c6ff 1745 for (var x = 0, arrays_len = arrays.length; x < arrays_len; ++x) {
0731742a
XL
1746 positions.push(0);
1747 }
1748 while (ret.length < MAX_RESULTS) {
1749 var smallest = getSmallest(arrays, positions, notDuplicates);
94b46f34 1750
0731742a
XL
1751 if (smallest === null) {
1752 break;
1753 }
5869c6ff 1754 for (x = 0; x < arrays_len && ret.length < MAX_RESULTS; ++x) {
0731742a
XL
1755 if (arrays[x].length > positions[x] &&
1756 arrays[x][positions[x]].lev === smallest &&
1757 !notDuplicates[arrays[x][positions[x]].fullPath]) {
1758 ret.push(arrays[x][positions[x]]);
1759 notDuplicates[arrays[x][positions[x]].fullPath] = true;
1760 positions[x] += 1;
83c7162d
XL
1761 }
1762 }
83c7162d 1763 }
0731742a
XL
1764 return ret;
1765 }
1766
1767 var queries = query.raw.split(",");
1768 var results = {
1769 "in_args": [],
1770 "returned": [],
1771 "others": [],
1772 };
1773
5869c6ff 1774 for (var i = 0, len = queries.length; i < len; ++i) {
0731742a
XL
1775 query = queries[i].trim();
1776 if (query.length !== 0) {
1777 var tmp = execQuery(getQuery(query), searchWords, filterCrates);
83c7162d 1778
0731742a
XL
1779 results.in_args.push(tmp.in_args);
1780 results.returned.push(tmp.returned);
1781 results.others.push(tmp.others);
1782 }
1783 }
1784 if (queries.length > 1) {
83c7162d 1785 return {
0731742a
XL
1786 "in_args": mergeArrays(results.in_args),
1787 "returned": mergeArrays(results.returned),
1788 "others": mergeArrays(results.others),
83c7162d 1789 };
83c7162d 1790 }
f9f354fc
XL
1791 return {
1792 "in_args": results.in_args[0],
1793 "returned": results.returned[0],
1794 "others": results.others[0],
1795 };
83c7162d
XL
1796 }
1797
0731742a
XL
1798 function getFilterCrates() {
1799 var elem = document.getElementById("crate-search");
1800
f9f354fc 1801 if (elem && elem.value !== "All crates" && hasOwnProperty(rawSearchIndex, elem.value)) {
0731742a
XL
1802 return elem.value;
1803 }
1804 return undefined;
1805 }
1806
1807 function search(e, forced) {
1a4d82fc 1808 var params = getQueryStringParams();
83c7162d 1809 var query = getQuery(search_input.value.trim());
1a4d82fc 1810
1a4d82fc
JJ
1811 if (e) {
1812 e.preventDefault();
1813 }
1814
0731742a
XL
1815 if (query.query.length === 0) {
1816 return;
1817 }
1818 if (forced !== true && query.id === currentResults) {
83c7162d
XL
1819 if (query.query.length > 0) {
1820 putBackSearch(search_input);
1821 }
1a4d82fc
JJ
1822 return;
1823 }
1824
62682a34 1825 // Update document title to maintain a meaningful browser history
29967ef6 1826 searchTitle = "Results for " + query.query + " - Rust";
62682a34 1827
1a4d82fc
JJ
1828 // Because searching is incremental by character, only the most
1829 // recent search query is added to the browser history.
1830 if (browserSupportsHistoryApi()) {
5869c6ff
XL
1831 var newURL = getNakedUrl() + "?search=" + encodeURIComponent(query.raw) +
1832 window.location.hash;
1a4d82fc 1833 if (!history.state && !params.search) {
5869c6ff 1834 history.pushState(query, "", newURL);
1a4d82fc 1835 } else {
5869c6ff 1836 history.replaceState(query, "", newURL);
1a4d82fc
JJ
1837 }
1838 }
1839
0731742a 1840 var filterCrates = getFilterCrates();
60c5eb7d 1841 showResults(execSearch(query, index, filterCrates));
1a4d82fc
JJ
1842 }
1843
1a4d82fc
JJ
1844 function buildIndex(rawSearchIndex) {
1845 searchIndex = [];
1846 var searchWords = [];
6a06907d 1847 var i, word;
f9f354fc 1848 var currentIndex = 0;
6a06907d 1849 var id = 0;
0731742a 1850
1a4d82fc 1851 for (var crate in rawSearchIndex) {
f9f354fc
XL
1852 if (!hasOwnProperty(rawSearchIndex, crate)) { continue; }
1853
1854 var crateSize = 0;
1a4d82fc 1855
7453a54e 1856 searchWords.push(crate);
6a06907d
XL
1857 var normalizedName = crate.indexOf("_") === -1
1858 ? crate
1859 : crate.replace(/_/g, "");
1860 // This object should have exactly the same set of fields as the "row"
1861 // object defined below. Your JavaScript runtime will thank you.
1862 // https://mathiasbynens.be/notes/shapes-ics
1863 var crateRow = {
7453a54e
SL
1864 crate: crate,
1865 ty: 1, // == ExternCrate
1866 name: crate,
1867 path: "",
1868 desc: rawSearchIndex[crate].doc,
6a06907d 1869 parent: undefined,
7453a54e 1870 type: null,
6a06907d
XL
1871 id: id,
1872 normalizedName: normalizedName,
1873 };
1874 id += 1;
1875 searchIndex.push(crateRow);
f9f354fc 1876 currentIndex += 1;
7453a54e 1877
6a06907d
XL
1878 // an array of (Number) item types
1879 var itemTypes = rawSearchIndex[crate].t;
1880 // an array of (String) item names
1881 var itemNames = rawSearchIndex[crate].n;
1882 // an array of (String) full paths (or empty string for previous path)
1883 var itemPaths = rawSearchIndex[crate].q;
1884 // an array of (String) descriptions
1885 var itemDescs = rawSearchIndex[crate].d;
1886 // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
1887 var itemParentIdxs = rawSearchIndex[crate].i;
1888 // an array of (Object | null) the type of the function, if any
1889 var itemFunctionSearchTypes = rawSearchIndex[crate].f;
1a4d82fc
JJ
1890 // an array of [(Number) item type,
1891 // (String) name]
9fa01778 1892 var paths = rawSearchIndex[crate].p;
f9f354fc
XL
1893 // a array of [(String) alias name
1894 // [Number] index to items]
1895 var aliases = rawSearchIndex[crate].a;
1a4d82fc 1896
74b04a01 1897 // convert `rawPaths` entries into object form
1a4d82fc 1898 var len = paths.length;
0731742a 1899 for (i = 0; i < len; ++i) {
1a4d82fc
JJ
1900 paths[i] = {ty: paths[i][0], name: paths[i][1]};
1901 }
1902
6a06907d 1903 // convert `item*` into an object form, and construct word indices.
1a4d82fc
JJ
1904 //
1905 // before any analysis is performed lets gather the search terms to
1906 // search against apart from the rest of the data. This is a quick
1907 // operation that is cached for the life of the page state so that
1908 // all other search operations have access to this cached data for
1909 // faster analysis operations
6a06907d 1910 len = itemTypes.length;
1a4d82fc 1911 var lastPath = "";
0731742a 1912 for (i = 0; i < len; ++i) {
6a06907d
XL
1913 // This object should have exactly the same set of fields as the "crateRow"
1914 // object defined above.
1915 if (typeof itemNames[i] === "string") {
1916 word = itemNames[i].toLowerCase();
1917 searchWords.push(word);
1918 } else {
1919 word = "";
1920 searchWords.push("");
f9f354fc 1921 }
6a06907d
XL
1922 var normalizedName = word.indexOf("_") === -1
1923 ? word
1924 : word.replace(/_/g, "");
f9f354fc
XL
1925 var row = {
1926 crate: crate,
6a06907d
XL
1927 ty: itemTypes[i],
1928 name: itemNames[i],
1929 path: itemPaths[i] ? itemPaths[i] : lastPath,
1930 desc: itemDescs[i],
1931 parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
1932 type: itemFunctionSearchTypes[i],
1933 id: id,
1934 normalizedName: normalizedName,
f9f354fc 1935 };
6a06907d 1936 id += 1;
1a4d82fc 1937 searchIndex.push(row);
1a4d82fc 1938 lastPath = row.path;
f9f354fc 1939 crateSize += 1;
1a4d82fc 1940 }
f9f354fc
XL
1941
1942 if (aliases) {
1943 ALIASES[crate] = {};
1944 var j, local_aliases;
1945 for (var alias_name in aliases) {
1946 if (!aliases.hasOwnProperty(alias_name)) { continue; }
1947
1948 if (!ALIASES[crate].hasOwnProperty(alias_name)) {
1949 ALIASES[crate][alias_name] = [];
1950 }
1951 local_aliases = aliases[alias_name];
5869c6ff 1952 for (j = 0, len = local_aliases.length; j < len; ++j) {
f9f354fc
XL
1953 ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
1954 }
1955 }
1956 }
1957 currentIndex += crateSize;
1a4d82fc
JJ
1958 }
1959 return searchWords;
1960 }
1961
6a06907d
XL
1962 function registerSearchEvents() {
1963 var searchAfter500ms = function() {
f9f354fc 1964 clearInputTimeout();
7cac9316 1965 if (search_input.value.length === 0) {
54a0048b 1966 if (browserSupportsHistoryApi()) {
5869c6ff
XL
1967 history.replaceState("", window.currentCrate + " - Rust",
1968 getNakedUrl() + window.location.hash);
54a0048b 1969 }
dfeec247 1970 hideSearchResults();
b039eaaf
SL
1971 } else {
1972 searchTimeout = setTimeout(search, 500);
1973 }
7cac9316 1974 };
6a06907d
XL
1975 search_input.onkeyup = searchAfter500ms;
1976 search_input.oninput = searchAfter500ms;
abe05a73 1977 document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
b039eaaf 1978 e.preventDefault();
f9f354fc 1979 clearInputTimeout();
b039eaaf 1980 search();
7cac9316
XL
1981 };
1982 search_input.onchange = function(e) {
dfeec247
XL
1983 if (e.target !== document.activeElement) {
1984 // To prevent doing anything when it's from a blur event.
1985 return;
1986 }
b039eaaf 1987 // Do NOT e.preventDefault() here. It will prevent pasting.
f9f354fc 1988 clearInputTimeout();
b039eaaf
SL
1989 // zero-timeout necessary here because at the time of event handler execution the
1990 // pasted content is not in the input field yet. Shouldn’t make any difference for
1991 // change, though.
1992 setTimeout(search, 0);
7cac9316
XL
1993 };
1994 search_input.onpaste = search_input.onchange;
1a4d82fc 1995
e1599b0c 1996 var selectCrate = document.getElementById("crate-search");
0731742a
XL
1997 if (selectCrate) {
1998 selectCrate.onchange = function() {
e1599b0c 1999 updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
0731742a
XL
2000 search(undefined, true);
2001 };
2002 }
2003
1a4d82fc
JJ
2004 // Push and pop states are used to add search results to the browser
2005 // history.
2006 if (browserSupportsHistoryApi()) {
c1a9b12d 2007 // Store the previous <title> so we can revert back to it later.
7cac9316 2008 var previousTitle = document.title;
c1a9b12d 2009
dfeec247 2010 window.addEventListener("popstate", function(e) {
1a4d82fc 2011 var params = getQueryStringParams();
c1a9b12d
SL
2012 // Revert to the previous title manually since the History
2013 // API ignores the title parameter.
7cac9316 2014 document.title = previousTitle;
1a4d82fc
JJ
2015 // When browsing forward to search results the previous
2016 // search will be repeated, so the currentResults are
2017 // cleared to ensure the search is successful.
2018 currentResults = null;
2019 // Synchronize search bar with query string state and
2020 // perform the search. This will empty the bar if there's
2021 // nothing there, which lets you really go back to a
2022 // previous state with nothing in the bar.
dfeec247 2023 if (params.search && params.search.length > 0) {
83c7162d 2024 search_input.value = params.search;
dfeec247
XL
2025 // Some browsers fire "onpopstate" for every page load
2026 // (Chrome), while others fire the event only when actually
2027 // popping a state (Firefox), which is why search() is
2028 // called both here and at the end of the startSearch()
2029 // function.
2030 search(e);
7cac9316 2031 } else {
0731742a 2032 search_input.value = "";
dfeec247
XL
2033 // When browsing back from search results the main page
2034 // visibility must be reset.
2035 hideSearchResults();
7cac9316 2036 }
dfeec247 2037 });
1a4d82fc 2038 }
6a06907d
XL
2039
2040 // This is required in firefox to avoid this problem: Navigating to a search result
2041 // with the keyboard, hitting enter, and then hitting back would take you back to
2042 // the doc page, rather than the search that should overlay it.
2043 // This was an interaction between the back-forward cache and our handlers
2044 // that try to sync state between the URL and the search input. To work around it,
2045 // do a small amount of re-init on page show.
2046 window.onpageshow = function(){
2047 var qSearch = getQueryStringParams().search;
2048 if (search_input.value === "" && qSearch) {
2049 search_input.value = qSearch;
2050 }
2051 search();
2052 };
1a4d82fc
JJ
2053 }
2054
2055 index = buildIndex(rawSearchIndex);
6a06907d
XL
2056 registerSearchEvents();
2057 // If there's a search term in the URL, execute the search now.
2058 if (getQueryStringParams().search) {
2059 search();
2060 }
2061 };
1a4d82fc 2062
6a06907d 2063 function addSidebarCrates(crates) {
1a4d82fc 2064 // Draw a convenient sidebar of known crates if we have a listing
5869c6ff 2065 if (window.rootPath === "../" || window.rootPath === "./") {
0731742a 2066 var sidebar = document.getElementsByClassName("sidebar-elems")[0];
0531ce1d 2067 if (sidebar) {
0731742a
XL
2068 var div = document.createElement("div");
2069 div.className = "block crate";
2070 div.innerHTML = "<h3>Crates</h3>";
2071 var ul = document.createElement("ul");
0531ce1d
XL
2072 div.appendChild(ul);
2073
0531ce1d 2074 for (var i = 0; i < crates.length; ++i) {
0731742a 2075 var klass = "crate";
5869c6ff 2076 if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
0731742a 2077 klass += " current";
0531ce1d 2078 }
0731742a 2079 var link = document.createElement("a");
5869c6ff 2080 link.href = window.rootPath + crates[i] + "/index.html";
0531ce1d
XL
2081 link.className = klass;
2082 link.textContent = crates[i];
2083
0731742a 2084 var li = document.createElement("li");
0531ce1d
XL
2085 li.appendChild(link);
2086 ul.appendChild(li);
1a4d82fc 2087 }
0531ce1d 2088 sidebar.appendChild(div);
1a4d82fc 2089 }
1a4d82fc 2090 }
fc512014
XL
2091 }
2092
c34b1796 2093 // delayed sidebar rendering.
f9f354fc 2094 window.initSidebarItems = function(items) {
0731742a 2095 var sidebar = document.getElementsByClassName("sidebar-elems")[0];
c34b1796
AL
2096 var current = window.sidebarCurrent;
2097
2098 function block(shortty, longty) {
2099 var filtered = items[shortty];
0731742a
XL
2100 if (!filtered) {
2101 return;
2102 }
c34b1796 2103
0731742a
XL
2104 var div = document.createElement("div");
2105 div.className = "block " + shortty;
2106 var h3 = document.createElement("h3");
7cac9316
XL
2107 h3.textContent = longty;
2108 div.appendChild(h3);
0731742a 2109 var ul = document.createElement("ul");
c34b1796 2110
5869c6ff 2111 for (var i = 0, len = filtered.length; i < len; ++i) {
c34b1796
AL
2112 var item = filtered[i];
2113 var name = item[0];
2114 var desc = item[1]; // can be null
2115
2116 var klass = shortty;
62682a34 2117 if (name === current.name && shortty === current.ty) {
0731742a 2118 klass += " current";
c34b1796
AL
2119 }
2120 var path;
0731742a
XL
2121 if (shortty === "mod") {
2122 path = name + "/index.html";
c34b1796 2123 } else {
0731742a 2124 path = shortty + "." + name + ".html";
c34b1796 2125 }
0731742a 2126 var link = document.createElement("a");
7cac9316
XL
2127 link.href = current.relpath + path;
2128 link.title = desc;
2129 link.className = klass;
2130 link.textContent = name;
0731742a 2131 var li = document.createElement("li");
7cac9316
XL
2132 li.appendChild(link);
2133 ul.appendChild(li);
c34b1796 2134 }
7cac9316 2135 div.appendChild(ul);
2c00a5a8
XL
2136 if (sidebar) {
2137 sidebar.appendChild(div);
2138 }
c34b1796
AL
2139 }
2140
3157f602 2141 block("primitive", "Primitive Types");
c34b1796 2142 block("mod", "Modules");
3157f602 2143 block("macro", "Macros");
c34b1796
AL
2144 block("struct", "Structs");
2145 block("enum", "Enums");
3b2f2976 2146 block("union", "Unions");
3157f602
XL
2147 block("constant", "Constants");
2148 block("static", "Statics");
c34b1796
AL
2149 block("trait", "Traits");
2150 block("fn", "Functions");
3157f602 2151 block("type", "Type Definitions");
abe05a73 2152 block("foreigntype", "Foreign Types");
94b46f34 2153 block("keyword", "Keywords");
9fa01778 2154 block("traitalias", "Trait Aliases");
f9f354fc 2155 };
c34b1796 2156
1a4d82fc 2157 window.register_implementors = function(imp) {
0731742a
XL
2158 var implementors = document.getElementById("implementors-list");
2159 var synthetic_implementors = document.getElementById("synthetic-implementors-list");
0531ce1d 2160
dfeec247
XL
2161 if (synthetic_implementors) {
2162 // This `inlined_types` variable is used to avoid having the same implementation
2163 // showing up twice. For example "String" in the "Sync" doc page.
2164 //
2165 // By the way, this is only used by and useful for traits implemented automatically
2166 // (like "Send" and "Sync").
2167 var inlined_types = new Set();
2168 onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
2169 var aliases = el.getAttribute("aliases");
2170 if (!aliases) {
2171 return;
2172 }
2173 aliases.split(",").forEach(function(alias) {
2174 inlined_types.add(alias);
2175 });
2176 });
2177 }
2178
1a4d82fc 2179 var libs = Object.getOwnPropertyNames(imp);
5869c6ff
XL
2180 for (var i = 0, llength = libs.length; i < llength; ++i) {
2181 if (libs[i] === window.currentCrate) { continue; }
1a4d82fc 2182 var structs = imp[libs[i]];
0531ce1d
XL
2183
2184 struct_loop:
5869c6ff 2185 for (var j = 0, slength = structs.length; j < slength; ++j) {
0531ce1d
XL
2186 var struct = structs[j];
2187
2188 var list = struct.synthetic ? synthetic_implementors : implementors;
2189
2190 if (struct.synthetic) {
5869c6ff 2191 for (var k = 0, stlength = struct.types.length; k < stlength; k++) {
dfeec247 2192 if (inlined_types.has(struct.types[k])) {
0531ce1d
XL
2193 continue struct_loop;
2194 }
dfeec247 2195 inlined_types.add(struct.types[k]);
0531ce1d
XL
2196 }
2197 }
2198
0731742a 2199 var code = document.createElement("code");
0531ce1d 2200 code.innerHTML = struct.text;
7cac9316 2201
5869c6ff
XL
2202 onEachLazy(code.getElementsByTagName("a"), function(elem) {
2203 var href = elem.getAttribute("href");
2204
0731742a 2205 if (href && href.indexOf("http") !== 0) {
5869c6ff 2206 elem.setAttribute("href", window.rootPath + href);
1a4d82fc 2207 }
5869c6ff
XL
2208 });
2209
0731742a 2210 var display = document.createElement("h3");
b7449926 2211 addClass(display, "impl");
0731742a
XL
2212 display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
2213 "<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
2214 "</tbody></table></span>";
b7449926 2215 list.appendChild(display);
1a4d82fc
JJ
2216 }
2217 }
2218 };
2219 if (window.pending_implementors) {
2220 window.register_implementors(window.pending_implementors);
2221 }
2222
d9579d0f
AL
2223 function labelForToggleButton(sectionIsCollapsed) {
2224 if (sectionIsCollapsed) {
2225 // button will expand the section
2226 return "+";
d9579d0f 2227 }
62682a34 2228 // button will collapse the section
6a06907d 2229 // note that this text is also set in the HTML template in ../render/mod.rs
0731742a 2230 return "\u2212"; // "\u2212" is "−" minus sign
d9579d0f 2231 }
1a4d82fc 2232
7cac9316
XL
2233 function onEveryMatchingChild(elem, className, func) {
2234 if (elem && className && func) {
0731742a
XL
2235 var length = elem.childNodes.length;
2236 var nodes = elem.childNodes;
2237 for (var i = 0; i < length; ++i) {
2238 if (hasClass(nodes[i], className)) {
2239 func(nodes[i]);
7cac9316 2240 } else {
0731742a 2241 onEveryMatchingChild(nodes[i], className, func);
7cac9316
XL
2242 }
2243 }
2244 }
2245 }
2246
5869c6ff 2247 function toggleAllDocs(fromAutoCollapse) {
1b1a35ee 2248 var innerToggle = document.getElementById(toggleAllDocsId);
0731742a 2249 if (!innerToggle) {
83c7162d
XL
2250 return;
2251 }
0731742a 2252 if (hasClass(innerToggle, "will-expand")) {
0531ce1d 2253 updateLocalStorage("rustdoc-collapse", "false");
0731742a
XL
2254 removeClass(innerToggle, "will-expand");
2255 onEveryMatchingChild(innerToggle, "inner", function(e) {
7cac9316
XL
2256 e.innerHTML = labelForToggleButton(false);
2257 });
0731742a 2258 innerToggle.title = "collapse all docs";
94b46f34 2259 if (fromAutoCollapse !== true) {
0731742a 2260 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
94b46f34
XL
2261 collapseDocs(e, "show");
2262 });
2263 }
d9579d0f 2264 } else {
0531ce1d 2265 updateLocalStorage("rustdoc-collapse", "true");
0731742a
XL
2266 addClass(innerToggle, "will-expand");
2267 onEveryMatchingChild(innerToggle, "inner", function(e) {
9fa01778
XL
2268 var parent = e.parentNode;
2269 var superParent = null;
2270
2271 if (parent) {
2272 superParent = parent.parentNode;
2273 }
2274 if (!parent || !superParent || superParent.id !== "main" ||
2275 hasClass(parent, "impl") === false) {
2276 e.innerHTML = labelForToggleButton(true);
2277 }
7cac9316 2278 });
0731742a 2279 innerToggle.title = "expand all docs";
94b46f34 2280 if (fromAutoCollapse !== true) {
0731742a 2281 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
9fa01778
XL
2282 var parent = e.parentNode;
2283 var superParent = null;
2284
2285 if (parent) {
2286 superParent = parent.parentNode;
2287 }
2288 if (!parent || !superParent || superParent.id !== "main" ||
2289 hasClass(parent, "impl") === false) {
5869c6ff 2290 collapseDocs(e, "hide");
9fa01778 2291 }
94b46f34
XL
2292 });
2293 }
d9579d0f 2294 }
a7813a04
XL
2295 }
2296
5869c6ff 2297 function collapseDocs(toggle, mode) {
7cac9316
XL
2298 if (!toggle || !toggle.parentNode) {
2299 return;
d9579d0f 2300 }
0531ce1d
XL
2301
2302 function adjustToggle(arg) {
2303 return function(e) {
0731742a 2304 if (hasClass(e, "toggle-label")) {
0531ce1d 2305 if (arg) {
0731742a 2306 e.style.display = "inline-block";
0531ce1d 2307 } else {
0731742a 2308 e.style.display = "none";
7cac9316 2309 }
0531ce1d 2310 }
0731742a 2311 if (hasClass(e, "inner")) {
0531ce1d
XL
2312 e.innerHTML = labelForToggleButton(arg);
2313 }
2314 };
0731742a
XL
2315 }
2316
9fa01778 2317 function implHider(addOrRemove, fullHide) {
0731742a 2318 return function(n) {
fc512014
XL
2319 var shouldHide =
2320 fullHide === true ||
2321 hasClass(n, "method") === true ||
2322 hasClass(n, "associatedconstant") === true;
2323 if (shouldHide === true || hasClass(n, "type") === true) {
2324 if (shouldHide === true) {
0731742a
XL
2325 if (addOrRemove) {
2326 addClass(n, "hidden-by-impl-hider");
2327 } else {
2328 removeClass(n, "hidden-by-impl-hider");
2329 }
2330 }
2331 var ns = n.nextElementSibling;
fc512014 2332 while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
f9f354fc
XL
2333 if (addOrRemove) {
2334 addClass(ns, "hidden-by-impl-hider");
2335 } else {
2336 removeClass(ns, "hidden-by-impl-hider");
0731742a 2337 }
f9f354fc 2338 ns = ns.nextElementSibling;
0731742a
XL
2339 }
2340 }
2341 };
2342 }
0531ce1d 2343
0731742a
XL
2344 var relatedDoc;
2345 var action = mode;
2346 if (hasClass(toggle.parentNode, "impl") === false) {
2347 relatedDoc = toggle.parentNode.nextElementSibling;
fc512014 2348 if (hasClass(relatedDoc, "item-info")) {
0531ce1d
XL
2349 relatedDoc = relatedDoc.nextElementSibling;
2350 }
a1dfa0c6 2351 if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
0731742a 2352 if (mode === "toggle") {
0531ce1d
XL
2353 if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
2354 action = "show";
2355 } else {
2356 action = "hide";
7cac9316 2357 }
0531ce1d
XL
2358 }
2359 if (action === "hide") {
2360 addClass(relatedDoc, "hidden-by-usual-hider");
0731742a
XL
2361 onEachLazy(toggle.childNodes, adjustToggle(true));
2362 addClass(toggle.parentNode, "collapsed");
0531ce1d
XL
2363 } else if (action === "show") {
2364 removeClass(relatedDoc, "hidden-by-usual-hider");
0731742a
XL
2365 removeClass(toggle.parentNode, "collapsed");
2366 onEachLazy(toggle.childNodes, adjustToggle(false));
0531ce1d
XL
2367 }
2368 }
2369 } else {
9fa01778 2370 // we are collapsing the impl block(s).
0531ce1d 2371
83c7162d 2372 var parentElem = toggle.parentNode;
0731742a 2373 relatedDoc = parentElem;
0531ce1d
XL
2374 var docblock = relatedDoc.nextElementSibling;
2375
0731742a 2376 while (hasClass(relatedDoc, "impl-items") === false) {
0531ce1d
XL
2377 relatedDoc = relatedDoc.nextElementSibling;
2378 }
2379
3dfed10e 2380 if (!relatedDoc && hasClass(docblock, "docblock") === false) {
0531ce1d
XL
2381 return;
2382 }
2383
9fa01778 2384 // Hide all functions, but not associated types/consts.
0531ce1d 2385
0731742a 2386 if (mode === "toggle") {
0531ce1d 2387 if (hasClass(relatedDoc, "fns-now-collapsed") ||
0731742a 2388 hasClass(docblock, "hidden-by-impl-hider")) {
0531ce1d
XL
2389 action = "show";
2390 } else {
2391 action = "hide";
2392 }
2393 }
2394
9fa01778 2395 var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
0531ce1d
XL
2396 if (action === "show") {
2397 removeClass(relatedDoc, "fns-now-collapsed");
fc512014
XL
2398 // Stability/deprecation/portability information is never hidden.
2399 if (hasClass(docblock, "item-info") === false) {
2400 removeClass(docblock, "hidden-by-usual-hider");
2401 }
9fa01778
XL
2402 onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
2403 onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
0531ce1d
XL
2404 } else if (action === "hide") {
2405 addClass(relatedDoc, "fns-now-collapsed");
fc512014
XL
2406 // Stability/deprecation/portability information should be shown even when detailed
2407 // info is hidden.
2408 if (hasClass(docblock, "item-info") === false) {
2409 addClass(docblock, "hidden-by-usual-hider");
2410 }
9fa01778
XL
2411 onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
2412 onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
0731742a
XL
2413 }
2414 }
2415 }
2416
5869c6ff 2417 function collapser(e, collapse) {
0731742a
XL
2418 // inherent impl ids are like "impl" or impl-<number>'.
2419 // they will never be hidden by default.
2420 var n = e.parentElement;
2421 if (n.id.match(/^impl(?:-\d+)?$/) === null) {
2422 // Automatically minimize all non-inherent impls
2423 if (collapse || hasClass(n, "impl")) {
5869c6ff 2424 collapseDocs(e, "hide");
0531ce1d
XL
2425 }
2426 }
2427 }
2428
5869c6ff 2429 function autoCollapse(collapse) {
94b46f34 2430 if (collapse) {
5869c6ff 2431 toggleAllDocs(true);
29967ef6 2432 } else if (getSettingValue("auto-hide-trait-implementations") !== "false") {
f9f354fc 2433 var impl_list = document.getElementById("trait-implementations-list");
0bf4aa26
XL
2434
2435 if (impl_list !== null) {
0731742a 2436 onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) {
5869c6ff 2437 collapser(e, collapse);
b7449926
XL
2438 });
2439 }
532ac7d7
XL
2440
2441 var blanket_list = document.getElementById("blanket-implementations-list");
2442
2443 if (blanket_list !== null) {
2444 onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
5869c6ff 2445 collapser(e, collapse);
532ac7d7
XL
2446 });
2447 }
8faf50e0 2448 }
476ff2be
SL
2449 }
2450
7cac9316
XL
2451 function insertAfter(newNode, referenceNode) {
2452 referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
2453 }
1a4d82fc 2454
0731742a
XL
2455 function createSimpleToggle(sectionIsCollapsed) {
2456 var toggle = document.createElement("a");
2457 toggle.href = "javascript:void(0)";
2458 toggle.className = "collapse-toggle";
2459 toggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed) +
2460 "</span>]";
2461 return toggle;
0531ce1d
XL
2462 }
2463
f9f354fc 2464 function createToggle(toggle, otherMessage, fontSize, extraClass, show) {
0731742a
XL
2465 var span = document.createElement("span");
2466 span.className = "toggle-label";
b7449926 2467 if (show) {
0731742a 2468 span.style.display = "none";
b7449926 2469 }
0531ce1d 2470 if (!otherMessage) {
0731742a 2471 span.innerHTML = "&nbsp;Expand&nbsp;description";
0531ce1d
XL
2472 } else {
2473 span.innerHTML = otherMessage;
8faf50e0
XL
2474 }
2475
2476 if (fontSize) {
2477 span.style.fontSize = fontSize;
0531ce1d 2478 }
476ff2be 2479
041b39d2
XL
2480 var mainToggle = toggle.cloneNode(true);
2481 mainToggle.appendChild(span);
1a4d82fc 2482
0731742a
XL
2483 var wrapper = document.createElement("div");
2484 wrapper.className = "toggle-wrapper";
b7449926 2485 if (!show) {
0731742a
XL
2486 addClass(wrapper, "collapsed");
2487 var inner = mainToggle.getElementsByClassName("inner");
b7449926 2488 if (inner && inner.length > 0) {
0731742a 2489 inner[0].innerHTML = "+";
b7449926
XL
2490 }
2491 }
94b46f34 2492 if (extraClass) {
b7449926 2493 addClass(wrapper, extraClass);
94b46f34 2494 }
041b39d2
XL
2495 wrapper.appendChild(mainToggle);
2496 return wrapper;
2497 }
1a4d82fc 2498
f9f354fc 2499 (function() {
1b1a35ee
XL
2500 var toggles = document.getElementById(toggleAllDocsId);
2501 if (toggles) {
2502 toggles.onclick = toggleAllDocs;
2503 }
2504
f9f354fc 2505 var toggle = createSimpleToggle(false);
29967ef6
XL
2506 var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
2507 var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
f9f354fc
XL
2508
2509 var func = function(e) {
2510 var next = e.nextElementSibling;
fc512014
XL
2511 if (next && hasClass(next, "item-info")) {
2512 next = next.nextElementSibling;
2513 }
f9f354fc
XL
2514 if (!next) {
2515 return;
2516 }
fc512014 2517 if (hasClass(next, "docblock")) {
f9f354fc
XL
2518 var newToggle = toggle.cloneNode(true);
2519 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2520 if (hideMethodDocs === true && hasClass(e, "method") === true) {
5869c6ff 2521 collapseDocs(newToggle, "hide");
60c5eb7d 2522 }
f9f354fc
XL
2523 }
2524 };
2525
2526 var funcImpl = function(e) {
2527 var next = e.nextElementSibling;
fc512014
XL
2528 if (next && hasClass(next, "item-info")) {
2529 next = next.nextElementSibling;
2530 }
f9f354fc
XL
2531 if (next && hasClass(next, "docblock")) {
2532 next = next.nextElementSibling;
2533 }
2534 if (!next) {
2535 return;
2536 }
f035d41b
XL
2537 if (hasClass(e, "impl") &&
2538 (next.getElementsByClassName("method").length > 0 ||
2539 next.getElementsByClassName("associatedconstant").length > 0)) {
3dfed10e
XL
2540 var newToggle = toggle.cloneNode(true);
2541 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2542 // In case the option "auto-collapse implementors" is not set to false, we collapse
2543 // all implementors.
2544 if (hideImplementors === true && e.parentNode.id === "implementors-list") {
5869c6ff 2545 collapseDocs(newToggle, "hide");
3dfed10e 2546 }
f9f354fc
XL
2547 }
2548 };
2549
2550 onEachLazy(document.getElementsByClassName("method"), func);
2551 onEachLazy(document.getElementsByClassName("associatedconstant"), func);
2552 onEachLazy(document.getElementsByClassName("impl"), funcImpl);
2553 var impl_call = function() {};
2554 if (hideMethodDocs === true) {
2555 impl_call = function(e, newToggle) {
2556 if (e.id.match(/^impl(?:-\d+)?$/) === null) {
2557 // Automatically minimize all non-inherent impls
2558 if (hasClass(e, "impl") === true) {
5869c6ff 2559 collapseDocs(newToggle, "hide");
f9f354fc
XL
2560 }
2561 }
2562 };
60c5eb7d 2563 }
f9f354fc
XL
2564 var newToggle = document.createElement("a");
2565 newToggle.href = "javascript:void(0)";
2566 newToggle.className = "collapse-toggle hidden-default collapsed";
2567 newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2568 "</span>] Show hidden undocumented items";
2569 function toggleClicked() {
2570 if (hasClass(this, "collapsed")) {
2571 removeClass(this, "collapsed");
2572 onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
2573 if (hasClass(x, "content") === false) {
2574 removeClass(x, "hidden");
2575 addClass(x, "x");
2576 }
2577 }, true);
2578 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
2579 "</span>] Hide undocumented items";
2580 } else {
2581 addClass(this, "collapsed");
2582 onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
2583 if (hasClass(x, "content") === false) {
2584 addClass(x, "hidden");
2585 removeClass(x, "x");
2586 }
2587 }, true);
2588 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2589 "</span>] Show hidden undocumented items";
2590 }
60c5eb7d 2591 }
f9f354fc
XL
2592 onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
2593 onEachLazy(e.getElementsByClassName("associatedconstant"), func);
5869c6ff
XL
2594 // We transform the DOM iterator into a vec of DOM elements to prevent performance
2595 // issues on webkit browsers.
2596 var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden"));
2597 var needToggle = hiddenElems.some(function(hiddenElem) {
2598 return hasClass(hiddenElem, "content") === false &&
2599 hasClass(hiddenElem, "docblock") === false;
2600 });
f9f354fc
XL
2601 if (needToggle === true) {
2602 var inner_toggle = newToggle.cloneNode(true);
2603 inner_toggle.onclick = toggleClicked;
2604 e.insertBefore(inner_toggle, e.firstChild);
2605 impl_call(e.previousSibling, inner_toggle);
2606 }
2607 });
2608
2609 var currentType = document.getElementsByClassName("type-decl")[0];
2610 var className = null;
2611 if (currentType) {
2612 currentType = currentType.getElementsByClassName("rust")[0];
2613 if (currentType) {
2614 currentType.classList.forEach(function(item) {
2615 if (item !== "main") {
2616 className = item;
2617 return true;
83c7162d 2618 }
7cac9316 2619 });
1a4d82fc 2620 }
7cac9316 2621 }
29967ef6 2622 var showItemDeclarations = getSettingValue("auto-hide-" + className);
f9f354fc
XL
2623 if (showItemDeclarations === null) {
2624 if (className === "enum" || className === "macro") {
2625 showItemDeclarations = "false";
2626 } else if (className === "struct" || className === "union" || className === "trait") {
2627 showItemDeclarations = "true";
2628 } else {
2629 // In case we found an unknown type, we just use the "parent" value.
29967ef6 2630 showItemDeclarations = getSettingValue("auto-hide-declarations");
f9f354fc
XL
2631 }
2632 }
2633 showItemDeclarations = showItemDeclarations === "false";
2634 function buildToggleWrapper(e) {
2635 if (hasClass(e, "autohide")) {
2636 var wrap = e.previousElementSibling;
2637 if (wrap && hasClass(wrap, "toggle-wrapper")) {
2638 var inner_toggle = wrap.childNodes[0];
2639 var extra = e.childNodes[0].tagName === "H3";
2640
2641 e.style.display = "none";
2642 addClass(wrap, "collapsed");
2643 onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) {
2644 e.innerHTML = labelForToggleButton(true);
2645 });
2646 onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) {
2647 e.style.display = "inline-block";
2648 if (extra === true) {
2649 e.innerHTML = " Show " + e.childNodes[0].innerHTML;
2650 }
2651 });
2652 }
2653 }
2654 if (e.parentNode.id === "main") {
2655 var otherMessage = "";
2656 var fontSize;
2657 var extraClass;
2658
2659 if (hasClass(e, "type-decl")) {
2660 fontSize = "20px";
2661 otherMessage = "&nbsp;Show&nbsp;declaration";
2662 if (showItemDeclarations === false) {
2663 extraClass = "collapsed";
2664 }
2665 } else if (hasClass(e, "sub-variant")) {
2666 otherMessage = "&nbsp;Show&nbsp;fields";
2667 } else if (hasClass(e, "non-exhaustive")) {
2668 otherMessage = "&nbsp;This&nbsp;";
2669 if (hasClass(e, "non-exhaustive-struct")) {
2670 otherMessage += "struct";
2671 } else if (hasClass(e, "non-exhaustive-enum")) {
2672 otherMessage += "enum";
2673 } else if (hasClass(e, "non-exhaustive-variant")) {
2674 otherMessage += "enum variant";
2675 } else if (hasClass(e, "non-exhaustive-type")) {
2676 otherMessage += "type";
2677 }
2678 otherMessage += "&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive";
2679 } else if (hasClass(e.childNodes[0], "impl-items")) {
2680 extraClass = "marg-left";
2681 }
2682
2683 e.parentNode.insertBefore(
2684 createToggle(
2685 toggle,
2686 otherMessage,
2687 fontSize,
2688 extraClass,
2689 hasClass(e, "type-decl") === false || showItemDeclarations === true),
2690 e);
2691 if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
2692 collapseDocs(e.previousSibling.childNodes[0], "toggle");
2693 }
2694 if (hasClass(e, "non-exhaustive") === true) {
2695 collapseDocs(e.previousSibling.childNodes[0], "toggle");
2696 }
532ac7d7 2697 }
83c7162d 2698 }
a1dfa0c6 2699
f9f354fc
XL
2700 onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
2701 onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
f035d41b 2702
5869c6ff 2703 autoCollapse(getSettingValue("collapse") === "true");
f035d41b 2704
5869c6ff 2705 var pageId = getPageId();
f035d41b
XL
2706 if (pageId !== null) {
2707 expandSection(pageId);
2708 }
f9f354fc 2709 }());
7cac9316 2710
0731742a
XL
2711 function createToggleWrapper(tog) {
2712 var span = document.createElement("span");
2713 span.className = "toggle-label";
2714 span.style.display = "none";
2715 span.innerHTML = "&nbsp;Expand&nbsp;attributes";
2716 tog.appendChild(span);
2717
2718 var wrapper = document.createElement("div");
2719 wrapper.className = "toggle-wrapper toggle-attributes";
2720 wrapper.appendChild(tog);
2721 return wrapper;
2722 }
2723
f9f354fc
XL
2724 (function() {
2725 // To avoid checking on "rustdoc-item-attributes" value on every loop...
2726 var itemAttributesFunc = function() {};
29967ef6 2727 if (getSettingValue("auto-hide-attributes") !== "false") {
f9f354fc
XL
2728 itemAttributesFunc = function(x) {
2729 collapseDocs(x.previousSibling.childNodes[0], "toggle");
2730 };
ea8adc8c 2731 }
f9f354fc
XL
2732 var attributesToggle = createToggleWrapper(createSimpleToggle(false));
2733 onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
2734 var attr_tog = attributesToggle.cloneNode(true);
2735 if (hasClass(i_e, "top-attr") === true) {
2736 addClass(attr_tog, "top-attr");
2737 }
2738 i_e.parentNode.insertBefore(attr_tog, i_e);
2739 itemAttributesFunc(i_e);
2740 });
2741 }());
2742
2743 (function() {
2744 // To avoid checking on "rustdoc-line-numbers" value on every loop...
2745 var lineNumbersFunc = function() {};
29967ef6 2746 if (getSettingValue("line-numbers") === "true") {
f9f354fc
XL
2747 lineNumbersFunc = function(x) {
2748 var count = x.textContent.split("\n").length;
2749 var elems = [];
2750 for (var i = 0; i < count; ++i) {
2751 elems.push(i + 1);
2752 }
2753 var node = document.createElement("pre");
2754 addClass(node, "line-number");
2755 node.innerHTML = elems.join("\n");
2756 x.parentNode.insertBefore(node, x);
2757 };
2758 }
2759 onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
2760 if (hasClass(e, "compile_fail")) {
2761 e.addEventListener("mouseover", function() {
2762 this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
2763 });
2764 e.addEventListener("mouseout", function() {
2765 this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2766 });
2767 } else if (hasClass(e, "ignore")) {
2768 e.addEventListener("mouseover", function() {
2769 this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
2770 });
2771 e.addEventListener("mouseout", function() {
2772 this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2773 });
2774 }
2775 lineNumbersFunc(e);
2776 });
2777 }());
abe05a73 2778
3dfed10e
XL
2779 onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
2780 e.onclick = function() {
2781 this.getElementsByClassName('notable-traits-tooltiptext')[0]
2782 .classList.toggle("force-tooltip");
2783 };
2784 });
2785
532ac7d7
XL
2786 // In the search display, allows to switch between tabs.
2787 function printTab(nb) {
2788 if (nb === 0 || nb === 1 || nb === 2) {
2789 currentTab = nb;
2790 }
2791 var nb_copy = nb;
2792 onEachLazy(document.getElementById("titles").childNodes, function(elem) {
2793 if (nb_copy === 0) {
2794 addClass(elem, "selected");
2795 } else {
2796 removeClass(elem, "selected");
2797 }
2798 nb_copy -= 1;
2799 });
2800 onEachLazy(document.getElementById("results").childNodes, function(elem) {
2801 if (nb === 0) {
2802 elem.style.display = "";
2803 } else {
2804 elem.style.display = "none";
2805 }
2806 nb -= 1;
2807 });
2808 }
2809
83c7162d 2810 function putBackSearch(search_input) {
dfeec247
XL
2811 var search = getSearchElement();
2812 if (search_input.value !== "" && hasClass(search, "hidden")) {
2813 showSearchResults(search);
83c7162d 2814 if (browserSupportsHistoryApi()) {
5869c6ff
XL
2815 var extra = "?search=" + encodeURIComponent(search_input.value);
2816 history.replaceState(search_input.value, "",
2817 getNakedUrl() + extra + window.location.hash);
83c7162d 2818 }
29967ef6 2819 document.title = searchTitle;
83c7162d
XL
2820 }
2821 }
abe05a73 2822
1b1a35ee
XL
2823 function getSearchLoadingText() {
2824 return "Loading search results...";
2825 }
2826
abe05a73
XL
2827 if (search_input) {
2828 search_input.onfocus = function() {
83c7162d 2829 putBackSearch(this);
abe05a73
XL
2830 };
2831 }
ff7c6d11
XL
2832
2833 var params = getQueryStringParams();
2834 if (params && params.search) {
e1599b0c 2835 var search = getSearchElement();
1b1a35ee 2836 search.innerHTML = "<h3 style=\"text-align: center;\">" + getSearchLoadingText() + "</h3>";
dfeec247 2837 showSearchResults(search);
ff7c6d11
XL
2838 }
2839
2840 var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
2841 if (sidebar_menu) {
2842 sidebar_menu.onclick = function() {
0731742a 2843 var sidebar = document.getElementsByClassName("sidebar")[0];
ff7c6d11
XL
2844 if (hasClass(sidebar, "mobile") === true) {
2845 hideSidebar();
2846 } else {
2847 showSidebar();
2848 }
2849 };
2850 }
2851
0731742a
XL
2852 if (main) {
2853 onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
2854 e.remove();
2855 });
2856 onEachLazy(main.childNodes, function(e) {
2857 // Unhide the actual content once loading is complete. Headers get
2858 // flex treatment for their horizontal layout, divs get block treatment
2859 // for vertical layout (column-oriented flex layout for divs caused
2860 // errors in mobile browsers).
2861 if (e.tagName === "H2" || e.tagName === "H3") {
9fa01778 2862 var nextTagName = e.nextElementSibling.tagName;
0731742a
XL
2863 if (nextTagName == "H2" || nextTagName == "H3") {
2864 e.nextElementSibling.style.display = "flex";
2865 } else {
2866 e.nextElementSibling.style.display = "block";
2867 }
2868 }
2869 });
2870 }
2871
6a06907d 2872 function addSearchOptions(crates) {
e1599b0c 2873 var elem = document.getElementById("crate-search");
0731742a
XL
2874
2875 if (!elem) {
2876 return;
2877 }
29967ef6 2878 var savedCrate = getSettingValue("saved-filter-crate");
6a06907d 2879 for (var i = 0, len = crates.length; i < len; ++i) {
0731742a 2880 var option = document.createElement("option");
6a06907d
XL
2881 option.value = crates[i];
2882 option.innerText = crates[i];
0731742a 2883 elem.appendChild(option);
60c5eb7d
XL
2884 // Set the crate filter from saved storage, if the current page has the saved crate
2885 // filter.
2886 //
2887 // If not, ignore the crate filter -- we want to support filtering for crates on sites
2888 // like doc.rust-lang.org where the crates may differ from page to page while on the
2889 // same domain.
6a06907d 2890 if (crates[i] === savedCrate) {
60c5eb7d
XL
2891 elem.value = savedCrate;
2892 }
0731742a 2893 }
f9f354fc 2894 };
e74abb32
XL
2895
2896 function buildHelperPopup() {
2897 var popup = document.createElement("aside");
2898 addClass(popup, "hidden");
2899 popup.id = "help";
2900
29967ef6
XL
2901 var book_info = document.createElement("span");
2902 book_info.innerHTML = "You can find more information in \
2903 <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
2904
e74abb32
XL
2905 var container = document.createElement("div");
2906 var shortcuts = [
2907 ["?", "Show this help dialog"],
2908 ["S", "Focus the search field"],
29967ef6 2909 ["T", "Focus the theme picker menu"],
e74abb32
XL
2910 ["↑", "Move up in search results"],
2911 ["↓", "Move down in search results"],
fc512014 2912 ["ctrl + ↑ / ↓", "Switch result tab"],
e74abb32
XL
2913 ["&#9166;", "Go to active search result"],
2914 ["+", "Expand all sections"],
2915 ["-", "Collapse all sections"],
6a06907d
XL
2916 ].map(function(x) {
2917 return "<dt>" +
2918 x[0].split(" ")
2919 .map(function(y, index) {
2920 return (index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " ";
2921 })
2922 .join("") + "</dt><dd>" + x[1] + "</dd>";
2923 }).join("");
e74abb32
XL
2924 var div_shortcuts = document.createElement("div");
2925 addClass(div_shortcuts, "shortcuts");
2926 div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
2927
2928 var infos = [
2929 "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
1b1a35ee
XL
2930 restrict the search to a given item kind.",
2931 "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
e74abb32
XL
2932 <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
2933 and <code>const</code>.",
dfeec247
XL
2934 "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
2935 <code>* -&gt; vec</code>)",
e74abb32
XL
2936 "Search multiple things at once by splitting your query with comma (e.g., \
2937 <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
2938 "You can look for items with an exact name by putting double quotes around \
2939 your request: <code>\"string\"</code>",
2940 "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
6a06907d
XL
2941 ].map(function(x) {
2942 return "<p>" + x + "</p>";
2943 }).join("");
e74abb32
XL
2944 var div_infos = document.createElement("div");
2945 addClass(div_infos, "infos");
2946 div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
2947
29967ef6 2948 container.appendChild(book_info);
e74abb32
XL
2949 container.appendChild(div_shortcuts);
2950 container.appendChild(div_infos);
2951
2952 popup.appendChild(container);
2953 insertAfter(popup, getSearchElement());
1b1a35ee
XL
2954 // So that it's only built once and then it'll do nothing when called!
2955 buildHelperPopup = function() {};
e74abb32
XL
2956 }
2957
6a06907d
XL
2958 function loadScript(url) {
2959 var script = document.createElement('script');
2960 script.src = url;
2961 document.head.append(script);
2962 }
2963
2964 function setupSearchLoader() {
2965 var searchLoaded = false;
2966 function loadSearch() {
2967 if (!searchLoaded) {
2968 searchLoaded = true;
2969 loadScript(window.searchJS);
2970 }
2971 }
2972
2973 // `crates{version}.js` should always be loaded before this script, so we can use it safely.
2974 addSearchOptions(window.ALL_CRATES);
2975 addSidebarCrates(window.ALL_CRATES);
2976
2977 search_input.addEventListener("focus", function() {
2978 search_input.origPlaceholder = search_input.placeholder;
2979 search_input.placeholder = "Type your search here.";
2980 loadSearch();
2981 });
2982 search_input.addEventListener("blur", function() {
2983 search_input.placeholder = search_input.origPlaceholder;
2984 });
2985 search_input.removeAttribute('disabled');
2986
2987 var crateSearchDropDown = document.getElementById("crate-search");
2988 // `crateSearchDropDown` can be null in case there is only crate because in that case, the
2989 // crate filter dropdown is removed.
2990 if (crateSearchDropDown) {
2991 crateSearchDropDown.addEventListener("focus", loadSearch);
2992 }
2993 var params = getQueryStringParams();
2994 if (params.search !== undefined) {
2995 loadSearch();
2996 }
2997 }
2998
60c5eb7d
XL
2999 onHashChange(null);
3000 window.onhashchange = onHashChange;
6a06907d 3001 setupSearchLoader();
1a4d82fc 3002}());