// Local js definitions: /* global addClass, getSettingValue, hasClass, searchState */ /* global onEach, onEachLazy, removeClass */ /* global switchTheme, useSystemTheme */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { position = position || 0; return this.indexOf(searchString, position) === position; }; } if (!String.prototype.endsWith) { String.prototype.endsWith = function(suffix, length) { var l = length || this.length; return this.indexOf(suffix, l - suffix.length) !== -1; }; } if (!DOMTokenList.prototype.add) { DOMTokenList.prototype.add = function(className) { if (className && !hasClass(this, className)) { if (this.className && this.className.length > 0) { this.className += " " + className; } else { this.className = className; } } }; } if (!DOMTokenList.prototype.remove) { DOMTokenList.prototype.remove = function(className) { if (className && this.className) { this.className = (" " + this.className + " ").replace(" " + className + " ", " ") .trim(); } }; } // Get a value from the rustdoc-vars div, which is used to convey data from // Rust to the JS. If there is no such element, return null. function getVar(name) { var el = document.getElementById("rustdoc-vars"); if (el) { return el.attributes["data-" + name].value; } else { return null; } } // Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL // for a resource under the root-path, with the resource-suffix. function resourcePath(basename, extension) { return getVar("root-path") + basename + getVar("resource-suffix") + extension; } (function () { window.rootPath = getVar("root-path"); window.currentCrate = getVar("current-crate"); window.searchJS = resourcePath("search", ".js"); window.searchIndexJS = resourcePath("search-index", ".js"); var sidebarVars = document.getElementById("sidebar-vars"); if (sidebarVars) { window.sidebarCurrent = { name: sidebarVars.attributes["data-name"].value, ty: sidebarVars.attributes["data-ty"].value, relpath: sidebarVars.attributes["data-relpath"].value, }; // FIXME: It would be nicer to generate this text content directly in HTML, // but with the current code it's hard to get the right information in the right place. var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location"); var locationTitle = document.querySelector(".sidebar h2.location"); if (mobileLocationTitle && locationTitle) { mobileLocationTitle.innerHTML = locationTitle.innerHTML; } } }()); // Gets the human-readable string for the virtual-key code of the // given KeyboardEvent, ev. // // This function is meant as a polyfill for KeyboardEvent#key, // since it is not supported in IE 11 or Chrome for Android. We also test for // KeyboardEvent#keyCode because the handleShortcut handler is // also registered for the keydown event, because Blink doesn't fire // keypress on hitting the Escape key. // // So I guess you could say things are getting pretty interoperable. function getVirtualKey(ev) { if ("key" in ev && typeof ev.key != "undefined") { return ev.key; } var c = ev.charCode || ev.keyCode; if (c == 27) { return "Escape"; } return String.fromCharCode(c); } var THEME_PICKER_ELEMENT_ID = "theme-picker"; var THEMES_ELEMENT_ID = "theme-choices"; var MAIN_ID = "main-content"; function getThemesElement() { return document.getElementById(THEMES_ELEMENT_ID); } function getThemePickerElement() { return document.getElementById(THEME_PICKER_ELEMENT_ID); } // Returns the current URL without any query parameter or hash. function getNakedUrl() { return window.location.href.split("?")[0].split("#")[0]; } function showThemeButtonState() { var themePicker = getThemePickerElement(); var themeChoices = getThemesElement(); themeChoices.style.display = "block"; themePicker.style.borderBottomRightRadius = "0"; themePicker.style.borderBottomLeftRadius = "0"; } function hideThemeButtonState() { var themePicker = getThemePickerElement(); var themeChoices = getThemesElement(); themeChoices.style.display = "none"; themePicker.style.borderBottomRightRadius = "3px"; themePicker.style.borderBottomLeftRadius = "3px"; } // Set up the theme picker list. (function () { if (!document.location.href.startsWith("file:///")) { return; } var themeChoices = getThemesElement(); var themePicker = getThemePickerElement(); var availableThemes = getVar("themes").split(","); removeClass(themeChoices.parentElement, "hidden"); function switchThemeButtonState() { if (themeChoices.style.display === "block") { hideThemeButtonState(); } else { showThemeButtonState(); } } function handleThemeButtonsBlur(e) { var active = document.activeElement; var related = e.relatedTarget; if (active.id !== THEME_PICKER_ELEMENT_ID && (!active.parentNode || active.parentNode.id !== THEMES_ELEMENT_ID) && (!related || (related.id !== THEME_PICKER_ELEMENT_ID && (!related.parentNode || related.parentNode.id !== THEMES_ELEMENT_ID)))) { hideThemeButtonState(); } } themePicker.onclick = switchThemeButtonState; themePicker.onblur = handleThemeButtonsBlur; availableThemes.forEach(function(item) { var but = document.createElement("button"); but.textContent = item; but.onclick = function() { switchTheme(window.currentTheme, window.mainTheme, item, true); useSystemTheme(false); }; but.onblur = handleThemeButtonsBlur; themeChoices.appendChild(but); }); }()); (function() { "use strict"; window.searchState = { loadingText: "Loading search results...", input: document.getElementsByClassName("search-input")[0], outputElement: function() { return document.getElementById("search"); }, title: document.title, titleBeforeSearch: document.title, timeout: null, // On the search screen, so you remain on the last tab you opened. // // 0 for "In Names" // 1 for "In Parameters" // 2 for "In Return Types" currentTab: 0, // tab and back preserves the element that was focused. focusedByTab: [null, null, null], clearInputTimeout: function() { if (searchState.timeout !== null) { clearTimeout(searchState.timeout); searchState.timeout = null; } }, // Sets the focus on the search bar at the top of the page focus: function() { searchState.input.focus(); }, // Removes the focus from the search bar. defocus: function() { searchState.input.blur(); }, showResults: function(search) { if (search === null || typeof search === 'undefined') { search = searchState.outputElement(); } addClass(main, "hidden"); removeClass(search, "hidden"); searchState.mouseMovedAfterSearch = false; document.title = searchState.title; }, hideResults: function(search) { if (search === null || typeof search === 'undefined') { search = searchState.outputElement(); } addClass(search, "hidden"); removeClass(main, "hidden"); document.title = searchState.titleBeforeSearch; // We also remove the query parameter from the URL. if (searchState.browserSupportsHistoryApi()) { history.replaceState(null, window.currentCrate + " - Rust", getNakedUrl() + window.location.hash); } }, getQueryStringParams: function() { var params = {}; window.location.search.substring(1).split("&"). map(function(s) { var pair = s.split("="); params[decodeURIComponent(pair[0])] = typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]); }); return params; }, browserSupportsHistoryApi: function() { return window.history && typeof window.history.pushState === "function"; }, setup: function() { var search_input = searchState.input; if (!searchState.input) { return; } function loadScript(url) { var script = document.createElement('script'); script.src = url; document.head.append(script); } var searchLoaded = false; function loadSearch() { if (!searchLoaded) { searchLoaded = true; loadScript(window.searchJS); loadScript(window.searchIndexJS); } } search_input.addEventListener("focus", function() { search_input.origPlaceholder = search_input.placeholder; search_input.placeholder = "Type your search here."; loadSearch(); }); if (search_input.value != '') { loadSearch(); } var params = searchState.getQueryStringParams(); if (params.search !== undefined) { var search = searchState.outputElement(); search.innerHTML = "

