diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 161b95d99930e..4d13956c3758b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -54,7 +54,6 @@ function resourcePath(basename, extension) { return getVar("root-path") + basename + getVar("resource-suffix") + extension; } - (function () { window.rootPath = getVar("root-path"); window.currentCrate = getVar("current-crate"); @@ -232,7 +231,7 @@ function hideThemeButtonState() { document.title = searchState.titleBeforeSearch; // We also remove the query parameter from the URL. if (searchState.browserSupportsHistoryApi()) { - history.replaceState("", window.currentCrate + " - Rust", + history.replaceState(null, window.currentCrate + " - Rust", getNakedUrl() + window.location.hash); } }, @@ -246,18 +245,6 @@ function hideThemeButtonState() { }); return params; }, - putBackSearch: function(search_input) { - var search = searchState.outputElement(); - if (search_input.value !== "" && hasClass(search, "hidden")) { - searchState.showResults(search); - if (searchState.browserSupportsHistoryApi()) { - var extra = "?search=" + encodeURIComponent(search_input.value); - history.replaceState(search_input.value, "", - getNakedUrl() + extra + window.location.hash); - } - document.title = searchState.title; - } - }, browserSupportsHistoryApi: function() { return window.history && typeof window.history.pushState === "function"; }, @@ -282,14 +269,10 @@ function hideThemeButtonState() { } search_input.addEventListener("focus", function() { - searchState.putBackSearch(this); - search_input.origPlaceholder = searchState.input.placeholder; + search_input.origPlaceholder = search_input.placeholder; search_input.placeholder = "Type your search here."; loadSearch(); }); - search_input.addEventListener("blur", function() { - search_input.placeholder = searchState.input.origPlaceholder; - }); if (search_input.value != '') { loadSearch(); @@ -330,7 +313,7 @@ function hideThemeButtonState() { var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1); if (searchState.browserSupportsHistoryApi()) { // `window.location.search`` contains all the query parameters, not just `search`. - history.replaceState(hash, "", + history.replaceState(null, "", getNakedUrl() + window.location.search + "#" + hash); } elem = document.getElementById(hash); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 104464b388114..8c832a222b74d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1,5 +1,5 @@ /* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */ -/* global onEachLazy, removeClass, searchState, updateLocalStorage */ +/* global onEachLazy, removeClass, searchState, hasClass */ (function() { // This mapping table should match the discriminants of @@ -133,6 +133,39 @@ window.initSearch = function(rawSearchIndex) { searchState.input.value = params.search || ""; } + /** + * Build an URL with search parameters. + * + * @param {string} search - The current search being performed. + * @param {string|null} filterCrates - The current filtering crate (if any). + * @return {string} + */ + function buildUrl(search, filterCrates) { + var extra = "?search=" + encodeURIComponent(search); + + if (filterCrates !== null) { + extra += "&filter-crate=" + encodeURIComponent(filterCrates); + } + return getNakedUrl() + extra + window.location.hash; + } + + /** + * Return the filtering crate or `null` if there is none. + * + * @return {string|null} + */ + function getFilterCrates() { + var elem = document.getElementById("crate-search"); + + if (elem && + elem.value !== "All crates" && + hasOwnPropertyRustdoc(rawSearchIndex, elem.value)) + { + return elem.value; + } + return null; + } + /** * Executes the query and returns a list of results for each results tab. * @param {Object} query - The user query @@ -595,7 +628,7 @@ window.initSearch = function(rawSearchIndex) { // aliases to be before the others in the displayed results. var aliases = []; var crateAliases = []; - if (filterCrates !== undefined) { + if (filterCrates !== null) { if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) { var query_aliases = ALIASES[filterCrates][query.search]; var len = query_aliases.length; @@ -694,7 +727,7 @@ window.initSearch = function(rawSearchIndex) { { val = extractGenerics(val.substr(1, val.length - 2)); for (i = 0; i < nSearchWords; ++i) { - if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) { + if (filterCrates !== null && searchIndex[i].crate !== filterCrates) { continue; } in_args = findArg(searchIndex[i], val, true, typeFilter); @@ -725,7 +758,7 @@ window.initSearch = function(rawSearchIndex) { var output = extractGenerics(parts[1]); for (i = 0; i < nSearchWords; ++i) { - if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) { + if (filterCrates !== null && searchIndex[i].crate !== filterCrates) { continue; } var type = searchIndex[i].type; @@ -781,7 +814,7 @@ window.initSearch = function(rawSearchIndex) { var lev, j; for (j = 0; j < nSearchWords; ++j) { ty = searchIndex[j]; - if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) { + if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) { continue; } var lev_add = 0; @@ -1279,17 +1312,6 @@ window.initSearch = function(rawSearchIndex) { }; } - function getFilterCrates() { - var elem = document.getElementById("crate-search"); - - if (elem && elem.value !== "All crates" && - hasOwnPropertyRustdoc(rawSearchIndex, elem.value)) - { - return elem.value; - } - return undefined; - } - /** * Perform a search based on the current state of the search input element * and display the results. @@ -1309,27 +1331,34 @@ window.initSearch = function(rawSearchIndex) { } if (!forced && query.id === currentResults) { if (query.query.length > 0) { - searchState.putBackSearch(searchState.input); + putBackSearch(); } return; } + var filterCrates = getFilterCrates(); + + // In case we have no information about the saved crate and there is a URL query parameter, + // we override it with the URL query parameter. + if (filterCrates === null && params["filter-crate"] !== undefined) { + filterCrates = params["filter-crate"]; + } + // Update document title to maintain a meaningful browser history searchState.title = "Results for " + query.query + " - Rust"; // Because searching is incremental by character, only the most // recent search query is added to the browser history. if (searchState.browserSupportsHistoryApi()) { - var newURL = getNakedUrl() + "?search=" + encodeURIComponent(query.raw) + - window.location.hash; + var newURL = buildUrl(query.raw, filterCrates); + if (!history.state && !params.search) { - history.pushState(query, "", newURL); + history.pushState(null, "", newURL); } else { - history.replaceState(query, "", newURL); + history.replaceState(null, "", newURL); } } - var filterCrates = getFilterCrates(); showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"], filterCrates); } @@ -1495,12 +1524,28 @@ window.initSearch = function(rawSearchIndex) { search(); } + function putBackSearch() { + var search_input = searchState.input; + if (!searchState.input) { + return; + } + var search = searchState.outputElement(); + if (search_input.value !== "" && hasClass(search, "hidden")) { + searchState.showResults(search); + if (searchState.browserSupportsHistoryApi()) { + history.replaceState(null, "", + buildUrl(search_input.value, getFilterCrates())); + } + document.title = searchState.title; + } + } + function registerSearchEvents() { var searchAfter500ms = function() { searchState.clearInputTimeout(); if (searchState.input.value.length === 0) { if (searchState.browserSupportsHistoryApi()) { - history.replaceState("", window.currentCrate + " - Rust", + history.replaceState(null, window.currentCrate + " - Rust", getNakedUrl() + window.location.hash); } searchState.hideResults(); @@ -1567,6 +1612,14 @@ window.initSearch = function(rawSearchIndex) { } }); + searchState.input.addEventListener("focus", function() { + putBackSearch(); + }); + + searchState.input.addEventListener("blur", function() { + searchState.input.placeholder = searchState.input.origPlaceholder; + }); + // Push and pop states are used to add search results to the browser // history. if (searchState.browserSupportsHistoryApi()) { @@ -1619,7 +1672,16 @@ window.initSearch = function(rawSearchIndex) { } function updateCrate(ev) { - updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value); + if (ev.target.value === "All crates") { + // If we don't remove it from the URL, it'll be picked up again by the search. + var params = searchState.getQueryStringParams(); + var query = searchState.input.value.trim(); + if (!history.state && !params.search) { + history.pushState(null, "", buildUrl(query, null)); + } else { + history.replaceState(null, "", buildUrl(query, null)); + } + } // In case you "cut" the entry from the search input, then change the crate filter // before paste back the previous search, you get the old search results without // the filter. To prevent this, we need to remove the previous results. @@ -1629,10 +1691,15 @@ window.initSearch = function(rawSearchIndex) { searchWords = buildIndex(rawSearchIndex); registerSearchEvents(); - // If there's a search term in the URL, execute the search now. - if (searchState.getQueryStringParams().search) { - search(); + + function runSearchIfNeeded() { + // If there's a search term in the URL, execute the search now. + if (searchState.getQueryStringParams().search) { + search(); + } } + + runSearchIfNeeded(); }; if (window.searchIndex !== undefined) { diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 47a8fcdfd5ecf..139fa5c9a11a6 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -4,7 +4,7 @@ (function () { function changeSetting(settingName, value) { - updateLocalStorage("rustdoc-" + settingName, value); + updateLocalStorage(settingName, value); switch (settingName) { case "theme": diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 498f60e9f25ae..90490acccfdb5 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -82,11 +82,11 @@ function toggleSidebar() { if (child.innerText === ">") { sidebar.classList.add("expanded"); child.innerText = "<"; - updateLocalStorage("rustdoc-source-sidebar-show", "true"); + updateLocalStorage("source-sidebar-show", "true"); } else { sidebar.classList.remove("expanded"); child.innerText = ">"; - updateLocalStorage("rustdoc-source-sidebar-show", "false"); + updateLocalStorage("source-sidebar-show", "false"); } } @@ -97,7 +97,7 @@ function createSidebarToggle() { var inner = document.createElement("div"); - if (getCurrentValue("rustdoc-source-sidebar-show") === "true") { + if (getCurrentValue("source-sidebar-show") === "true") { inner.innerText = "<"; } else { inner.innerText = ">"; @@ -120,7 +120,7 @@ function createSourceSidebar() { var sidebar = document.createElement("div"); sidebar.id = "source-sidebar"; - if (getCurrentValue("rustdoc-source-sidebar-show") !== "true") { + if (getCurrentValue("source-sidebar-show") !== "true") { container.classList.remove("expanded"); } else { container.classList.add("expanded"); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 06bb34eb11573..ccf3d0a581a17 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -15,7 +15,7 @@ var settingsDataset = (function () { })(); function getSettingValue(settingName) { - var current = getCurrentValue('rustdoc-' + settingName); + var current = getCurrentValue(settingName); if (current !== null) { return current; } @@ -106,7 +106,7 @@ function hasOwnPropertyRustdoc(obj, property) { function updateLocalStorage(name, value) { try { - window.localStorage.setItem(name, value); + window.localStorage.setItem("rustdoc-" + name, value); } catch(e) { // localStorage is not accessible, do nothing } @@ -114,7 +114,7 @@ function updateLocalStorage(name, value) { function getCurrentValue(name) { try { - return window.localStorage.getItem(name); + return window.localStorage.getItem("rustdoc-" + name); } catch(e) { return null; } @@ -127,7 +127,7 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { // If this new value comes from a system setting or from the previously // saved theme, no need to save it. if (saveTheme) { - updateLocalStorage("rustdoc-theme", newTheme); + updateLocalStorage("theme", newTheme); } if (styleElem.href === newHref) { @@ -158,7 +158,7 @@ function useSystemTheme(value) { value = true; } - updateLocalStorage("rustdoc-use-system-theme", value); + updateLocalStorage("use-system-theme", value); // update the toggle if we're on the settings page var toggle = document.getElementById("use-system-theme"); @@ -231,7 +231,7 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { if (getSettingValue("use-system-theme") === null && getSettingValue("preferred-dark-theme") === null && darkThemes.indexOf(localStoredTheme) >= 0) { - updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); + updateLocalStorage("preferred-dark-theme", localStoredTheme); } // call the function to initialize the theme at least once! diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index 98ca40512ee3c..73d310fc5c9cc 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -11,8 +11,38 @@ wait-for: "#crate-search" click: "#crate-search" // We select "lib2" option then press enter to change the filter. press-key: "ArrowDown" +press-key: "ArrowDown" press-key: "Enter" // Waiting for the search results to appear... wait-for: "#titles" // We check that there is no more "test_docs" appearing. assert-false: "#results .externcrate" +// We also check that "lib2" is the filter crate. +assert-property: ("#crate-search", {"value": "lib2"}) + +// Now we check that leaving the search results and putting them back keeps the +// crate filtering. +press-key: "Escape" +wait-for: 100 +assert-css: ("#main-content", {"display": "block"}) +focus: ".search-input" +wait-for: 100 +assert-css: ("#main-content", {"display": "none"}) +// We check that there is no more "test_docs" appearing. +assert-false: "#results .externcrate" +assert-property: ("#crate-search", {"value": "lib2"}) + +// Selecting back "All crates" +click: "#crate-search" +press-key: "ArrowUp" +press-key: "ArrowUp" +press-key: "Enter" +// Waiting for the search results to appear... +wait-for: "#titles" +assert-property: ("#crate-search", {"value": "All crates"}) + +// Checking that the URL parameter is taken into account for crate filtering. +goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2 +wait-for: "#crate-search" +assert-property: ("#crate-search", {"value": "lib2"}) +assert-false: "#results .externcrate" diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 4f73a7f634098..dbf5cf9650c5f 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -357,6 +357,8 @@ function runChecks(testFile, loaded, index) { var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'; if (testFileContent.indexOf("FILTER_CRATE") !== -1) { testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;"; + } else { + testFileContent += "exports.FILTER_CRATE = null;"; } var loadedFile = loadContent(testFileContent);