diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 085880b215d14..a71c538afd530 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -9,7 +9,7 @@ rules. margin-left: 0 !important; } -#copy-path, #sidebar-button, .sidebar-resizer { +#sidebar-button, .sidebar-resizer { /* It requires JS to work so no need to display it in this case. */ display: none !important; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index e957a13a2b038..c26d0972292f3 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -2113,34 +2113,41 @@ function preLoadCss(cssUrl) { }, 1000); } - // Copy button that appears next to the path breadcrumbs. - const but = document.getElementById("copy-path"); - if (!but) { - return; - } - but.onclick = () => { - // We get the path from the "breadcrumbs" and the actual item name. - let path = ""; - // @ts-expect-error - const heading = document.getElementById(MAIN_ID).querySelector(".main-heading"); - - if (heading) { - const breadcrumbs = heading.querySelector(".rustdoc-breadcrumbs"); - if (breadcrumbs) { - // @ts-expect-error - path = breadcrumbs.innerText; - if (path.length > 0) { - path += "::"; + const itemPath = nonnull(document.getElementById(MAIN_ID)).querySelector(".main-heading h1"); + // The best way to check it's a page where we should generate the "copy path" button is to + // check if there is a `` in the `

`. + if (itemPath && itemPath.querySelector("span")) { + // Copy button that appears next to the path breadcrumbs. + const but = document.createElement("button"); + but.id = "copy-path"; + but.setAttribute("title", "Copy item path to clipboard"); + but.innerText = "Copy item path"; + + but.onclick = () => { + const heading = nonnull( + document.getElementById(MAIN_ID)).querySelector(".main-heading"); + if (heading) { + // We get the path from the "breadcrumbs" and the actual item name. + let path = ""; + + const breadcrumbs = heading.querySelector(".rustdoc-breadcrumbs"); + if (breadcrumbs) { + // @ts-expect-error + path = breadcrumbs.innerText; + if (path.length > 0) { + path += "::"; + } } - } - // @ts-expect-error - path += heading.querySelector("h1 > span").innerText; + // @ts-expect-error + path += heading.querySelector("h1 > span").innerText; - copyContentToClipboard(path); - copyButtonAnimation(but); - } - }; + copyContentToClipboard(path); + copyButtonAnimation(but); + } + }; + itemPath.appendChild(but); + } /** * Copy buttons on code examples. diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index 4a257923dc53c..e0e762ed8beab 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -11,12 +11,9 @@ {% endif %}

{{typ}} - + {{name|wrapped|safe}}  {# #} - {# #}

{# #} {# #} diff --git a/tests/rustdoc-gui/copy-path.goml b/tests/rustdoc-gui/copy-path.goml index 1350531514443..5be9e928c164c 100644 --- a/tests/rustdoc-gui/copy-path.goml +++ b/tests/rustdoc-gui/copy-path.goml @@ -1,5 +1,6 @@ -// Checks that the "copy path" button is not triggering JS error and its display -// isn't broken and the copied path is as expected. +// Checks that the "copy path" button is not triggering JS error and its display isn't broken and +// the copied path is as expected. Also checks that the button is only present on the expected +// pages. go-to: "file://" + |DOC_PATH| + "/test_docs/foreign_impl_order/trait.Foo.html" permissions: ["clipboard-read"] @@ -7,6 +8,7 @@ permissions: ["clipboard-read"] assert-clipboard: "" // First we store the size of the button before we click on it. +wait-for: "#copy-path" store-size: ("#copy-path", {"width": width, "height": height}) click: "#copy-path" // We wait for the new text to appear. @@ -22,6 +24,7 @@ assert-size: ("#copy-path:not(.clicked)", {"width": |width|, "height": |height|} // Check the path for a module. go-to: "file://" + |DOC_PATH| + "/test_docs/foreign_impl_order/index.html" +wait-for: "#copy-path" click: "#copy-path" // We wait for the new text to appear. wait-for: "#copy-path.clicked" @@ -30,8 +33,49 @@ assert-clipboard: "test_docs::foreign_impl_order" // Check the path for the crate. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +wait-for: "#copy-path" click: "#copy-path" // We wait for the new text to appear. wait-for: "#copy-path.clicked" // We check that the clipboard value is the expected one. assert-clipboard: "test_docs" + +// Now check the presence of the "copy code" button. Above we already checked for items, crate +// and modules. +define-function: ("check-copy-path-presence", [path], block { + go-to: "file://" + |DOC_PATH| + "/test_docs/" + |path| + wait-for: "#copy-path" +}) + +// Keyword +call-function: ("check-copy-path-presence", {"path": "keyword.for.html"}) +// Attribute +call-function: ("check-copy-path-presence", {"path": "attribute.forbid.html"}) +// Macro +call-function: ("check-copy-path-presence", {"path": "macro.attr_macro.html"}) +// Constant +call-function: ("check-copy-path-presence", {"path": "constant.CONST.html"}) + +// And now we check its absence. +define-function: ("check-copy-path-absence", [path], block { + go-to: "file://" + |DOC_PATH| + "/" + |path| + expect-failure: true + wait-for: "#copy-path" + expect-failure: false +}) + +// To prevent waiting for too long, we set the maximum time for "wait-for" to 1 second. +set-timeout: 1000 + +// Source code page. +call-function: ("check-copy-path-absence", {"path": "src/test_docs/lib.rs.html"}) +// Settings page. +call-function: ("check-copy-path-absence", {"path": "settings.html"}) +// Help page. +call-function: ("check-copy-path-absence", {"path": "help.html"}) +// All items page. +call-function: ("check-copy-path-absence", {"path": "test_docs/all.html"}) + +// Check the button is not present if javascript is disabled (since it's generated with JS...). +javascript: false +call-function: ("check-copy-path-absence", {"path": "test_docs/index.html"})