" + searchState.loadingText + "

"; searchState.showResults(search); loadSearch(); } }, }; function getPageId() { if (window.location.hash) { var tmp = window.location.hash.replace(/^#/, ""); if (tmp.length > 0) { return tmp; } } return null; } var toggleAllDocsId = "toggle-all-docs"; var main = document.getElementById(MAIN_ID); var savedHash = ""; function handleHashes(ev) { var elem; var search = searchState.outputElement(); if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { // This block occurs when clicking on an element in the navbar while // in a search. searchState.hideResults(search); var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1); if (searchState.browserSupportsHistoryApi()) { // `window.location.search`` contains all the query parameters, not just `search`. history.replaceState(null, "", getNakedUrl() + window.location.search + "#" + hash); } elem = document.getElementById(hash); if (elem) { elem.scrollIntoView(); } } // This part is used in case an element is not visible. if (savedHash !== window.location.hash) { savedHash = window.location.hash; if (savedHash.length === 0) { return; } expandSection(savedHash.slice(1)); // we remove the '#' } } function onHashChange(ev) { // If we're in mobile mode, we should hide the sidebar in any case. var sidebar = document.getElementsByClassName("sidebar")[0]; removeClass(sidebar, "shown"); handleHashes(ev); } function openParentDetails(elem) { while (elem) { if (elem.tagName === "DETAILS") { elem.open = true; } elem = elem.parentNode; } } function expandSection(id) { openParentDetails(document.getElementById(id)); } function getHelpElement(build) { if (build) { buildHelperPopup(); } return document.getElementById("help"); } /** * Show the help popup. * * @param {boolean} display - Whether to show or hide the popup * @param {Event} ev - The event that triggered this call * @param {Element} [help] - The help element if it already exists */ function displayHelp(display, ev, help) { if (display) { help = help ? help : getHelpElement(true); if (hasClass(help, "hidden")) { ev.preventDefault(); removeClass(help, "hidden"); addClass(document.body, "blur"); } } else { // No need to build the help popup if we want to hide it in case it hasn't been // built yet... help = help ? help : getHelpElement(false); if (help && !hasClass(help, "hidden")) { ev.preventDefault(); addClass(help, "hidden"); removeClass(document.body, "blur"); } } } function handleEscape(ev) { var help = getHelpElement(false); var search = searchState.outputElement(); if (help && !hasClass(help, "hidden")) { displayHelp(false, ev, help); } else if (search && !hasClass(search, "hidden")) { searchState.clearInputTimeout(); ev.preventDefault(); searchState.hideResults(search); } searchState.defocus(); hideThemeButtonState(); } var disableShortcuts = getSettingValue("disable-shortcuts") === "true"; function handleShortcut(ev) { // Don't interfere with browser shortcuts if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { return; } if (document.activeElement.tagName === "INPUT") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); break; } } else { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); break; case "s": case "S": displayHelp(false, ev); ev.preventDefault(); searchState.focus(); break; case "+": case "-": ev.preventDefault(); toggleAllDocs(); break; case "?": displayHelp(true, ev); break; case "t": case "T": displayHelp(false, ev); ev.preventDefault(); var themePicker = getThemePickerElement(); themePicker.click(); themePicker.focus(); break; default: if (getThemePickerElement().parentNode.contains(ev.target)) { handleThemeKeyDown(ev); } } } } function handleThemeKeyDown(ev) { var active = document.activeElement; var themes = getThemesElement(); switch (getVirtualKey(ev)) { case "ArrowUp": ev.preventDefault(); if (active.previousElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { active.previousElementSibling.focus(); } else { showThemeButtonState(); themes.lastElementChild.focus(); } break; case "ArrowDown": ev.preventDefault(); if (active.nextElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { active.nextElementSibling.focus(); } else { showThemeButtonState(); themes.firstElementChild.focus(); } break; case "Enter": case "Return": case "Space": if (ev.target.id === THEME_PICKER_ELEMENT_ID && themes.style.display === "none") { ev.preventDefault(); showThemeButtonState(); themes.firstElementChild.focus(); } break; case "Home": ev.preventDefault(); themes.firstElementChild.focus(); break; case "End": ev.preventDefault(); themes.lastElementChild.focus(); break; // The escape key is handled in handleEscape, not here, // so that pressing escape will close the menu even if it isn't focused } } document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); (function() { var x = document.getElementsByClassName("version-selector"); if (x.length > 0) { x[0].onchange = function() { var i, match, url = document.location.href, stripped = "", len = window.rootPath.match(/\.\.\//g).length + 1; for (i = 0; i < len; ++i) { match = url.match(/\/[^/]*$/); if (i < len - 1) { stripped = match[0] + stripped; } url = url.substring(0, url.length - match[0].length); } var selectedVersion = document.getElementsByClassName("version-selector")[0].value; url += "/" + selectedVersion + stripped; document.location.href = url; }; } }()); // delayed sidebar rendering. window.initSidebarItems = function(items) { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; var others; var current = window.sidebarCurrent; function addSidebarCrates(crates) { if (!hasClass(document.body, "crate")) { // We only want to list crates on the crate page. return; } // Draw a convenient sidebar of known crates if we have a listing var div = document.createElement("div"); div.className = "block crate"; div.innerHTML = "

Crates

"; var ul = document.createElement("ul"); div.appendChild(ul); for (var i = 0; i < crates.length; ++i) { var klass = "crate"; if (window.rootPath !== "./" && crates[i] === window.currentCrate) { klass += " current"; } var link = document.createElement("a"); link.href = window.rootPath + crates[i] + "/index.html"; link.className = klass; link.textContent = crates[i]; var li = document.createElement("li"); li.appendChild(link); ul.appendChild(li); } others.appendChild(div); } /** * Append to the sidebar a "block" of links - a heading along with a list (`