src/librustdoc/html/static/js/main.js JAVASCRIPT 2,296 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,296.
1// Local js definitions:2/* global addClass, getSettingValue, hasClass, updateLocalStorage */3/* global onEachLazy, removeClass, getVar, nonnull */45"use strict";67// The amount of time that the cursor must remain still over a hover target before8// revealing a tooltip.9//10// https://www.nngroup.com/articles/timing-exposing-content/11window.RUSTDOC_TOOLTIP_HOVER_MS = 300;12window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS = 450;1314/**15 * Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL16 * for a resource under the root-path, with the resource-suffix.17 *18 * @param {string} basename19 * @param {string} extension20 */21function resourcePath(basename, extension) {22    return getVar("root-path") + basename + getVar("resource-suffix") + extension;23}2425function hideMain() {26    addClass(document.getElementById(MAIN_ID), "hidden");27    const toggle = document.getElementById("toggle-all-docs");28    if (toggle) {29        toggle.setAttribute("disabled", "disabled");30    }31}3233function showMain() {34    const main = document.getElementById(MAIN_ID);35    if (!main) {36        return;37    }38    removeClass(main, "hidden");39    const mainHeading = main.querySelector(".main-heading");40    if (mainHeading && window.searchState.rustdocToolbar) {41        if (window.searchState.rustdocToolbar.parentElement) {42            window.searchState.rustdocToolbar.parentElement.removeChild(43                window.searchState.rustdocToolbar,44            );45        }46        mainHeading.appendChild(window.searchState.rustdocToolbar);47    }48    const toggle = document.getElementById("toggle-all-docs");49    if (toggle) {50        toggle.removeAttribute("disabled");51    }52}5354window.rootPath = getVar("root-path");55window.currentCrate = getVar("current-crate");5657/**58 * Gets the human-readable string for the virtual-key code of the59 * 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 for63 * KeyboardEvent#keyCode because the handleShortcut handler is64 * also registered for the keydown event, because Blink doesn't fire65 * keypress on hitting the Escape key.66 *67 * So I guess you could say things are getting pretty interoperable.68 *69 * @param {KeyboardEvent} ev70 * @returns {string}71 */72function getVirtualKey(ev) {73    if ("key" in ev && typeof ev.key !== "undefined") {74        return ev.key;75    }7677    const c = ev.charCode || ev.keyCode;78    if (c === 27) {79        return "Escape";80    }81    return String.fromCharCode(c);82}8384const MAIN_ID = "main-content";85const ALTERNATIVE_DISPLAY_ID = "alternative-display";86const NOT_DISPLAYED_ID = "not-displayed";8788// Returns the current URL without any query parameter or hash.89function getNakedUrl() {90    return window.location.href.split("?")[0].split("#")[0];91}9293/**94 * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`95 * doesn't have a parent node.96 *97 * @param {HTMLElement} newNode98 * @param {HTMLElement & { parentNode: HTMLElement }} referenceNode99 */100function insertAfter(newNode, referenceNode) {101    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);102}103104/**105 * This function creates a new `<section>` with the given `id` and `classes` if it doesn't already106 * exist.107 *108 * More information about this in `switchDisplayedElement` documentation.109 *110 * @param {string} id111 * @param {string} classes112 */113function getOrCreateSection(id, classes) {114    let el = document.getElementById(id);115116    if (!el) {117        el = document.createElement("section");118        el.id = id;119        el.className = classes;120        // @ts-expect-error121        insertAfter(el, document.getElementById(MAIN_ID));122    }123    return el;124}125126/**127 * Returns the `<section>` element which contains the displayed element.128 *129 * @return {HTMLElement}130 */131function getAlternativeDisplayElem() {132    return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");133}134135/**136 * Returns the `<section>` element which contains the not-displayed elements.137 *138 * @return {HTMLElement}139 */140function getNotDisplayedElem() {141    return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");142}143144/**145 * To nicely switch between displayed "extra" elements (such as search results or settings menu)146 * and to alternate between the displayed and not displayed elements, we hold them in two different147 * `<section>` elements. They work in pair: one holds the hidden elements while the other148 * contains the displayed element (there can be only one at the same time!). So basically, we switch149 * elements between the two `<section>` elements.150 *151 * @param {Element|null} elemToDisplay152 */153function switchDisplayedElement(elemToDisplay) {154    const el = getAlternativeDisplayElem();155156    if (el.children.length > 0) {157        // @ts-expect-error158        getNotDisplayedElem().appendChild(el.firstElementChild);159    }160    if (elemToDisplay === null) {161        addClass(el, "hidden");162        showMain();163        return;164    }165    el.appendChild(elemToDisplay);166    hideMain();167    removeClass(el, "hidden");168169    const mainHeading = elemToDisplay.querySelector(".main-heading");170    if (mainHeading && window.searchState.rustdocToolbar) {171        if (window.searchState.rustdocToolbar.parentElement) {172            window.searchState.rustdocToolbar.parentElement.removeChild(173                window.searchState.rustdocToolbar,174            );175        }176        mainHeading.appendChild(window.searchState.rustdocToolbar);177    }178}179180function browserSupportsHistoryApi() {181    return window.history && typeof window.history.pushState === "function";182}183184/**185 * Download CSS from the web without making it the active stylesheet.186 * We use this in the settings popover so that you don't get FOUC when switching.187 *188 * @param {string} cssUrl189 */190function preLoadCss(cssUrl) {191    // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload192    const link = document.createElement("link");193    link.href = cssUrl;194    link.rel = "preload";195    link.as = "style";196    document.getElementsByTagName("head")[0].appendChild(link);197}198199(function() {200    const isHelpPage = window.location.pathname.endsWith("/help.html");201202    /**203     * Run a JavaScript file asynchronously.204     * @param {string} url205     * @param {function(): any} errorCallback206     */207    function loadScript(url, errorCallback) {208        const script = document.createElement("script");209        script.src = url;210        if (errorCallback !== undefined) {211            script.onerror = errorCallback;212        }213        document.head.append(script);214    }215216    onEachLazy(document.querySelectorAll(".settings-menu"), settingsMenu => {217        /** @param {MouseEvent} event */218        settingsMenu.querySelector("a").onclick = event => {219            if (event.ctrlKey || event.altKey || event.metaKey) {220                return;221            }222            window.hideAllModals(false);223            addClass(settingsMenu, "rotate");224            event.preventDefault();225            // Sending request for the CSS and the JS files at the same time so it will226            // hopefully be loaded when the JS will generate the settings content.227            // @ts-expect-error228            loadScript(getVar("static-root-path") + getVar("settings-js"));229            // Pre-load all theme CSS files, so that switching feels seamless.230            //231            // When loading settings.html as a standalone page, the equivalent HTML is232            // generated in context.rs.233            setTimeout(() => {234                const themes = getVar("themes").split(",");235                for (const theme of themes) {236                    // if there are no themes, do nothing237                    // "".split(",") == [""]238                    if (theme !== "") {239                        preLoadCss(getVar("root-path") + theme + ".css");240                    }241                }242            }, 0);243        };244    });245246    window.searchState = {247        rustdocToolbar: document.querySelector("rustdoc-toolbar"),248        loadingText: "Loading search results...",249        inputElement: () => {250            let el = document.getElementsByClassName("search-input")[0];251            if (!el) {252                const out = nonnull(nonnull(window.searchState.outputElement()).parentElement);253                const hdr = document.createElement("div");254                hdr.className = "main-heading search-results-main-heading";255                const params = window.searchState.getQueryStringParams();256                const autofocusParam = params.search === "" ? "autofocus" : "";257                hdr.innerHTML = `<nav class="sub">258                    <form class="search-form loading">259                        <span></span> <!-- This empty span is a hacky fix for Safari: see #93184 -->260                        <input261                            ${autofocusParam}262                            class="search-input"263                            name="search"264                            aria-label="Run search in the documentation"265                            autocomplete="off"266                            spellcheck="false"267                            placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…"268                            type="search">269                    </form>270                </nav><div class="search-switcher"></div>`;271                out.insertBefore(hdr, window.searchState.outputElement());272                el = document.getElementsByClassName("search-input")[0];273            }274            if (el instanceof HTMLInputElement) {275                return el;276            }277            return null;278        },279        containerElement: () => {280            let el = document.getElementById("search");281            if (!el) {282                el = document.createElement("section");283                el.id = "search";284                getNotDisplayedElem().appendChild(el);285            }286            return el;287        },288        outputElement: () => {289            const container = window.searchState.containerElement();290            if (!container) {291                return null;292            }293            let el = container.querySelector(".search-out");294            if (!el) {295                el = document.createElement("div");296                el.className = "search-out";297                container.appendChild(el);298            }299            return el;300        },301        title: document.title,302        titleBeforeSearch: document.title,303        timeout: null,304        // On the search screen, so you remain on the last tab you opened.305        //306        // 0 for "In Names"307        // 1 for "In Parameters"308        // 2 for "In Return Types"309        currentTab: 0,310        // tab and back preserves the element that was focused.311        focusedByTab: [null, null, null],312        clearInputTimeout: () => {313            if (window.searchState.timeout !== null) {314                clearTimeout(window.searchState.timeout);315                window.searchState.timeout = null;316            }317        },318        isDisplayed: () => {319            const container = window.searchState.containerElement();320            if (!container) {321                return false;322            }323            return !!container.parentElement && container.parentElement.id ===324                ALTERNATIVE_DISPLAY_ID;325        },326        // Sets the focus on the search bar at the top of the page327        focus: () => {328            const inputElement = window.searchState.inputElement();329            window.searchState.showResults();330            if (inputElement) {331                inputElement.focus();332                // Avoid glitch if something focuses the search button after clicking.333                requestAnimationFrame(() => inputElement.focus());334            }335        },336        // Removes the focus from the search bar.337        defocus: () => {338            nonnull(window.searchState.inputElement()).blur();339        },340        toggle: () => {341            if (window.searchState.isDisplayed()) {342                window.searchState.defocus();343                window.searchState.hideResults();344            } else {345                window.searchState.focus();346            }347        },348        showResults: () => {349            document.title = window.searchState.title;350            if (window.searchState.isDisplayed()) {351                return;352            }353            const search = window.searchState.containerElement();354            switchDisplayedElement(search);355            const btn = document.querySelector("#search-button a");356            if (browserSupportsHistoryApi() && btn instanceof HTMLAnchorElement &&357                window.searchState.getQueryStringParams().search === undefined358            ) {359                history.pushState(null, "", btn.href);360            }361            const btnLabel = document.querySelector("#search-button a span.label");362            if (btnLabel) {363                btnLabel.innerHTML = "Exit";364            }365        },366        removeQueryParameters: () => {367            // We change the document title.368            document.title = window.searchState.titleBeforeSearch;369            if (browserSupportsHistoryApi()) {370                history.replaceState(null, "", getNakedUrl() + window.location.hash);371            }372        },373        hideResults: () => {374            switchDisplayedElement(null);375            // We also remove the query parameter from the URL.376            window.searchState.removeQueryParameters();377            const btnLabel = document.querySelector("#search-button a span.label");378            if (btnLabel) {379                btnLabel.innerHTML = "Search";380            }381        },382        getQueryStringParams: () => {383            /** @type {Object.<any, string>} */384            const params = {};385            window.location.search.substring(1).split("&").386                map(s => {387                    // https://github.com/rust-lang/rust/issues/119219388                    const pair = s.split("=").map(x => x.replace(/\+/g, " "));389                    params[decodeURIComponent(pair[0])] =390                        typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);391                });392            return params;393        },394        setup: () => {395            let searchLoaded = false;396            const search_input = window.searchState.inputElement();397            if (!search_input) {398                return;399            }400            // If you're browsing the nightly docs, the page might need to be refreshed for the401            // search to work because the hash of the JS scripts might have changed.402            function sendSearchForm() {403                // @ts-expect-error404                document.getElementsByClassName("search-form")[0].submit();405            }406            function loadSearch() {407                if (!searchLoaded) {408                    searchLoaded = true;409                    window.rr_ = data => {410                        window.searchIndex = data;411                    };412                    if (!window.StringdexOnload) {413                        window.StringdexOnload = [];414                    }415                    window.StringdexOnload.push(() => {416                        loadScript(417                            getVar("static-root-path") + getVar("search-js"),418                            sendSearchForm,419                        );420                    });421                    loadScript(getVar("static-root-path") + getVar("stringdex-js"), sendSearchForm);422                    loadScript(resourcePath("search.index/root", ".js"), sendSearchForm);423                }424            }425426            search_input.addEventListener("focus", () => {427                loadSearch();428            });429430            const btn = document.getElementById("search-button");431            if (btn) {432                btn.onclick = event => {433                    if (event.ctrlKey || event.altKey || event.metaKey) {434                        return;435                    }436                    event.preventDefault();437                    window.searchState.toggle();438                    loadSearch();439                };440            }441442            // Push and pop states are used to add search results to the browser443            // history.444            if (browserSupportsHistoryApi()) {445                // Store the previous <title> so we can revert back to it later.446                const previousTitle = document.title;447448                window.addEventListener("popstate", e => {449                    const params = window.searchState.getQueryStringParams();450                    // Revert to the previous title manually since the History451                    // API ignores the title parameter.452                    document.title = previousTitle;453                    // Synchronize search bar with query string state and454                    // perform the search. This will empty the bar if there's455                    // nothing there, which lets you really go back to a456                    // previous state with nothing in the bar.457                    const inputElement = window.searchState.inputElement();458                    if (params.search !== undefined && inputElement !== null) {459                        loadSearch();460                        inputElement.value = params.search;461                        // Some browsers fire "onpopstate" for every page load462                        // (Chrome), while others fire the event only when actually463                        // popping a state (Firefox), which is why search() is464                        // called both here and at the end of the startSearch()465                        // function.466                        e.preventDefault();467                        window.searchState.showResults();468                        if (params.search === "") {469                            window.searchState.focus();470                        }471                    } else {472                        // When browsing back from search results the main page473                        // visibility must be reset.474                        window.searchState.hideResults();475                    }476                });477            }478479            // This is required in firefox to avoid this problem: Navigating to a search result480            // with the keyboard, hitting enter, and then hitting back would take you back to481            // the doc page, rather than the search that should overlay it.482            // This was an interaction between the back-forward cache and our handlers483            // that try to sync state between the URL and the search input. To work around it,484            // do a small amount of re-init on page show.485            window.onpageshow = () => {486                const inputElement = window.searchState.inputElement();487                const qSearch = window.searchState.getQueryStringParams().search;488                if (qSearch !== undefined && inputElement !== null) {489                    if (inputElement.value === "") {490                        inputElement.value = qSearch;491                    }492                    window.searchState.showResults();493                    if (qSearch === "") {494                        loadSearch();495                        window.searchState.focus();496                    }497                } else {498                    window.searchState.hideResults();499                }500            };501502            const params = window.searchState.getQueryStringParams();503            if (params.search !== undefined) {504                window.searchState.setLoadingSearch();505                loadSearch();506            }507        },508        setLoadingSearch: () => {509            const search = window.searchState.outputElement();510            nonnull(search).innerHTML = "<h3 class=\"search-loading\">" +511                window.searchState.loadingText + "</h3>";512            window.searchState.showResults();513        },514        descShards: new Map(),515        loadDesc: async function({descShard, descIndex}) {516            if (descShard.promise === null) {517                descShard.promise = new Promise((resolve, reject) => {518                    // The `resolve` callback is stored in the `descShard`519                    // object, which is itself stored in `this.descShards` map.520                    // It is called in `loadedDescShard` by the521                    // search.desc script.522                    descShard.resolve = resolve;523                    const ds = descShard;524                    const fname = `${ds.crate}-desc-${ds.shard}-`;525                    const url = resourcePath(526                        `search.desc/${descShard.crate}/${fname}`,527                        ".js",528                    );529                    loadScript(url, reject);530                });531            }532            const list = await descShard.promise;533            return list[descIndex];534        },535        loadedDescShard: function(crate, shard, data) {536            // If loadedDescShard gets called, then the library must have been declared.537            // @ts-expect-error538            this.descShards.get(crate)[shard].resolve(data.split("\n"));539        },540    };541542    const toggleAllDocsId = "toggle-all-docs";543    let savedHash = "";544545    /**546     * @param {HashChangeEvent|null} ev547     */548    function handleHashes(ev) {549        if (ev !== null && window.searchState.isDisplayed() && ev.newURL) {550            // This block occurs when clicking on an element in the navbar while551            // in a search.552            switchDisplayedElement(null);553            const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);554            if (browserSupportsHistoryApi()) {555                // `window.location.search`` contains all the query parameters, not just `search`.556                history.replaceState(null, "",557                    getNakedUrl() + window.location.search + "#" + hash);558            }559            const elem = document.getElementById(hash);560            if (elem) {561                elem.scrollIntoView();562            }563        }564        // This part is used in case an element is not visible.565        const pageId = window.location.hash.replace(/^#/, "");566        if (savedHash !== pageId) {567            savedHash = pageId;568            if (pageId !== "") {569                expandSection(pageId);570            }571        }572        if (savedHash.startsWith("impl-")) {573            // impl-disambiguated links, used by the search engine574            // format: impl-X[-for-Y]/method.WHATEVER575            // turn this into method.WHATEVER[-NUMBER]576            const splitAt = savedHash.indexOf("/");577            if (splitAt !== -1) {578                const implId = savedHash.slice(0, splitAt);579                const assocId = savedHash.slice(splitAt + 1);580                const implElems = document.querySelectorAll(581                    `details > summary > section[id^="${implId}"]`,582                );583                onEachLazy(implElems, implElem => {584                    const numbered = /^(.+?)-([0-9]+)$/.exec(implElem.id);585                    if (implElem.id !== implId && (!numbered || numbered[1] !== implId)) {586                        return false;587                    }588                    return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(589                        `[id^="${assocId}"]`),590                        item => {591                            const numbered = /^(.+?)-([0-9]+)$/.exec(item.id);592                            if (item.id === assocId || (numbered && numbered[1] === assocId)) {593                                openParentDetails(item);594                                item.scrollIntoView();595                                // Let the section expand itself before trying to highlight596                                setTimeout(() => {597                                    window.location.replace("#" + item.id);598                                }, 0);599                                return true;600                            }601                        },602                    );603                });604            }605        }606    }607608    /**609     * @param {HashChangeEvent|null} ev610     */611    function onHashChange(ev) {612        // If we're in mobile mode, we should hide the sidebar in any case.613        hideSidebar();614        handleHashes(ev);615    }616617    /**618     * @param {HTMLElement|null} elem619     */620    function openParentDetails(elem) {621        while (elem) {622            if (elem instanceof HTMLDetailsElement) {623                elem.open = true;624            }625            elem = elem.parentElement;626        }627    }628629    /**630     * @param {string} id631     */632    function expandSection(id) {633        openParentDetails(document.getElementById(id));634    }635636    /**637     * @param {KeyboardEvent} ev638     */639    function handleEscape(ev) {640        window.searchState.clearInputTimeout();641        window.searchState.hideResults();642        ev.preventDefault();643        window.searchState.defocus();644        window.hideAllModals(true); // true = reset focus for tooltips645    }646647    /**648     * @param {KeyboardEvent} ev649     */650    function handleShortcut(ev) {651        // Don't interfere with browser shortcuts652        const disableShortcuts = getSettingValue("disable-shortcuts") === "true";653        if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {654            return;655        }656657        if (document.activeElement &&658            document.activeElement instanceof HTMLInputElement &&659            document.activeElement.type !== "checkbox" &&660            document.activeElement.type !== "radio") {661            switch (getVirtualKey(ev)) {662            case "Escape":663                handleEscape(ev);664                break;665            }666        } else {667            switch (getVirtualKey(ev)) {668            case "Escape":669                handleEscape(ev);670                break;671672            case "s":673            case "S":674            case "/":675                ev.preventDefault();676                window.searchState.focus();677                break;678679            case "+":680            case "=":681                ev.preventDefault();682                expandAllDocs();683                break;684            case "-":685                ev.preventDefault();686                collapseAllDocs(false);687                break;688            case "_":689                ev.preventDefault();690                collapseAllDocs(true);691                break;692693            case "?":694                showHelp();695                break;696697            default:698                break;699            }700        }701    }702703    document.addEventListener("keypress", handleShortcut);704    document.addEventListener("keydown", handleShortcut);705706    function addSidebarItems() {707        if (!window.SIDEBAR_ITEMS) {708            return;709        }710        const sidebar = document.getElementById("rustdoc-modnav");711712        /**713         * Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.714         *715         * @param {string} shortty - A short type name, like "primitive", "mod", or "macro"716         * @param {string} id - The HTML id of the corresponding section on the module page.717         * @param {string} longty - A long, capitalized, plural name, like "Primitive Types",718         *                          "Modules", or "Macros".719         */720        function block(shortty, id, longty) {721            // @ts-expect-error722            const filtered = window.SIDEBAR_ITEMS[shortty];723            if (!filtered) {724                return;725            }726727            const modpath = hasClass(document.querySelector(".rustdoc"), "mod") ? "../" : "";728729            const h3 = document.createElement("h3");730            h3.innerHTML = `<a href="${modpath}index.html#${id}">${longty}</a>`;731            const ul = document.createElement("ul");732            ul.className = "block " + shortty;733734            for (const name of filtered) {735                let path;736                if (shortty === "mod") {737                    path = `${modpath}${name}/index.html`;738                } else {739                    path = `${modpath}${shortty}.${name}.html`;740                }741                let current_page = document.location.href.toString();742                if (current_page.endsWith("/")) {743                    current_page += "index.html";744                }745                const link = document.createElement("a");746                link.href = path;747                link.textContent = name;748                const li = document.createElement("li");749                // Don't "optimize" this to just use `path`.750                // We want the browser to normalize this into an absolute URL.751                if (link.href === current_page) {752                    li.classList.add("current");753                }754                li.appendChild(link);755                ul.appendChild(li);756            }757            // @ts-expect-error758            sidebar.appendChild(h3);759            // @ts-expect-error760            sidebar.appendChild(ul);761        }762763        if (sidebar) {764            // keep this synchronized with ItemSection::ALL in html/render/mod.rs765            // Re-exports aren't shown here, because they don't have child pages766            //block("reexport", "reexports", "Re-exports");767            block("primitive", "primitives", "Primitive Types");768            block("mod", "modules", "Modules");769            block("macro", "macros", "Macros");770            block("struct", "structs", "Structs");771            block("enum", "enums", "Enums");772            block("constant", "constants", "Constants");773            block("static", "static", "Statics");774            block("trait", "traits", "Traits");775            block("fn", "functions", "Functions");776            block("type", "types", "Type Aliases");777            block("union", "unions", "Unions");778            // No point, because these items don't appear in modules779            //block("impl", "impls", "Implementations");780            //block("tymethod", "tymethods", "Type Methods");781            //block("method", "methods", "Methods");782            //block("structfield", "fields", "Fields");783            //block("variant", "variants", "Variants");784            //block("associatedtype", "associated-types", "Associated Types");785            //block("associatedconstant", "associated-consts", "Associated Constants");786            block("foreigntype", "foreign-types", "Foreign Types");787            block("keyword", "keywords", "Keywords");788            block("attribute", "attributes", "Attributes");789            block("attr", "attributes", "Attribute Macros");790            block("derive", "derives", "Derive Macros");791            block("traitalias", "trait-aliases", "Trait Aliases");792        }793    }794795    // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code>796    window.register_implementors = imp => {797        /** Takes an ID as input and returns a list of two elements. The first element is the DOM798         * element with the given ID and the second is the "negative marker", meaning the location799         * between the negative and non-negative impls.800         *801         * @param {string} id: ID of the DOM element.802         *803         * @return {[HTMLElement|null, HTMLElement|null]}804         */805        function implementorsElems(id) {806            const elem = document.getElementById(id);807            return [elem, elem ? elem.querySelector(".negative-marker") : null];808        }809        const implementors = implementorsElems("implementors-list");810        const syntheticImplementors = implementorsElems("synthetic-implementors-list");811        const inlined_types = new Set();812813        const TEXT_IDX = 0;814        const IS_NEG_IDX = 1;815        const SYNTHETIC_IDX = 2;816        const TYPES_IDX = 3;817818        if (syntheticImplementors[0]) {819            // This `inlined_types` variable is used to avoid having the same implementation820            // showing up twice. For example "String" in the "Sync" doc page.821            //822            // By the way, this is only used by and useful for traits implemented automatically823            // (like "Send" and "Sync").824            onEachLazy(syntheticImplementors[0].getElementsByClassName("impl"), el => {825                const aliases = el.getAttribute("data-aliases");826                if (!aliases) {827                    return;828                }829                // @ts-expect-error830                aliases.split(",").forEach(alias => {831                    inlined_types.add(alias);832                });833            });834        }835836        // @ts-expect-error837        let currentNbImpls = implementors[0].getElementsByClassName("impl").length;838        // @ts-expect-error839        const traitName = document.querySelector(".main-heading h1 > .trait").textContent;840        const baseIdName = "impl-" + traitName + "-";841        const libs = Object.getOwnPropertyNames(imp);842        // We don't want to include impls from this JS file, when the HTML already has them.843        // The current crate should always be ignored. Other crates that should also be844        // ignored are included in the attribute `data-ignore-extern-crates`.845        const script = document846            .querySelector("script[data-ignore-extern-crates]");847        const ignoreExternCrates = new Set(848            // @ts-expect-error849            (script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),850        );851        for (const lib of libs) {852            if (lib === window.currentCrate || ignoreExternCrates.has(lib)) {853                continue;854            }855            const structs = imp[lib];856857            struct_loop:858            for (const struct of structs) {859                const list = struct[SYNTHETIC_IDX] ? syntheticImplementors : implementors;860861                // The types list is only used for synthetic impls.862                // If this changes, `main.js` and `write_shared.rs` both need changed.863                if (struct[SYNTHETIC_IDX]) {864                    for (const struct_type of struct[TYPES_IDX]) {865                        if (inlined_types.has(struct_type)) {866                            continue struct_loop;867                        }868                        inlined_types.add(struct_type);869                    }870                }871872                const code = document.createElement("h3");873                code.innerHTML = struct[TEXT_IDX];874                addClass(code, "code-header");875876                onEachLazy(code.getElementsByTagName("a"), elem => {877                    const href = elem.getAttribute("href");878879                    if (href && !href.startsWith("#") && !/^(?:[a-z+]+:)?\/\//.test(href)) {880                        elem.setAttribute("href", window.rootPath + href);881                    }882                });883884                const currentId = baseIdName + currentNbImpls;885                const anchor = document.createElement("a");886                anchor.href = "#" + currentId;887                addClass(anchor, "anchor");888889                const display = document.createElement("div");890                display.id = currentId;891                addClass(display, "impl");892                display.appendChild(anchor);893                display.appendChild(code);894895                // If this is a negative implementor, we put it into the right location (just896                // before the negative impl marker).897                if (struct[IS_NEG_IDX]) {898                    // @ts-expect-error899                    list[1].before(display);900                } else {901                    // @ts-expect-error902                    list[0].appendChild(display);903                }904                currentNbImpls += 1;905            }906        }907        if (implementors[0]) {908            implementors[0].classList.add("loaded");909        }910        if (syntheticImplementors[0]) {911            syntheticImplementors[0].classList.add("loaded");912        }913    };914    if (window.pending_implementors) {915        window.register_implementors(window.pending_implementors);916    }917918    /**919     * <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+type.impl&type=code>920     *921     * [RUSTDOCIMPL] type.impl922     *923     * This code inlines implementations into the type alias docs at runtime. It's done at924     * runtime because some crates have many type aliases and many methods, and we don't want925     * to generate *O*`(types*methods)` HTML text. The data inside is mostly HTML fragments,926     * wrapped in JSON.927     *928     * - It only includes docs generated for the current crate. This function accepts an929     *   object mapping crate names to the set of impls.930     *931     * - It filters down to the set of applicable impls. The Rust type checker is used to932     *   tag each HTML blob with the set of type aliases that can actually use it, so the933     *   JS only needs to consult the attached list of type aliases.934     *935     * - It renames the ID attributes, to avoid conflicting IDs in the resulting DOM.936     *937     * - It adds the necessary items to the sidebar. If it's an inherent impl, that means938     *   adding methods, associated types, and associated constants. If it's a trait impl,939     *   that means adding it to the trait impl sidebar list.940     *941     * - It adds the HTML block itself. If it's an inherent impl, it goes after the type942     *   alias's own inherent impls. If it's a trait impl, it goes in the Trait943     *   Implementations section.944     *945     * - After processing all of the impls, it sorts the sidebar items by name.946     *947     * @param {rustdoc.TypeImpls} imp948     */949    window.register_type_impls = imp => {950        // @ts-expect-error951        if (!imp || !imp[window.currentCrate]) {952            return;953        }954        window.pending_type_impls = undefined;955        const idMap = new Map();956957        let implementations = document.getElementById("implementations-list");958        let trait_implementations = document.getElementById("trait-implementations-list");959        let trait_implementations_header = document.getElementById("trait-implementations");960961        // We want to include the current type alias's impls, and no others.962        const script = document.querySelector("script[data-self-path]");963        const selfPath = script ? script.getAttribute("data-self-path") : null;964965        // These sidebar blocks need filled in, too.966        const mainContent = nonnull(document.querySelector("#main-content"));967        const sidebarSection = nonnull(document.querySelector(".sidebar section"));968        let methods = document.querySelector(".sidebar .block.method");969        let associatedTypes = document.querySelector(".sidebar .block.associatedtype");970        let associatedConstants = document.querySelector(".sidebar .block.associatedconstant");971        let sidebarTraitList = document.querySelector(".sidebar .block.trait-implementation");972973        for (const impList of imp[nonnull(window.currentCrate)]) {974            const types = impList.slice(2);975            const text = impList[0];976            const traitName = impList[1];977            const isTrait = typeof traitName === "string";978            // @ts-expect-error979            if (types.indexOf(selfPath) === -1) {980                continue;981            }982            let outputList = isTrait ? trait_implementations : implementations;983            if (outputList === null) {984                const outputListName = isTrait ? "Trait Implementations" : "Implementations";985                const outputListId = isTrait ?986                    "trait-implementations-list" :987                    "implementations-list";988                const outputListHeaderId = isTrait ? "trait-implementations" : "implementations";989                const outputListHeader = document.createElement("h2");990                outputListHeader.id = outputListHeaderId;991                outputListHeader.innerText = outputListName;992                outputList = document.createElement("div");993                outputList.id = outputListId;994                if (isTrait) {995                    const link = document.createElement("a");996                    link.href = `#${outputListHeaderId}`;997                    link.innerText = "Trait Implementations";998                    const h = document.createElement("h3");999                    h.appendChild(link);1000                    trait_implementations = outputList;1001                    trait_implementations_header = outputListHeader;1002                    sidebarSection.appendChild(h);1003                    sidebarTraitList = document.createElement("ul");1004                    sidebarTraitList.className = "block trait-implementation";1005                    sidebarSection.appendChild(sidebarTraitList);1006                    mainContent.appendChild(outputListHeader);1007                    mainContent.appendChild(outputList);1008                } else {1009                    implementations = outputList;1010                    if (trait_implementations) {1011                        mainContent.insertBefore(outputListHeader, trait_implementations_header);1012                        mainContent.insertBefore(outputList, trait_implementations_header);1013                    } else {1014                        mainContent.appendChild(outputListHeader);1015                        mainContent.appendChild(outputList);1016                    }1017                }1018            }1019            const template = document.createElement("template");1020            template.innerHTML = text;10211022            onEachLazy(template.content.querySelectorAll("a"), elem => {1023                const href = elem.getAttribute("href");10241025                if (href && !href.startsWith("#") && !/^(?:[a-z+]+:)?\/\//.test(href)) {1026                    elem.setAttribute("href", window.rootPath + href);1027                }1028            });1029            onEachLazy(template.content.querySelectorAll("[id]"), el => {1030                let i = 0;1031                if (idMap.has(el.id)) {1032                    i = idMap.get(el.id);1033                } else if (document.getElementById(el.id)) {1034                    i = 1;1035                    while (document.getElementById(`${el.id}-${2 * i}`)) {1036                        i = 2 * i;1037                    }1038                    while (document.getElementById(`${el.id}-${i}`)) {1039                        i += 1;1040                    }1041                }1042                if (i !== 0) {1043                    const oldHref = `#${el.id}`;1044                    const newHref = `#${el.id}-${i}`;1045                    el.id = `${el.id}-${i}`;1046                    onEachLazy(template.content.querySelectorAll("a[href]"), link => {1047                        if (link.getAttribute("href") === oldHref) {1048                            link.href = newHref;1049                        }1050                    });1051                }1052                idMap.set(el.id, i + 1);1053            });1054            const templateAssocItems = template.content.querySelectorAll("section.tymethod, " +1055                "section.method, section.associatedtype, section.associatedconstant");1056            if (isTrait) {1057                const li = document.createElement("li");1058                const a = document.createElement("a");1059                a.href = `#${nonnull(template.content.querySelector(".impl")).id}`;1060                a.textContent = traitName;1061                li.appendChild(a);1062                // @ts-expect-error1063                sidebarTraitList.append(li);1064            } else {1065                onEachLazy(templateAssocItems, item => {1066                    let block = hasClass(item, "associatedtype") ? associatedTypes : (1067                        hasClass(item, "associatedconstant") ? associatedConstants : (1068                        methods));1069                    if (!block) {1070                        const blockTitle = hasClass(item, "associatedtype") ? "Associated Types" : (1071                            hasClass(item, "associatedconstant") ? "Associated Constants" : (1072                            "Methods"));1073                        const blockClass = hasClass(item, "associatedtype") ? "associatedtype" : (1074                            hasClass(item, "associatedconstant") ? "associatedconstant" : (1075                            "method"));1076                        const blockHeader = document.createElement("h3");1077                        const blockLink = document.createElement("a");1078                        blockLink.href = "#implementations";1079                        blockLink.innerText = blockTitle;1080                        blockHeader.appendChild(blockLink);1081                        block = document.createElement("ul");1082                        block.className = `block ${blockClass}`;1083                        const insertionReference = methods || sidebarTraitList;1084                        if (insertionReference) {1085                            const insertionReferenceH = insertionReference.previousElementSibling;1086                            sidebarSection.insertBefore(blockHeader, insertionReferenceH);1087                            sidebarSection.insertBefore(block, insertionReferenceH);1088                        } else {1089                            sidebarSection.appendChild(blockHeader);1090                            sidebarSection.appendChild(block);1091                        }1092                        if (hasClass(item, "associatedtype")) {1093                            associatedTypes = block;1094                        } else if (hasClass(item, "associatedconstant")) {1095                            associatedConstants = block;1096                        } else {1097                            methods = block;1098                        }1099                    }1100                    const li = document.createElement("li");1101                    const a = document.createElement("a");1102                    a.innerText = item.id.split("-")[0].split(".")[1];1103                    a.href = `#${item.id}`;1104                    li.appendChild(a);1105                    block.appendChild(li);1106                });1107            }1108            outputList.appendChild(template.content);1109        }11101111        for (const list of [methods, associatedTypes, associatedConstants, sidebarTraitList]) {1112            if (!list) {1113                continue;1114            }1115            const newChildren = Array.prototype.slice.call(list.children);1116            newChildren.sort((a, b) => {1117                const aI = a.innerText;1118                const bI = b.innerText;1119                return aI < bI ? -1 :1120                    aI > bI ? 1 :1121                    0;1122            });1123            list.replaceChildren(...newChildren);1124        }1125    };1126    if (window.pending_type_impls) {1127        window.register_type_impls(window.pending_type_impls);1128    }11291130    function addSidebarCrates() {1131        // @ts-expect-error1132        if (!window.ALL_CRATES) {1133            return;1134        }1135        const sidebarElems = document.getElementById("rustdoc-modnav");1136        if (!sidebarElems) {1137            return;1138        }1139        // Draw a convenient sidebar of known crates if we have a listing1140        const h3 = document.createElement("h3");1141        h3.innerHTML = "Crates";1142        const ul = document.createElement("ul");1143        ul.className = "block crate";11441145        // @ts-expect-error1146        for (const crate of window.ALL_CRATES) {1147            const link = document.createElement("a");1148            link.href = window.rootPath + crate + "/index.html";1149            link.textContent = crate;11501151            const li = document.createElement("li");1152            if (window.rootPath !== "./" && crate === window.currentCrate) {1153                li.className = "current";1154            }1155            li.appendChild(link);1156            ul.appendChild(li);1157        }1158        sidebarElems.appendChild(h3);1159        sidebarElems.appendChild(ul);1160    }11611162    function expandAllDocs() {1163        const innerToggle = document.getElementById(toggleAllDocsId);1164        removeClass(innerToggle, "will-expand");1165        onEachLazy(document.getElementsByClassName("toggle"), e => {1166            if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {1167                e.open = true;1168            }1169        });1170        // @ts-expect-error1171        innerToggle.children[0].innerText = "Summary";1172    }11731174    /**1175     * @param {boolean} collapseImpls - also collapse impl blocks if set to true1176     */1177    function collapseAllDocs(collapseImpls) {1178        const innerToggle = document.getElementById(toggleAllDocsId);1179        addClass(innerToggle, "will-expand");1180        onEachLazy(document.getElementsByClassName("toggle"), e => {1181            if ((collapseImpls || e.parentNode.id !== "implementations-list") ||1182                (!hasClass(e, "implementors-toggle") &&1183                 !hasClass(e, "type-contents-toggle"))1184            ) {1185                e.open = false;1186            }1187        });1188        // @ts-expect-error1189        innerToggle.children[0].innerText = "Show all";1190    }11911192    /**1193     * @param {MouseEvent=} ev1194     */1195    function toggleAllDocs(ev) {1196        const innerToggle = document.getElementById(toggleAllDocsId);1197        if (!innerToggle) {1198            return;1199        }1200        if (hasClass(innerToggle, "will-expand")) {1201            expandAllDocs();1202        } else {1203            collapseAllDocs(ev !== undefined && ev.shiftKey);1204        }1205    }12061207    (function() {1208        const toggles = document.getElementById(toggleAllDocsId);1209        if (toggles) {1210            toggles.onclick = toggleAllDocs;1211        }12121213        const hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";1214        const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";1215        const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";12161217        // @ts-expect-error1218        function setImplementorsTogglesOpen(id, open) {1219            const list = document.getElementById(id);1220            if (list !== null) {1221                onEachLazy(list.getElementsByClassName("implementors-toggle"), e => {1222                    e.open = open;1223                });1224            }1225        }12261227        if (hideImplementations) {1228            setImplementorsTogglesOpen("trait-implementations-list", false);1229            setImplementorsTogglesOpen("blanket-implementations-list", false);1230        }12311232        onEachLazy(document.getElementsByClassName("toggle"), e => {1233            if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {1234                e.open = true;1235            }1236            if (hideMethodDocs && hasClass(e, "method-toggle")) {1237                e.open = false;1238            }12391240        });1241    }());12421243    window.rustdoc_add_line_numbers_to_examples = () => {1244        // @ts-expect-error1245        function generateLine(nb) {1246            return `<span data-nosnippet>${nb}</span>`;1247        }12481249        onEachLazy(document.querySelectorAll(1250            ".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code",1251        ), code => {1252            if (hasClass(code.parentElement.parentElement, "hide-lines")) {1253                removeClass(code.parentElement.parentElement, "hide-lines");1254                return;1255            }1256            const lines = code.innerHTML.split("\n");1257            const digits = (lines.length + "").length;1258            // @ts-expect-error1259            code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n");1260            addClass(code.parentElement.parentElement, `digits-${digits}`);1261        });1262    };12631264    window.rustdoc_remove_line_numbers_from_examples = () => {1265        onEachLazy(1266            document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"),1267            x => addClass(x, "hide-lines"),1268        );1269    };12701271    if (getSettingValue("line-numbers") === "true") {1272        window.rustdoc_add_line_numbers_to_examples();1273    }12741275    function showSidebar() {1276        window.hideAllModals(false);1277        const sidebar = document.getElementsByClassName("sidebar")[0];1278        addClass(sidebar, "shown");1279    }12801281    function hideSidebar() {1282        const sidebar = document.getElementsByClassName("sidebar")[0];1283        removeClass(sidebar, "shown");1284    }12851286    window.addEventListener("resize", () => {1287        if (window.CURRENT_TOOLTIP_ELEMENT) {1288            // As a workaround to the behavior of `contains: layout` used in doc togglers,1289            // tooltip popovers are positioned using javascript.1290            //1291            // This means when the window is resized, we need to redo the layout.1292            const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;1293            const force_visible = base.TOOLTIP_FORCE_VISIBLE;1294            hideTooltip(false);1295            if (force_visible) {1296                showTooltip(base);1297                base.TOOLTIP_FORCE_VISIBLE = true;1298            }1299        }1300    });13011302    const mainElem = document.getElementById(MAIN_ID);1303    if (mainElem) {1304        mainElem.addEventListener("click", hideSidebar);1305    }13061307    onEachLazy(document.querySelectorAll("a[href^='#']"), el => {1308        // For clicks on internal links (<A> tags with a hash property), we expand the section we're1309        // jumping to *before* jumping there. We can't do this in onHashChange, because it changes1310        // the height of the document so we wind up scrolled to the wrong place.1311        el.addEventListener("click", () => {1312            expandSection(el.hash.slice(1));1313            hideSidebar();1314        });1315    });13161317    onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {1318        // @ts-expect-error1319        // Clicking on the summary's contents should not collapse it,1320        // but links within should still fire.1321        el.addEventListener("click", e => {1322            if (!e.target.matches("summary, a, a *")) {1323                e.preventDefault();1324            }1325        });1326    });13271328    /**1329     * Show a tooltip immediately.1330     *1331     * @param {HTMLElement} e - The tooltip's anchor point. The DOM is consulted to figure1332     *                          out what the tooltip should contain, and where it should be1333     *                          positioned.1334     */1335    function showTooltip(e) {1336        const notable_ty = e.getAttribute("data-notable-ty");1337        if (!window.NOTABLE_TRAITS && notable_ty) {1338            const data = document.getElementById("notable-traits-data");1339            if (data) {1340                window.NOTABLE_TRAITS = JSON.parse(data.innerText);1341            } else {1342                throw new Error("showTooltip() called with notable without any notable traits!");1343            }1344        }1345        // Make this function idempotent. If the tooltip is already shown, avoid doing extra work1346        // and leave it alone.1347        if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {1348            clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);1349            return;1350        }1351        window.hideAllModals(false);1352        // use Object.assign to make sure the object has the correct type1353        // with all of the correct fields before it is assigned to a variable,1354        // as typescript has no way to change the type of a variable once it is initialized.1355        const wrapper = Object.assign(document.createElement("div"), {TOOLTIP_BASE: e});1356        if (notable_ty) {1357            wrapper.innerHTML = "<div class=\"content\">" +1358                // @ts-expect-error1359                window.NOTABLE_TRAITS[notable_ty] + "</div>";1360        } else {1361            // Replace any `title` attribute with `data-title` to avoid double tooltips.1362            const ttl = e.getAttribute("title");1363            if (ttl !== null) {1364                e.setAttribute("data-title", ttl);1365                e.removeAttribute("title");1366            }1367            const dttl = e.getAttribute("data-title");1368            if (dttl !== null) {1369                const titleContent = document.createElement("div");1370                titleContent.className = "content";1371                titleContent.appendChild(document.createTextNode(dttl));1372                wrapper.appendChild(titleContent);1373            }1374        }1375        wrapper.className = "tooltip popover";1376        const focusCatcher = document.createElement("div");1377        focusCatcher.setAttribute("tabindex", "0");1378        // @ts-expect-error1379        focusCatcher.onfocus = hideTooltip;1380        wrapper.appendChild(focusCatcher);1381        const pos = e.getBoundingClientRect();1382        // 5px overlap so that the mouse can easily travel from place to place1383        wrapper.style.top = (pos.top + window.scrollY + pos.height) + "px";1384        // @ts-expect-error1385        wrapper.style.left = 0;1386        wrapper.style.right = "auto";1387        wrapper.style.visibility = "hidden";1388        document.body.appendChild(wrapper);1389        const wrapperPos = wrapper.getBoundingClientRect();1390        // offset so that the arrow points at the center of the "(i)"1391        const finalPos = pos.left + window.scrollX - wrapperPos.width + 24;1392        if (finalPos > 0) {1393            wrapper.style.left = finalPos + "px";1394        } else {1395            wrapper.style.setProperty(1396                "--popover-arrow-offset",1397                (wrapperPos.right - pos.right + 4) + "px",1398            );1399        }1400        wrapper.style.visibility = "";1401        window.CURRENT_TOOLTIP_ELEMENT = wrapper;1402        clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);1403        wrapper.onpointerenter = ev => {1404            // If this is a synthetic touch event, ignore it. A click event will be along shortly.1405            if (ev.pointerType !== "mouse") {1406                return;1407            }1408            clearTooltipHoverTimeout(e);1409        };1410        wrapper.onpointerleave = ev => {1411            // If this is a synthetic touch event, ignore it. A click event will be along shortly.1412            if (ev.pointerType !== "mouse" || !(ev.relatedTarget instanceof HTMLElement)) {1413                return;1414            }1415            if (!e.TOOLTIP_FORCE_VISIBLE && !e.contains(ev.relatedTarget)) {1416                // See "Tooltip pointer leave gesture" below.1417                setTooltipHoverTimeout(e, false);1418                addClass(wrapper, "fade-out");1419            }1420        };1421    }14221423    /**1424     * Show or hide the tooltip after a timeout. If a timeout was already set before this function1425     * was called, that timeout gets cleared. If the tooltip is already in the requested state,1426     * this function will still clear any pending timeout, but otherwise do nothing.1427     *1428     * @param {HTMLElement} element - The tooltip's anchor point. The DOM is consulted to figure1429     *                                out what the tooltip should contain, and where it should be1430     *                                positioned.1431     * @param {boolean}    show    - If true, the tooltip will be made visible. If false, it will1432     *                               be hidden.1433     */1434    function setTooltipHoverTimeout(element, show) {1435        clearTooltipHoverTimeout(element);1436        if (!show && !window.CURRENT_TOOLTIP_ELEMENT) {1437            // To "hide" an already hidden element, just cancel its timeout.1438            return;1439        }1440        if (show && window.CURRENT_TOOLTIP_ELEMENT) {1441            // To "show" an already visible element, just cancel its timeout.1442            return;1443        }1444        if (window.CURRENT_TOOLTIP_ELEMENT &&1445            window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) {1446            // Don't do anything if another tooltip is already visible.1447            return;1448        }1449        element.TOOLTIP_HOVER_TIMEOUT = setTimeout(() => {1450            if (show) {1451                showTooltip(element);1452            } else if (!element.TOOLTIP_FORCE_VISIBLE) {1453                hideTooltip(false);1454            }1455        }, show ? window.RUSTDOC_TOOLTIP_HOVER_MS : window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS);1456    }14571458    /**1459     * If a show/hide timeout was set by `setTooltipHoverTimeout`, cancel it. If none exists,1460     * do nothing.1461     *1462     * @param {HTMLElement} element - The tooltip's anchor point,1463     *                                as passed to `setTooltipHoverTimeout`.1464     */1465    function clearTooltipHoverTimeout(element) {1466        if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) {1467            removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");1468            clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);1469            delete element.TOOLTIP_HOVER_TIMEOUT;1470        }1471    }14721473    /**1474     * @param {Event & { relatedTarget: Node }} event1475     */1476    function tooltipBlurHandler(event) {1477        if (window.CURRENT_TOOLTIP_ELEMENT &&1478            !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) &&1479            !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) &&1480            !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) &&1481            !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)1482        ) {1483            // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.1484            // When I click the button on an already-opened tooltip popover, Safari1485            // hides the popover and then immediately shows it again, while everyone else hides it1486            // and it stays hidden.1487            //1488            // To work around this, make sure the click finishes being dispatched before1489            // hiding the popover. Since `hideTooltip()` is idempotent, this makes Safari behave1490            // consistently with the other two.1491            setTimeout(() => hideTooltip(false), 0);1492        }1493    }14941495    /**1496     * Hide the current tooltip immediately.1497     *1498     * @param {boolean} focus - If set to `true`, move keyboard focus to the tooltip anchor point.1499     *                          If set to `false`, leave keyboard focus alone.1500     */1501    function hideTooltip(focus) {1502        if (window.CURRENT_TOOLTIP_ELEMENT) {1503            if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {1504                if (focus) {1505                    window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();1506                }1507                window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;1508            }1509            document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);1510            clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);1511            window.CURRENT_TOOLTIP_ELEMENT = undefined;1512        }1513    }15141515    onEachLazy(document.getElementsByClassName("tooltip"), e => {1516        e.onclick = () => {1517            e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;1518            if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {1519                hideTooltip(true);1520            } else {1521                showTooltip(e);1522                // @ts-expect-error1523                window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");1524                // @ts-expect-error1525                window.CURRENT_TOOLTIP_ELEMENT.focus();1526                // @ts-expect-error1527                window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;1528            }1529            return false;1530        };1531        // @ts-expect-error1532        e.onpointerenter = ev => {1533            // If this is a synthetic touch event, ignore it. A click event will be along shortly.1534            if (ev.pointerType !== "mouse") {1535                return;1536            }1537            setTooltipHoverTimeout(e, true);1538        };1539        // @ts-expect-error1540        e.onpointermove = ev => {1541            // If this is a synthetic touch event, ignore it. A click event will be along shortly.1542            if (ev.pointerType !== "mouse") {1543                return;1544            }1545            setTooltipHoverTimeout(e, true);1546        };1547        // @ts-expect-error1548        e.onpointerleave = ev => {1549            // If this is a synthetic touch event, ignore it. A click event will be along shortly.1550            if (ev.pointerType !== "mouse") {1551                return;1552            }1553            if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT &&1554                !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) {1555                // Tooltip pointer leave gesture:1556                //1557                // Designing a good hover microinteraction is a matter of guessing user1558                // intent from what are, literally, vague gestures. In this case, guessing if1559                // hovering in or out of the tooltip base is intentional or not.1560                //1561                // To figure this out, a few different techniques are used:1562                //1563                // * When the mouse pointer enters a tooltip anchor point, its hitbox is grown1564                //   on the bottom, where the popover is/will appear. Search "hover tunnel" in1565                //   rustdoc.css for the implementation.1566                // * There's a delay when the mouse pointer enters the popover base anchor, in1567                //   case the mouse pointer was just passing through and the user didn't want1568                //   to open it.1569                // * Similarly, a delay is added when exiting the anchor, or the popover1570                //   itself, before hiding it.1571                // * A fade-out animation is layered onto the pointer exit delay to immediately1572                //   inform the user that they successfully dismissed the popover, while still1573                //   providing a way for them to cancel it if it was a mistake and they still1574                //   wanted to interact with it.1575                // * No animation is used for revealing it, because we don't want people to try1576                //   to interact with an element while it's in the middle of fading in: either1577                //   they're allowed to interact with it while it's fading in, meaning it can't1578                //   serve as mistake-proofing for the popover, or they can't, but1579                //   they might try and be frustrated.1580                //1581                // See also:1582                // * https://www.nngroup.com/articles/timing-exposing-content/1583                // * https://www.nngroup.com/articles/tooltip-guidelines/1584                // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown1585                setTooltipHoverTimeout(e, false);1586                addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");1587            }1588        };1589    });15901591    const sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];1592    if (sidebar_menu_toggle) {1593        sidebar_menu_toggle.addEventListener("click", () => {1594            const sidebar = document.getElementsByClassName("sidebar")[0];1595            // @ts-expect-error1596            if (!hasClass(sidebar, "shown")) {1597                showSidebar();1598            } else {1599                hideSidebar();1600            }1601        });1602    }16031604    // @ts-expect-error1605    function helpBlurHandler(event) {1606        const isInPopover = onEachLazy(1607            document.querySelectorAll(".settings-menu, .help-menu"),1608            menu => {1609                return menu.contains(document.activeElement) || menu.contains(event.relatedTarget);1610            },1611        );1612        if (!isInPopover) {1613            window.hidePopoverMenus();1614        }1615    }16161617    function buildHelpMenu() {1618        const book_info = document.createElement("span");1619        const drloChannel = `https://doc.rust-lang.org/${getVar("channel")}`;1620        book_info.className = "top";1621        book_info.innerHTML = `You can find more information in \1622<a href="${drloChannel}/rustdoc/">the rustdoc book</a>.`;16231624        const shortcuts = [1625            ["?", "Show this help dialog"],1626            ["S / /", "Focus the search field"],1627            ["↑", "Move up in search results"],1628            ["↓", "Move down in search results"],1629            ["← / →", "Switch result tab (when results focused)"],1630            ["&#9166;", "Go to active search result"],1631            ["+ / =", "Expand all sections"],1632            ["-", "Collapse all sections"],1633            // for the sake of brevity, we don't say "inherit impl blocks",1634            // although that would be more correct,1635            // since trait impl blocks are collapsed by -1636            ["_", "Collapse all sections, including impl blocks"],1637        ].map(x => "<dt>" +1638            x[0].split(" ")1639                .map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " "))1640                .join("") + "</dt><dd>" + x[1] + "</dd>").join("");1641        const div_shortcuts = document.createElement("div");1642        addClass(div_shortcuts, "shortcuts");1643        div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";16441645        const infos = [1646            `For a full list of all search features, take a look \1647             <a href="${drloChannel}/rustdoc/read-documentation/search.html">here</a>.`,1648            "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \1649             restrict the search to a given item kind.",1650            "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \1651             <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \1652             and <code>constant</code>.",1653            "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \1654             <code>-&gt; vec</code> or <code>String, enum:Cow -&gt; bool</code>)",1655            "You can look for items with an exact name by putting double quotes around \1656             your request: <code>\"string\"</code>",1657             `Look for functions that accept or return \1658              <a href="${drloChannel}/std/primitive.slice.html">slices</a> and \1659              <a href="${drloChannel}/std/primitive.array.html">arrays</a> by writing square \1660              brackets (e.g., <code>-&gt; [u8]</code> or <code>[] -&gt; Option</code>)`,1661            "Look for items inside another one by searching for a path: <code>vec::Vec</code>",1662        ].map(x => "<p>" + x + "</p>").join("");1663        const div_infos = document.createElement("div");1664        addClass(div_infos, "infos");1665        div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;16661667        const rustdoc_version = document.createElement("span");1668        rustdoc_version.className = "bottom";1669        const rustdoc_version_code = document.createElement("code");1670        rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");1671        rustdoc_version.appendChild(rustdoc_version_code);16721673        const container = document.createElement("div");1674        if (!isHelpPage) {1675            container.className = "popover";1676        }1677        container.id = "help";16781679        const side_by_side = document.createElement("div");1680        side_by_side.className = "side-by-side";1681        side_by_side.appendChild(div_shortcuts);1682        side_by_side.appendChild(div_infos);16831684        const content = document.createElement("div");1685        content.className = "content";16861687        content.appendChild(book_info);1688        content.appendChild(side_by_side);1689        content.appendChild(rustdoc_version);16901691        container.appendChild(content);16921693        if (isHelpPage) {1694            const help_section = document.createElement("section");1695            help_section.appendChild(container);1696            nonnull(document.getElementById("main-content")).appendChild(help_section);1697        } else {1698            onEachLazy(document.getElementsByClassName("help-menu"), menu => {1699                if (menu.offsetWidth !== 0) {1700                    menu.appendChild(container);1701                    container.onblur = helpBlurHandler;1702                    menu.onblur = helpBlurHandler;1703                    menu.children[0].onblur = helpBlurHandler;1704                    return true;1705                }1706            });1707        }17081709        return container;1710    }17111712    /**1713     * Hide popover menus, clickable tooltips, and the sidebar (if applicable).1714     *1715     * Pass `true` to reset focus for tooltip popovers.1716     */1717    window.hideAllModals = switchFocus => {1718        hideSidebar();1719        window.hidePopoverMenus();1720        hideTooltip(switchFocus);1721    };17221723    /**1724     * Hide all the popover menus.1725     */1726    window.hidePopoverMenus = () => {1727        onEachLazy(document.querySelectorAll(".settings-menu .popover"), elem => {1728            elem.style.display = "none";1729        });1730        onEachLazy(document.querySelectorAll(".help-menu .popover"), elem => {1731            elem.parentElement.removeChild(elem);1732        });1733    };17341735    /**1736     * Show the help popup menu.1737     */1738    function showHelp() {1739        window.hideAllModals(false);1740        // Prevent `blur` events from being dispatched as a result of closing1741        // other modals.1742        onEachLazy(document.querySelectorAll(".help-menu a"), menu => {1743            if (menu.offsetWidth !== 0) {1744                menu.focus();1745                return true;1746            }1747        });1748        buildHelpMenu();1749    }17501751    if (isHelpPage) {1752        buildHelpMenu();1753    } else {1754        onEachLazy(document.querySelectorAll(".help-menu > a"), helpLink => {1755            helpLink.addEventListener(1756                "click",1757                /** @param {MouseEvent} event */1758                event => {1759                    // By default, have help button open docs in a popover.1760                    // If user clicks with a moderator, though, use default browser behavior,1761                    // probably opening in a new window or tab.1762                    if (event.ctrlKey ||1763                        event.altKey ||1764                        event.metaKey) {1765                        return;1766                    }1767                    event.preventDefault();1768                    if (document.getElementById("help")) {1769                        window.hidePopoverMenus();1770                    } else {1771                        showHelp();1772                    }1773                },1774            );1775        });1776    }17771778    addSidebarItems();1779    addSidebarCrates();1780    onHashChange(null);1781    window.addEventListener("hashchange", onHashChange);1782    window.searchState.setup();1783}());17841785// Hide, show, and resize the sidebar1786//1787// The body class and CSS variable are initially set up in storage.js,1788// but in this file, we implement:1789//1790//   * the show sidebar button, which appears if the sidebar is hidden1791//     and, by clicking on it, will bring it back1792//   * the sidebar resize handle, which appears only on large viewports1793//     with a [fine precision pointer] to allow the user to change1794//     the size of the sidebar1795//1796// [fine precision pointer]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer1797(function() {1798    // 100 is the size of the logo1799    // don't let the sidebar get smaller than that, or it'll get squished1800    const SIDEBAR_MIN = 100;1801    // Don't let the sidebar get bigger than this1802    const SIDEBAR_MAX = 500;1803    // Don't let the body (including the gutter) get smaller than this1804    //1805    // WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY1806    // Acceptable values for BODY_MIN are constrained by the mobile breakpoint1807    // (which is the minimum size of the whole page where the sidebar exists)1808    // and the default sidebar width:1809    //1810    //     BODY_MIN <= RUSTDOC_MOBILE_BREAKPOINT - DEFAULT_SIDEBAR_WIDTH1811    //1812    // At the time of this writing, the DEFAULT_SIDEBAR_WIDTH on src pages is1813    // 300px, and the RUSTDOC_MOBILE_BREAKPOINT is 700px, so BODY_MIN must be1814    // at most 400px. Otherwise, it would start out at the default size, then1815    // grabbing the resize handle would suddenly cause it to jank to1816    // its constraint-generated maximum.1817    const RUSTDOC_MOBILE_BREAKPOINT = 700;1818    const BODY_MIN = 400;1819    // At half-way past the minimum size, vanish the sidebar entirely1820    const SIDEBAR_VANISH_THRESHOLD = SIDEBAR_MIN / 2;18211822    // Toolbar button to show the sidebar.1823    //1824    // On small, "mobile-sized" viewports, it's not persistent and it1825    // can only be activated by going into Settings and hiding the nav bar.1826    // On larger, "desktop-sized" viewports (though that includes many1827    // tablets), it's fixed-position, appears in the left side margin,1828    // and it can be activated by resizing the sidebar into nothing.1829    let sidebarButton = document.getElementById("sidebar-button");1830    const body = document.querySelector(".main-heading");1831    if (!sidebarButton && body) {1832        sidebarButton = document.createElement("div");1833        sidebarButton.id = "sidebar-button";1834        const path = `${window.rootPath}${window.currentCrate}/all.html`;1835        sidebarButton.innerHTML = `<a href="${path}" title="show sidebar"></a>`;1836        body.insertBefore(sidebarButton, body.firstChild);1837    }1838    if (sidebarButton) {1839        sidebarButton.addEventListener("click", e => {1840            removeClass(document.documentElement, "hide-sidebar");1841            updateLocalStorage("hide-sidebar", "false");1842            if (window.rustdocToggleSrcSidebar) {1843                window.rustdocToggleSrcSidebar();1844            }1845            e.preventDefault();1846        });1847    }18481849    /**1850     * Pointer capture.1851     *1852     * Resizing is a single-pointer gesture. Any secondary pointer is ignored1853     *1854     * @type {null|number}1855     */1856    let currentPointerId = null;18571858    /**1859     * "Desired" sidebar size.1860     *1861     * This is stashed here for window resizing. If the sidebar gets1862     * shrunk to maintain BODY_MIN, and then the user grows the window again,1863     * it gets the sidebar to restore its size.1864     *1865     * @type {null|number}1866     */1867    let desiredSidebarSize = null;18681869    /**1870     * Sidebar resize debouncer.1871     *1872     * The sidebar itself is resized instantly, but the body HTML can be too1873     * big for that, causing reflow jank. To reduce this, we queue up a separate1874     * animation frame and throttle it.1875     *1876     * @type {false|ReturnType<typeof setTimeout>}1877     */1878    let pendingSidebarResizingFrame = false;18791880    /** @type {HTMLElement|null} */1881    const resizer = document.querySelector(".sidebar-resizer");1882    /** @type {HTMLElement|null} */1883    const sidebar = document.querySelector(".sidebar");1884    // If this page has no sidebar at all, bail out.1885    if (!resizer || !sidebar) {1886        return;1887    }18881889    // src page and docs page use different variables, because the contents of1890    // the sidebar are so different that it's reasonable to thing the user1891    // would want them to have different sizes1892    const isSrcPage = hasClass(document.body, "src");18931894    // Call this function to hide the sidebar when using the resize handle1895    //1896    // This function also nulls out the sidebar width CSS variable and setting,1897    // causing it to return to its default. This does not happen if you do it1898    // from settings.js, which uses a separate function. It's done here because1899    // the minimum sidebar size is rather uncomfortable, and it must pass1900    // through that size when using the shrink-to-nothing gesture.1901    const hideSidebar = function() {1902        if (isSrcPage) {1903            window.rustdocCloseSourceSidebar();1904            updateLocalStorage("src-sidebar-width", null);1905            // [RUSTDOCIMPL] CSS variable fast path1906            //1907            // The sidebar width variable is attached to the <html> element by1908            // storage.js, because the sidebar and resizer don't exist yet.1909            // But the resize code, in `resize()`, sets the property on the1910            // sidebar and resizer elements (which are the only elements that1911            // use the variable) to avoid recalculating CSS on the entire1912            // document on every frame.1913            //1914            // So, to clear it, we need to clear all three.1915            document.documentElement.style.removeProperty("--src-sidebar-width");1916            sidebar.style.removeProperty("--src-sidebar-width");1917            resizer.style.removeProperty("--src-sidebar-width");1918        } else {1919            addClass(document.documentElement, "hide-sidebar");1920            updateLocalStorage("hide-sidebar", "true");1921            updateLocalStorage("desktop-sidebar-width", null);1922            document.documentElement.style.removeProperty("--desktop-sidebar-width");1923            sidebar.style.removeProperty("--desktop-sidebar-width");1924            resizer.style.removeProperty("--desktop-sidebar-width");1925        }1926    };19271928    // Call this function to show the sidebar from the resize handle.1929    // On docs pages, this can only happen if the user has grabbed the resize1930    // handle, shrunk the sidebar down to nothing, and then pulls back into1931    // the visible range without releasing it. You can, however, grab the1932    // resize handle on a source page with the sidebar closed, because it1933    // remains visible all the time on there.1934    const showSidebar = function() {1935        if (isSrcPage) {1936            window.rustdocShowSourceSidebar();1937        } else {1938            removeClass(document.documentElement, "hide-sidebar");1939            updateLocalStorage("hide-sidebar", "false");1940        }1941    };19421943    /**1944     * Call this to set the correct CSS variable and setting.1945     * This function doesn't enforce size constraints. Do that before calling it!1946     *1947     * @param {number} size - CSS px width of the sidebar.1948     */1949    const changeSidebarSize = function(size) {1950        if (isSrcPage) {1951            updateLocalStorage("src-sidebar-width", size.toString());1952            // [RUSTDOCIMPL] CSS variable fast path1953            //1954            // While this property is set on the HTML element at load time,1955            // because the sidebar isn't actually loaded yet,1956            // we scope this update to the sidebar to avoid hitting a slow1957            // path in WebKit.1958            sidebar.style.setProperty("--src-sidebar-width", size + "px");1959            resizer.style.setProperty("--src-sidebar-width", size + "px");1960        } else {1961            updateLocalStorage("desktop-sidebar-width", size.toString());1962            sidebar.style.setProperty("--desktop-sidebar-width", size + "px");1963            resizer.style.setProperty("--desktop-sidebar-width", size + "px");1964        }1965    };19661967    // Check if the sidebar is hidden. Since src pages and doc pages have1968    // different settings, this function has to check that.1969    const isSidebarHidden = function() {1970        return isSrcPage ?1971            !hasClass(document.documentElement, "src-sidebar-expanded") :1972            hasClass(document.documentElement, "hide-sidebar");1973    };19741975    /**1976     * Respond to the resize handle event.1977     * This function enforces size constraints, and implements the1978     * shrink-to-nothing gesture based on thresholds defined above.1979     *1980     * @param {PointerEvent} e1981     */1982    const resize = function(e) {1983        if (currentPointerId === null || currentPointerId !== e.pointerId) {1984            return;1985        }1986        e.preventDefault();1987        const pos = e.clientX - 3;1988        if (pos < SIDEBAR_VANISH_THRESHOLD) {1989            hideSidebar();1990        } else if (pos >= SIDEBAR_MIN) {1991            if (isSidebarHidden()) {1992                showSidebar();1993            }1994            // don't let the sidebar get wider than SIDEBAR_MAX, or the body narrower1995            // than BODY_MIN1996            const constrainedPos = Math.min(pos, window.innerWidth - BODY_MIN, SIDEBAR_MAX);1997            changeSidebarSize(constrainedPos);1998            desiredSidebarSize = constrainedPos;1999            if (pendingSidebarResizingFrame !== false) {2000                clearTimeout(pendingSidebarResizingFrame);

