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"})