]>
git.proxmox.com Git - rustc.git/blob - src/librustdoc/html/static/js/main.js
1 // Local js definitions:
2 /* global addClass, getSettingValue, hasClass, searchState */
3 /* global onEach, onEachLazy, removeClass */
4 /* global switchTheme, useSystemTheme */
6 if (!String
.prototype.startsWith
) {
7 String
.prototype.startsWith = function(searchString
, position
) {
8 position
= position
|| 0;
9 return this.indexOf(searchString
, position
) === position
;
12 if (!String
.prototype.endsWith
) {
13 String
.prototype.endsWith = function(suffix
, length
) {
14 var l
= length
|| this.length
;
15 return this.indexOf(suffix
, l
- suffix
.length
) !== -1;
19 if (!DOMTokenList
.prototype.add
) {
20 DOMTokenList
.prototype.add = function(className
) {
21 if (className
&& !hasClass(this, className
)) {
22 if (this.className
&& this.className
.length
> 0) {
23 this.className
+= " " + className
;
25 this.className
= className
;
31 if (!DOMTokenList
.prototype.remove
) {
32 DOMTokenList
.prototype.remove = function(className
) {
33 if (className
&& this.className
) {
34 this.className
= (" " + this.className
+ " ").replace(" " + className
+ " ", " ")
41 var rustdocVars
= document
.getElementById("rustdoc-vars");
43 window
.rootPath
= rustdocVars
.attributes
["data-root-path"].value
;
44 window
.currentCrate
= rustdocVars
.attributes
["data-current-crate"].value
;
45 window
.searchJS
= rustdocVars
.attributes
["data-search-js"].value
;
46 window
.searchIndexJS
= rustdocVars
.attributes
["data-search-index-js"].value
;
48 var sidebarVars
= document
.getElementById("sidebar-vars");
50 window
.sidebarCurrent
= {
51 name
: sidebarVars
.attributes
["data-name"].value
,
52 ty
: sidebarVars
.attributes
["data-ty"].value
,
53 relpath
: sidebarVars
.attributes
["data-relpath"].value
,
58 // Gets the human-readable string for the virtual-key code of the
59 // given KeyboardEvent, ev.
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.
67 // So I guess you could say things are getting pretty interoperable.
68 function getVirtualKey(ev
) {
69 if ("key" in ev
&& typeof ev
.key
!= "undefined") {
73 var c
= ev
.charCode
|| ev
.keyCode
;
77 return String
.fromCharCode(c
);
80 var THEME_PICKER_ELEMENT_ID
= "theme-picker";
81 var THEMES_ELEMENT_ID
= "theme-choices";
83 function getThemesElement() {
84 return document
.getElementById(THEMES_ELEMENT_ID
);
87 function getThemePickerElement() {
88 return document
.getElementById(THEME_PICKER_ELEMENT_ID
);
91 // Returns the current URL without any query parameter or hash.
92 function getNakedUrl() {
93 return window
.location
.href
.split("?")[0].split("#")[0];
96 function showThemeButtonState() {
97 var themePicker
= getThemePickerElement();
98 var themeChoices
= getThemesElement();
100 themeChoices
.style
.display
= "block";
101 themePicker
.style
.borderBottomRightRadius
= "0";
102 themePicker
.style
.borderBottomLeftRadius
= "0";
105 function hideThemeButtonState() {
106 var themePicker
= getThemePickerElement();
107 var themeChoices
= getThemesElement();
109 themeChoices
.style
.display
= "none";
110 themePicker
.style
.borderBottomRightRadius
= "3px";
111 themePicker
.style
.borderBottomLeftRadius
= "3px";
114 // Set up the theme picker list.
116 var themeChoices
= getThemesElement();
117 var themePicker
= getThemePickerElement();
118 var availableThemes
/* INSERT THEMES HERE */;
120 function switchThemeButtonState() {
121 if (themeChoices
.style
.display
=== "block") {
122 hideThemeButtonState();
124 showThemeButtonState();
128 function handleThemeButtonsBlur(e
) {
129 var active
= document
.activeElement
;
130 var related
= e
.relatedTarget
;
132 if (active
.id
!== THEME_PICKER_ELEMENT_ID
&&
133 (!active
.parentNode
|| active
.parentNode
.id
!== THEMES_ELEMENT_ID
) &&
135 (related
.id
!== THEME_PICKER_ELEMENT_ID
&&
136 (!related
.parentNode
|| related
.parentNode
.id
!== THEMES_ELEMENT_ID
)))) {
137 hideThemeButtonState();
141 themePicker
.onclick
= switchThemeButtonState
;
142 themePicker
.onblur
= handleThemeButtonsBlur
;
143 availableThemes
.forEach(function(item
) {
144 var but
= document
.createElement("button");
145 but
.textContent
= item
;
146 but
.onclick = function() {
147 switchTheme(window
.currentTheme
, window
.mainTheme
, item
, true);
148 useSystemTheme(false);
150 but
.onblur
= handleThemeButtonsBlur
;
151 themeChoices
.appendChild(but
);
158 window
.searchState
= {
159 loadingText
: "Loading search results...",
160 input
: document
.getElementsByClassName("search-input")[0],
161 outputElement: function() {
162 return document
.getElementById("search");
164 title
: document
.title
,
165 titleBeforeSearch
: document
.title
,
167 // On the search screen, so you remain on the last tab you opened.
170 // 1 for "In Parameters"
171 // 2 for "In Return Types"
173 // tab and back preserves the element that was focused.
174 focusedByTab
: [null, null, null],
175 clearInputTimeout: function() {
176 if (searchState
.timeout
!== null) {
177 clearTimeout(searchState
.timeout
);
178 searchState
.timeout
= null;
181 // Sets the focus on the search bar at the top of the page
183 searchState
.input
.focus();
185 // Removes the focus from the search bar.
186 defocus: function() {
187 searchState
.input
.blur();
189 showResults: function(search
) {
190 if (search
=== null || typeof search
=== 'undefined') {
191 search
= searchState
.outputElement();
193 addClass(main
, "hidden");
194 removeClass(search
, "hidden");
195 searchState
.mouseMovedAfterSearch
= false;
196 document
.title
= searchState
.title
;
198 hideResults: function(search
) {
199 if (search
=== null || typeof search
=== 'undefined') {
200 search
= searchState
.outputElement();
202 addClass(search
, "hidden");
203 removeClass(main
, "hidden");
204 document
.title
= searchState
.titleBeforeSearch
;
205 // We also remove the query parameter from the URL.
206 if (searchState
.browserSupportsHistoryApi()) {
207 history
.replaceState("", window
.currentCrate
+ " - Rust",
208 getNakedUrl() + window
.location
.hash
);
211 getQueryStringParams: function() {
213 window
.location
.search
.substring(1).split("&").
215 var pair
= s
.split("=");
216 params
[decodeURIComponent(pair
[0])] =
217 typeof pair
[1] === "undefined" ? null : decodeURIComponent(pair
[1]);
221 putBackSearch: function(search_input
) {
222 var search
= searchState
.outputElement();
223 if (search_input
.value
!== "" && hasClass(search
, "hidden")) {
224 searchState
.showResults(search
);
225 if (searchState
.browserSupportsHistoryApi()) {
226 var extra
= "?search=" + encodeURIComponent(search_input
.value
);
227 history
.replaceState(search_input
.value
, "",
228 getNakedUrl() + extra
+ window
.location
.hash
);
230 document
.title
= searchState
.title
;
233 browserSupportsHistoryApi: function() {
234 return window
.history
&& typeof window
.history
.pushState
=== "function";
237 var search_input
= searchState
.input
;
238 if (!searchState
.input
) {
241 function loadScript(url
) {
242 var script
= document
.createElement('script');
244 document
.head
.append(script
);
247 var searchLoaded
= false;
248 function loadSearch() {
251 loadScript(window
.searchJS
);
252 loadScript(window
.searchIndexJS
);
256 search_input
.addEventListener("focus", function() {
257 searchState
.putBackSearch(this);
258 search_input
.origPlaceholder
= searchState
.input
.placeholder
;
259 search_input
.placeholder
= "Type your search here.";
262 search_input
.addEventListener("blur", function() {
263 search_input
.placeholder
= searchState
.input
.origPlaceholder
;
266 search_input
.removeAttribute('disabled');
268 // `crates{version}.js` should always be loaded before this script, so we can use it
270 searchState
.addCrateDropdown(window
.ALL_CRATES
);
271 var params
= searchState
.getQueryStringParams();
272 if (params
.search
!== undefined) {
273 var search
= searchState
.outputElement();
274 search
.innerHTML
= "<h3 style=\"text-align: center;\">" +
275 searchState
.loadingText
+ "</h3>";
276 searchState
.showResults(search
);
280 addCrateDropdown: function(crates
) {
281 var elem
= document
.getElementById("crate-search");
286 var savedCrate
= getSettingValue("saved-filter-crate");
287 for (var i
= 0, len
= crates
.length
; i
< len
; ++i
) {
288 var option
= document
.createElement("option");
289 option
.value
= crates
[i
];
290 option
.innerText
= crates
[i
];
291 elem
.appendChild(option
);
292 // Set the crate filter from saved storage, if the current page has the saved crate
295 // If not, ignore the crate filter -- we want to support filtering for crates on
296 // sites like doc.rust-lang.org where the crates may differ from page to page while
299 if (crates
[i
] === savedCrate
) {
300 elem
.value
= savedCrate
;
306 function getPageId() {
307 if (window
.location
.hash
) {
308 var tmp
= window
.location
.hash
.replace(/^#/, "");
309 if (tmp
.length
> 0) {
316 function showSidebar() {
317 var elems
= document
.getElementsByClassName("sidebar-elems")[0];
319 addClass(elems
, "show-it");
321 var sidebar
= document
.getElementsByClassName("sidebar")[0];
323 addClass(sidebar
, "mobile");
324 var filler
= document
.getElementById("sidebar-filler");
326 var div
= document
.createElement("div");
327 div
.id
= "sidebar-filler";
328 sidebar
.appendChild(div
);
333 function hideSidebar() {
334 var elems
= document
.getElementsByClassName("sidebar-elems")[0];
336 removeClass(elems
, "show-it");
338 var sidebar
= document
.getElementsByClassName("sidebar")[0];
339 removeClass(sidebar
, "mobile");
340 var filler
= document
.getElementById("sidebar-filler");
344 document
.getElementsByTagName("body")[0].style
.marginTop
= "";
347 var toggleAllDocsId
= "toggle-all-docs";
348 var main
= document
.getElementById("main");
351 function handleHashes(ev
) {
353 var search
= searchState
.outputElement();
354 if (ev
!== null && search
&& !hasClass(search
, "hidden") && ev
.newURL
) {
355 // This block occurs when clicking on an element in the navbar while
357 searchState
.hideResults(search
);
358 var hash
= ev
.newURL
.slice(ev
.newURL
.indexOf("#") + 1);
359 if (searchState
.browserSupportsHistoryApi()) {
360 // `window.location.search`` contains all the query parameters, not just `search`.
361 history
.replaceState(hash
, "",
362 getNakedUrl() + window
.location
.search
+ "#" + hash
);
364 elem
= document
.getElementById(hash
);
366 elem
.scrollIntoView();
369 // This part is used in case an element is not visible.
370 if (savedHash
!== window
.location
.hash
) {
371 savedHash
= window
.location
.hash
;
372 if (savedHash
.length
=== 0) {
375 expandSection(savedHash
.slice(1)); // we remove the '#'
379 function onHashChange(ev
) {
380 // If we're in mobile mode, we should hide the sidebar in any case.
385 function openParentDetails(elem
) {
387 if (elem
.tagName
=== "DETAILS") {
390 elem
= elem
.parentNode
;
394 function expandSection(id
) {
395 openParentDetails(document
.getElementById(id
));
398 function getHelpElement(build
) {
402 return document
.getElementById("help");
405 function displayHelp(display
, ev
, help
) {
407 help
= help
? help
: getHelpElement(true);
408 if (hasClass(help
, "hidden")) {
410 removeClass(help
, "hidden");
411 addClass(document
.body
, "blur");
414 // No need to build the help popup if we want to hide it in case it hasn't been
416 help
= help
? help
: getHelpElement(false);
417 if (help
&& !hasClass(help
, "hidden")) {
419 addClass(help
, "hidden");
420 removeClass(document
.body
, "blur");
425 function handleEscape(ev
) {
426 var help
= getHelpElement(false);
427 var search
= searchState
.outputElement();
428 if (help
&& !hasClass(help
, "hidden")) {
429 displayHelp(false, ev
, help
);
430 } else if (search
&& !hasClass(search
, "hidden")) {
431 searchState
.clearInputTimeout();
433 searchState
.hideResults(search
);
435 searchState
.defocus();
436 hideThemeButtonState();
439 var disableShortcuts
= getSettingValue("disable-shortcuts") === "true";
440 function handleShortcut(ev
) {
441 // Don't interfere with browser shortcuts
442 if (ev
.ctrlKey
|| ev
.altKey
|| ev
.metaKey
|| disableShortcuts
) {
446 if (document
.activeElement
.tagName
=== "INPUT") {
447 switch (getVirtualKey(ev
)) {
453 switch (getVirtualKey(ev
)) {
460 displayHelp(false, ev
);
472 displayHelp(true, ev
);
477 displayHelp(false, ev
);
479 var themePicker
= getThemePickerElement();
485 if (getThemePickerElement().parentNode
.contains(ev
.target
)) {
486 handleThemeKeyDown(ev
);
492 function handleThemeKeyDown(ev
) {
493 var active
= document
.activeElement
;
494 var themes
= getThemesElement();
495 switch (getVirtualKey(ev
)) {
498 if (active
.previousElementSibling
&& ev
.target
.id
!== THEME_PICKER_ELEMENT_ID
) {
499 active
.previousElementSibling
.focus();
501 showThemeButtonState();
502 themes
.lastElementChild
.focus();
507 if (active
.nextElementSibling
&& ev
.target
.id
!== THEME_PICKER_ELEMENT_ID
) {
508 active
.nextElementSibling
.focus();
510 showThemeButtonState();
511 themes
.firstElementChild
.focus();
517 if (ev
.target
.id
=== THEME_PICKER_ELEMENT_ID
&& themes
.style
.display
=== "none") {
519 showThemeButtonState();
520 themes
.firstElementChild
.focus();
525 themes
.firstElementChild
.focus();
529 themes
.lastElementChild
.focus();
531 // The escape key is handled in handleEscape, not here,
532 // so that pressing escape will close the menu even if it isn't focused
536 document
.addEventListener("keypress", handleShortcut
);
537 document
.addEventListener("keydown", handleShortcut
);
540 var x
= document
.getElementsByClassName("version-selector");
542 x
[0].onchange = function() {
544 url
= document
.location
.href
,
546 len
= window
.rootPath
.match(/\.\.\//g).length
+ 1;
548 for (i
= 0; i
< len
; ++i
) {
549 match
= url
.match(/\/[^/]*$/);
551 stripped
= match
[0] + stripped
;
553 url
= url
.substring(0, url
.length
- match
[0].length
);
556 var selectedVersion
= document
.getElementsByClassName("version-selector")[0].value
;
557 url
+= "/" + selectedVersion
+ stripped
;
559 document
.location
.href
= url
;
564 // delayed sidebar rendering.
565 window
.initSidebarItems = function(items
) {
566 var sidebar
= document
.getElementsByClassName("sidebar-elems")[0];
567 var current
= window
.sidebarCurrent
;
569 function addSidebarCrates(crates
) {
570 if (!hasClass(document
.body
, "crate")) {
571 // We only want to list crates on the crate page.
574 // Draw a convenient sidebar of known crates if we have a listing
575 var div
= document
.createElement("div");
576 div
.className
= "block crate";
577 div
.innerHTML
= "<h3>Crates</h3>";
578 var ul
= document
.createElement("ul");
581 for (var i
= 0; i
< crates
.length
; ++i
) {
583 if (window
.rootPath
!== "./" && crates
[i
] === window
.currentCrate
) {
586 var link
= document
.createElement("a");
587 link
.href
= window
.rootPath
+ crates
[i
] + "/index.html";
588 link
.className
= klass
;
589 link
.textContent
= crates
[i
];
591 var li
= document
.createElement("li");
592 li
.appendChild(link
);
595 sidebar
.appendChild(div
);
598 function block(shortty
, longty
) {
599 var filtered
= items
[shortty
];
604 var div
= document
.createElement("div");
605 div
.className
= "block " + shortty
;
606 var h3
= document
.createElement("h3");
607 h3
.textContent
= longty
;
609 var ul
= document
.createElement("ul");
611 for (var i
= 0, len
= filtered
.length
; i
< len
; ++i
) {
612 var item
= filtered
[i
];
614 var desc
= item
[1]; // can be null
617 if (name
=== current
.name
&& shortty
=== current
.ty
) {
621 if (shortty
=== "mod") {
622 path
= name
+ "/index.html";
624 path
= shortty
+ "." + name
+ ".html";
626 var link
= document
.createElement("a");
627 link
.href
= current
.relpath
+ path
;
629 link
.className
= klass
;
630 link
.textContent
= name
;
631 var li
= document
.createElement("li");
632 li
.appendChild(link
);
636 sidebar
.appendChild(div
);
640 var isModule
= hasClass(document
.body
, "mod");
642 block("primitive", "Primitive Types");
643 block("mod", "Modules");
644 block("macro", "Macros");
645 block("struct", "Structs");
646 block("enum", "Enums");
647 block("union", "Unions");
648 block("constant", "Constants");
649 block("static", "Statics");
650 block("trait", "Traits");
651 block("fn", "Functions");
652 block("type", "Type Definitions");
653 block("foreigntype", "Foreign Types");
654 block("keyword", "Keywords");
655 block("traitalias", "Trait Aliases");
658 // `crates{version}.js` should always be loaded before this script, so we can use
660 addSidebarCrates(window
.ALL_CRATES
);
664 window
.register_implementors = function(imp
) {
665 var implementors
= document
.getElementById("implementors-list");
666 var synthetic_implementors
= document
.getElementById("synthetic-implementors-list");
668 if (synthetic_implementors
) {
669 // This `inlined_types` variable is used to avoid having the same implementation
670 // showing up twice. For example "String" in the "Sync" doc page.
672 // By the way, this is only used by and useful for traits implemented automatically
673 // (like "Send" and "Sync").
674 var inlined_types
= new Set();
675 onEachLazy(synthetic_implementors
.getElementsByClassName("impl"), function(el
) {
676 var aliases
= el
.getAttribute("data-aliases");
680 aliases
.split(",").forEach(function(alias
) {
681 inlined_types
.add(alias
);
686 var currentNbImpls
= implementors
.getElementsByClassName("impl").length
;
687 var traitName
= document
.querySelector("h1.fqn > .in-band > .trait").textContent
;
688 var baseIdName
= "impl-" + traitName
+ "-";
689 var libs
= Object
.getOwnPropertyNames(imp
);
690 for (var i
= 0, llength
= libs
.length
; i
< llength
; ++i
) {
691 if (libs
[i
] === window
.currentCrate
) { continue; }
692 var structs
= imp
[libs
[i
]];
695 for (var j
= 0, slength
= structs
.length
; j
< slength
; ++j
) {
696 var struct
= structs
[j
];
698 var list
= struct
.synthetic
? synthetic_implementors
: implementors
;
700 if (struct
.synthetic
) {
701 for (var k
= 0, stlength
= struct
.types
.length
; k
< stlength
; k
++) {
702 if (inlined_types
.has(struct
.types
[k
])) {
703 continue struct_loop
;
705 inlined_types
.add(struct
.types
[k
]);
709 var code
= document
.createElement("h3");
710 code
.innerHTML
= struct
.text
;
711 addClass(code
, "code-header");
712 addClass(code
, "in-band");
714 onEachLazy(code
.getElementsByTagName("a"), function(elem
) {
715 var href
= elem
.getAttribute("href");
717 if (href
&& href
.indexOf("http") !== 0) {
718 elem
.setAttribute("href", window
.rootPath
+ href
);
722 var currentId
= baseIdName
+ currentNbImpls
;
723 var anchor
= document
.createElement("a");
724 anchor
.href
= "#" + currentId
;
725 addClass(anchor
, "anchor");
727 var display
= document
.createElement("div");
728 display
.id
= currentId
;
729 addClass(display
, "impl");
730 display
.appendChild(anchor
);
731 display
.appendChild(code
);
732 list
.appendChild(display
);
737 if (window
.pending_implementors
) {
738 window
.register_implementors(window
.pending_implementors
);
741 function labelForToggleButton(sectionIsCollapsed
) {
742 if (sectionIsCollapsed
) {
743 // button will expand the section
746 // button will collapse the section
747 // note that this text is also set in the HTML template in ../render/mod.rs
748 return "\u2212"; // "\u2212" is "−" minus sign
751 function toggleAllDocs() {
752 var innerToggle
= document
.getElementById(toggleAllDocsId
);
756 var sectionIsCollapsed
= false;
757 if (hasClass(innerToggle
, "will-expand")) {
758 removeClass(innerToggle
, "will-expand");
759 onEachLazy(document
.getElementsByClassName("rustdoc-toggle"), function(e
) {
760 if (!hasClass(e
, "type-contents-toggle")) {
764 innerToggle
.title
= "collapse all docs";
766 addClass(innerToggle
, "will-expand");
767 onEachLazy(document
.getElementsByClassName("rustdoc-toggle"), function(e
) {
768 if (e
.parentNode
.id
!== "main" ||
769 (!hasClass(e
, "implementors-toggle") &&
770 !hasClass(e
, "type-contents-toggle")))
775 sectionIsCollapsed
= true;
776 innerToggle
.title
= "expand all docs";
778 innerToggle
.children
[0].innerText
= labelForToggleButton(sectionIsCollapsed
);
781 function insertAfter(newNode
, referenceNode
) {
782 referenceNode
.parentNode
.insertBefore(newNode
, referenceNode
.nextSibling
);
786 var toggles
= document
.getElementById(toggleAllDocsId
);
788 toggles
.onclick
= toggleAllDocs
;
791 var hideMethodDocs
= getSettingValue("auto-hide-method-docs") === "true";
792 var hideImplementations
= getSettingValue("auto-hide-trait-implementations") === "true";
793 var hideLargeItemContents
= getSettingValue("auto-hide-large-items") !== "false";
795 function setImplementorsTogglesOpen(id
, open
) {
796 var list
= document
.getElementById(id
);
798 onEachLazy(list
.getElementsByClassName("implementors-toggle"), function(e
) {
804 if (hideImplementations
) {
805 setImplementorsTogglesOpen("trait-implementations-list", false);
806 setImplementorsTogglesOpen("blanket-implementations-list", false);
809 onEachLazy(document
.getElementsByClassName("rustdoc-toggle"), function (e
) {
810 if (!hideLargeItemContents
&& hasClass(e
, "type-contents-toggle")) {
813 if (hideMethodDocs
&& hasClass(e
, "method-toggle")) {
819 var pageId
= getPageId();
820 if (pageId
!== null) {
821 expandSection(pageId
);
826 // To avoid checking on "rustdoc-line-numbers" value on every loop...
827 var lineNumbersFunc = function() {};
828 if (getSettingValue("line-numbers") === "true") {
829 lineNumbersFunc = function(x
) {
830 var count
= x
.textContent
.split("\n").length
;
832 for (var i
= 0; i
< count
; ++i
) {
835 var node
= document
.createElement("pre");
836 addClass(node
, "line-number");
837 node
.innerHTML
= elems
.join("\n");
838 x
.parentNode
.insertBefore(node
, x
);
841 onEachLazy(document
.getElementsByClassName("rust-example-rendered"), function(e
) {
842 if (hasClass(e
, "compile_fail")) {
843 e
.addEventListener("mouseover", function() {
844 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "#f00";
846 e
.addEventListener("mouseout", function() {
847 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "";
849 } else if (hasClass(e
, "ignore")) {
850 e
.addEventListener("mouseover", function() {
851 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "#ff9200";
853 e
.addEventListener("mouseout", function() {
854 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "";
861 function handleClick(id
, f
) {
862 var elem
= document
.getElementById(id
);
864 elem
.addEventListener("click", f
);
867 handleClick("help-button", function(ev
) {
868 displayHelp(true, ev
);
871 onEachLazy(document
.getElementsByTagName("a"), function(el
) {
872 // For clicks on internal links (<A> tags with a hash property), we expand the section we're
873 // jumping to *before* jumping there. We can't do this in onHashChange, because it changes
874 // the height of the document so we wind up scrolled to the wrong place.
876 el
.addEventListener("click", function() {
877 expandSection(el
.hash
.slice(1));
882 onEachLazy(document
.getElementsByClassName("notable-traits"), function(e
) {
883 e
.onclick = function() {
884 this.getElementsByClassName('notable-traits-tooltiptext')[0]
885 .classList
.toggle("force-tooltip");
889 var sidebar_menu
= document
.getElementsByClassName("sidebar-menu")[0];
891 sidebar_menu
.onclick = function() {
892 var sidebar
= document
.getElementsByClassName("sidebar")[0];
893 if (hasClass(sidebar
, "mobile")) {
901 var buildHelperPopup = function() {
902 var popup
= document
.createElement("aside");
903 addClass(popup
, "hidden");
906 popup
.addEventListener("click", function(ev
) {
907 if (ev
.target
=== popup
) {
908 // Clicked the blurred zone outside the help popup; dismiss help.
909 displayHelp(false, ev
);
913 var book_info
= document
.createElement("span");
914 book_info
.innerHTML
= "You can find more information in \
915 <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
917 var container
= document
.createElement("div");
919 ["?", "Show this help dialog"],
920 ["S", "Focus the search field"],
921 ["T", "Focus the theme picker menu"],
922 ["↑", "Move up in search results"],
923 ["↓", "Move down in search results"],
924 ["← / →", "Switch result tab (when results focused)"],
925 ["⏎", "Go to active search result"],
926 ["+", "Expand all sections"],
927 ["-", "Collapse all sections"],
931 .map(function(y
, index
) {
932 return (index
& 1) === 0 ? "<kbd>" + y
+ "</kbd>" : " " + y
+ " ";
934 .join("") + "</dt><dd>" + x
[1] + "</dd>";
936 var div_shortcuts
= document
.createElement("div");
937 addClass(div_shortcuts
, "shortcuts");
938 div_shortcuts
.innerHTML
= "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts
+ "</dl></div>";
941 "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
942 restrict the search to a given item kind.",
943 "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
944 <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
945 and <code>const</code>.",
946 "Search functions by type signature (e.g., <code>vec -> usize</code> or \
947 <code>* -> vec</code>)",
948 "Search multiple things at once by splitting your query with comma (e.g., \
949 <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
950 "You can look for items with an exact name by putting double quotes around \
951 your request: <code>\"string\"</code>",
952 "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
954 return "<p>" + x
+ "</p>";
956 var div_infos
= document
.createElement("div");
957 addClass(div_infos
, "infos");
958 div_infos
.innerHTML
= "<h2>Search Tricks</h2>" + infos
;
960 container
.appendChild(book_info
);
961 container
.appendChild(div_shortcuts
);
962 container
.appendChild(div_infos
);
964 popup
.appendChild(container
);
965 insertAfter(popup
, searchState
.outputElement());
966 // So that it's only built once and then it'll do nothing when called!
967 buildHelperPopup = function() {};
971 window
.addEventListener("hashchange", onHashChange
);
976 var reset_button_timeout
= null;
978 window
.copy_path = function(but
) {
979 var parent
= but
.parentElement
;
982 onEach(parent
.childNodes
, function(child
) {
983 if (child
.tagName
=== 'A') {
984 path
.push(child
.textContent
);
988 var el
= document
.createElement('textarea');
989 el
.value
= path
.join('::');
990 el
.setAttribute('readonly', '');
991 // To not make it appear on the screen.
992 el
.style
.position
= 'absolute';
993 el
.style
.left
= '-9999px';
995 document
.body
.appendChild(el
);
997 document
.execCommand('copy');
998 document
.body
.removeChild(el
);
1000 // There is always one children, but multiple childNodes.
1001 but
.children
[0].style
.display
= 'none';
1004 if (but
.childNodes
.length
< 2) {
1005 tmp
= document
.createTextNode('✓');
1006 but
.appendChild(tmp
);
1008 onEachLazy(but
.childNodes
, function(e
) {
1009 if (e
.nodeType
=== Node
.TEXT_NODE
) {
1014 tmp
.textContent
= '✓';
1017 if (reset_button_timeout
!== null) {
1018 window
.clearTimeout(reset_button_timeout
);
1021 function reset_button() {
1022 tmp
.textContent
= '';
1023 reset_button_timeout
= null;
1024 but
.children
[0].style
.display
= "";
1027 reset_button_timeout
= window
.setTimeout(reset_button
, 1000);