Code quality findings 96

Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
search_input.addEventListener("focus", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("popstate", e => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
document.addEventListener("keypress", handleShortcut);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
document.addEventListener("keydown", handleShortcut);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("resize", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
mainElem.addEventListener("click", hideSidebar);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
el.addEventListener("click", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
el.addEventListener("click", e => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
sidebar_menu_toggle.addEventListener("click", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
helpLink.addEventListener(
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("hashchange", onHashChange);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
sidebarButton.addEventListener("click", e => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("resize", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("pointermove", resize, false);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("pointercancel", stopResize, false);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
window.addEventListener("pointerup", stopResize, false);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
resizer.addEventListener("pointerdown", initResize, false);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
copyButton.addEventListener("click", () => {
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
elem.addEventListener("mouseover", addCopyButton);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
elem.addEventListener("click", showHideCodeExampleButtons);
Remove event listeners when no longer needed to prevent memory leaks
warning performance event-listener-leak
document.body.addEventListener("copy", event => {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if ("key" in ev && typeof ev.key !== "undefined") {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if ("key" in ev && typeof ev.key !== "undefined") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (c === 27) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (elemToDisplay === null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return window.history && typeof window.history.pushState === "function";
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
return window.history && typeof window.history.pushState === "function";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (errorCallback !== undefined) {
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
setTimeout(() => {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
// "".split(",") == [""]
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (theme !== "") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const autofocusParam = params.search === "" ? "autofocus" : "";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (window.searchState.timeout !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
window.searchState.getQueryStringParams().search === undefined
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (params.search !== undefined && inputElement !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (params.search === "") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (qSearch !== undefined && inputElement !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (inputElement.value === "") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (qSearch === "") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (params.search !== undefined) {
Ensure all async functions handle errors properly
info correctness async-without-catch
loadDesc: async function({descShard, descIndex}) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (descShard.promise === null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev !== null && window.searchState.isDisplayed() && ev.newURL) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (savedHash !== pageId) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (pageId !== "") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (splitAt !== -1) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (implElem.id !== implId && (!numbered || numbered[1] !== implId)) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (item.id === assocId || (numbered && numbered[1] === assocId)) {
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
setTimeout(() => {
Ensure the element exists to avoid null errors
info correctness unchecked-element
openParentDetails(document.getElementById(id));
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
document.activeElement.type !== "checkbox" &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
document.activeElement.type !== "radio") {
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (getVirtualKey(ev)) {
Ensure all cases are handled or a default case is present
info correctness switch-without-default
switch (getVirtualKey(ev)) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (shortty === "mod") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (link.href === current_page) {
Ensure the element exists to avoid null errors
info correctness unchecked-element
const elem = document.getElementById(id);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (lib === window.currentCrate || ignoreExternCrates.has(lib)) {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
const isTrait = typeof traitName === "string";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const isTrait = typeof traitName === "string";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (types.indexOf(selfPath) === -1) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (outputList === null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (i !== 0) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (link.getAttribute("href") === oldHref) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (window.rootPath !== "./" && crate === window.currentCrate) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if ((collapseImpls || e.parentNode.id !== "implementations-list") ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
collapseAllDocs(ev !== undefined && ev.shiftKey);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (list !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (getSettingValue("line-numbers") === "true") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ttl !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (dttl !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev.pointerType !== "mouse") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev.pointerType !== "mouse" || !(ev.relatedTarget instanceof HTMLElement)) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) {
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
element.TOOLTIP_HOVER_TIMEOUT = setTimeout(() => {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) {
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
setTimeout(() => hideTooltip(false), 0);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev.pointerType !== "mouse") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev.pointerType !== "mouse") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (ev.pointerType !== "mouse") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
.map((y, index) => ((index & 1) === 0 ? "<kbd>" + y + "</kbd>" : " " + y + " "))
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (menu.offsetWidth !== 0) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (menu.offsetWidth !== 0) {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
* @type {false|ReturnType<typeof setTimeout>}
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (currentPointerId === null || currentPointerId !== e.pointerId) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (pendingSidebarResizingFrame !== false) {
Can lead to race conditions; consider Promises or async/await for better control
info correctness set-timeout
pendingSidebarResizingFrame = setTimeout(() => {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (currentPointerId === null || pendingSidebarResizingFrame === false) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (desiredSidebarSize !== null && desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {

Security findings 4

Use textContent or DOM methods to prevent XSS vulnerabilities
security innerhtml-xss
btnLabel.innerHTML = "Exit";
Use textContent or DOM methods to prevent XSS vulnerabilities
security innerhtml-xss
btnLabel.innerHTML = "Search";
Use textContent or DOM methods to prevent XSS vulnerabilities
security innerhtml-xss
nonnull(search).innerHTML = "<h3 class=\"search-loading\">" +
Use textContent or DOM methods to prevent XSS vulnerabilities
security innerhtml-xss
code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n");

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.