Skip to content

Commit

Permalink
8277420: Provide a way to copy the hyperlink to a doc element to the …
Browse files Browse the repository at this point in the history
…clipboard

Reviewed-by: prappo
  • Loading branch information
hns committed May 27, 2022
1 parent 176bb23 commit 37ecbb4
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 104 deletions.
Expand Up @@ -120,7 +120,7 @@ protected void addSearchFileContents(Content contentTree) {
.put(HtmlAttr.ALT, copyText))
.add(HtmlTree.SPAN(Text.of(copyText))
.put(HtmlAttr.DATA_COPIED, copiedText))
.addStyle(HtmlStyle.copyUrl)
.addStyle(HtmlStyle.copy)
.setId(HtmlId.of("page-search-copy")))
.add(HtmlTree.P(HtmlTree.INPUT("checkbox", HtmlId.of("search-redirect")))
.add(HtmlTree.LABEL("search-redirect",
Expand Down
Expand Up @@ -459,6 +459,7 @@ protected Content snippetTagOutput(Element element, SnippetTree tag, StyledText
.add(new HtmlTree(TagName.IMG)
.put(HtmlAttr.SRC, htmlWriter.pathToRoot.resolve(DocPaths.CLIPBOARD_SVG).getPath())
.put(HtmlAttr.ALT, copyText))
.addStyle(HtmlStyle.copy)
.addStyle(HtmlStyle.snippetCopy)
.put(HtmlAttr.ONCLICK, "copySnippet(this)"));
return snippetContainer.add(pre.add(code));
Expand Down
Expand Up @@ -655,11 +655,6 @@ public enum HtmlStyle {
//
// The following constants are used for items in the static and interactive search indexes.

/**
* The class for a {@code button} in the search page to copy the search URL to the clipboard.
*/
copyUrl,

/**
* The class for a {@code details} element in the search page to show additional information.
*/
Expand Down Expand Up @@ -915,6 +910,11 @@ public enum HtmlStyle {
*/
classUses,

/**
* The class for a {@code button} element to copy some page content to the clipboard.
*/
copy,

/**
* The class of an {@code a} element for a link with an external target.
*/
Expand Down
Expand Up @@ -31,6 +31,8 @@ const messages = {
loading: "##REPLACE:doclet.search.loading##",
searching: "##REPLACE:doclet.search.searching##",
redirecting: "##REPLACE:doclet.search.redirecting##",
copyUrl: "##REPLACE:doclet.Copy_url_to_clipboard##",
urlCopied: "##REPLACE:doclet.Copied_url_to_clipboard##"
}
const categories = {
modules: "##REPLACE:doclet.search.modules##",
Expand Down Expand Up @@ -412,6 +414,16 @@ $(function() {
$("ul.sub-nav-list-small li a").click(collapse);
$("input#search-input").focus(collapse);
$("main").click(collapse);
$("section[id] > :header, :header[id], :header:has(a[id])").hover(
function () {
$(this).append($("<button class='copy copy-header' onclick='copyUrl(this)'> " +
"<img src='" + pathtoroot + "copy.svg' alt='" + messages.copyUrl + "'> " +
"<span data-copied='" + messages.urlCopied + "'></span></button>"));
},
function () {
$(this).find("button:last").remove();
}
);
$(window).on("orientationchange", collapse).on("resize", function(e) {
if (expanded && windowWidth !== window.innerWidth) collapse();
});
Expand Down
Expand Up @@ -105,27 +105,49 @@ function indexFilesLoaded() {
&& memberSearchIndex
&& tagSearchIndex;
}

// Copy the contents of the local snippet to the clipboard
function copySnippet(button) {
copyToClipboard(button.nextElementSibling.innerText);
switchCopyLabel(button.firstElementChild, button.parentElement);
}
// Copy the link to the adjacent header to the clipboard
function copyUrl(button) {
var id;
var header = button.parentElement;
if (header.hasAttribute("id")) {
id = header.getAttribute("id");
} else if (header.parentElement.tagName === 'SECTION' && header.parentElement.hasAttribute("id")) {
id = header.parentElement.getAttribute("id");
} else if (header.firstElementChild && header.firstElementChild.tagName === "A"
&& header.firstElementChild.hasAttribute("id")) {
id = header.firstElementChild.getAttribute("id");
}
var url = document.location.href;
if (url.indexOf("#") > -1) {
url = url.substring(0, url.indexOf("#"));
}
copyToClipboard(url + "#" + id);
switchCopyLabel(button.lastElementChild, button.parentElement);
}
function copyToClipboard(content) {
var textarea = document.createElement("textarea");
textarea.style.height = 0;
document.body.appendChild(textarea);
textarea.value = button.nextElementSibling.innerText;
textarea.value = content;
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
var span = button.firstElementChild;
}
function switchCopyLabel(span, parent) {
var copied = span.getAttribute("data-copied");
if (span.innerHTML !== copied) {
var initialLabel = span.innerHTML;
span.innerHTML = copied;
var parent = button.parentElement;
parent.onmouseleave = parent.ontouchend = function() {
span.innerHTML = initialLabel;
};
}
}

// Workaround for scroll position not being included in browser history (8249133)
document.addEventListener("DOMContentLoaded", function(e) {
var contentDiv = document.querySelector("div.flex-content");
Expand Down
Expand Up @@ -62,6 +62,10 @@ h5 {
h6 {
font-size:13px;
}
/* Disable font boosting */
h1, h2, h3, h4, h5, h6 {
max-height: 2em;
}
ul {
list-style-type:disc;
}
Expand Down Expand Up @@ -717,52 +721,6 @@ span#page-search-link {
background: #F8981D;
color: #253441;
}
button.copy-url {
opacity: 80%;
transition: opacity 0.2s;
margin-left: 0.4em;
border: none;
border-radius: 3px;
cursor: pointer;
background: none;
padding:0.3em;
position: relative;
top:0.13em
}
button.copy-url img {
width: 1.2em;
height: 1.2em;
padding: 0.01em 0;
background: none;
position:relative;
top: 0.15em;
}
div.page-search-info:hover button.copy-url {
opacity: 90%;
}
div.page-search-info button.copy-url:hover {
background-color: #dfe6f1;
opacity: 100%;
}
button.copy-url span {
color: #000000;
content: attr(aria-label);
font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
font-size: 85%;
line-height: 1.2em;
padding: 0.2em;
position: relative;
top: -0.18em;
transition: opacity 0.1s;
opacity: 0;
}
div.page-search-info:hover button.copy-url span {
opacity: 90%;
}
div.page-search-info button.copy-url:active {
background-color: #cfdbee;
opacity: 100%;
}
.module-graph span {
display:none;
position:absolute;
Expand Down Expand Up @@ -832,7 +790,111 @@ main a[href*="://"]:focus::after {
132-240 240 120 120 240-240 132 132V0z" fill="%23bb7a2a"/>\
</svg>');
}

/*
* Styles for copy-to-clipboard buttons
*/
button.copy {
opacity: 80%;
border: none;
border-radius: 3px;
position: relative;
background:none;
transition: opacity 0.2s;
cursor: pointer;
}
button.copy:hover,
button.copy:active {
opacity: 100%;
}
button.copy img {
position: relative;
background: none;
}
button.copy span {
color: #303030;
position: relative;
top: -0.1em;
transition: all 0.1s;
font-size: 85%;
line-height: 1.2em;
}
/* header/section copy button */
button.copy-header {
margin: 0 0.2em;
padding: 0 4px;
height: 1.35em;
}
button.copy-header img {
height: 1em;
top: 0.1em;
}
button.copy-header:active {
background-color: rgba(128, 128, 160, 0.2);
}
/* search page copy button */
button#page-search-copy {
margin-left: 0.4em;
padding:0.3em;
top:0.13em;
}
button#page-search-copy img {
width: 1.2em;
height: 1.2em;
padding: 0.01em 0;
top: 0.15em;
}
button#page-search-copy span {
color: #000000;
content: attr(aria-label);
line-height: 1.2em;
padding: 0.2em;
top: -0.18em;
opacity: 0;
}
div.page-search-info:hover button#page-search-copy,
div.page-search-info:hover button#page-search-copy span {
opacity: 90%;
}
div.page-search-info button#page-search-copy:hover {
background-color: #dfe6f1;
}
div.page-search-info button#page-search-copy:active {
background-color: #cfdbee;
}
/* snippet copy button */
button.snippet-copy {
position: absolute;
top: 6px;
right: 6px;
height: 1.7em;
opacity: 50%;
padding: 2px;
}
button.snippet-copy img {
width: 18px;
height: 18px;
padding: 0.05em 0;
}
button.snippet-copy span {
content: attr(aria-label);
line-height: 1.2em;
padding: 0.2em;
position: relative;
top: -0.5em;
display: none;
}
div.snippet-container:hover button.snippet-copy span {
display: inline;
}
div.snippet-container:hover button.snippet-copy {
opacity: 80%;
}
div.snippet-container button.snippet-copy:hover {
opacity: 100%;
}
button.snippet-copy:active {
background: #d3d3d3;
}
/*
* Styles for user-provided tables.
*
Expand Down Expand Up @@ -1067,49 +1129,6 @@ pre.snippet {
div.snippet-container {
position: relative;
}
button.snippet-copy {
position: absolute;
top: 6px;
right: 6px;
height: 1.7em;
opacity: 50%;
transition: opacity 0.2s;
padding: 2px;
border: none;
cursor: pointer;
background: none;
}
button.snippet-copy img {
width: 18px;
height: 18px;
padding: 0.05em 0;
background: none;
}
div.snippet-container:hover button.snippet-copy {
opacity: 80%;
}
div.snippet-container button.snippet-copy:hover {
opacity: 100%;
}
button.snippet-copy span {
color: #3d3d3d;
content: attr(aria-label);
font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
font-size: 85%;
line-height: 1.2em;
padding: 0.2em;
position: relative;
white-space: nowrap;
top: -0.5em;
display: none;
}
div.snippet-container:hover button.snippet-copy span {
display: inline;
}
button.snippet-copy:active {
background: #d3d3d3;
opacity: 100%;
}
@media screen and (max-width: 800px) {
pre.snippet {
padding-top: 26px;
Expand Down
Expand Up @@ -135,7 +135,7 @@ void run() throws Exception {
removeAll(styleSheetNames, "borderless", "plain", "striped");

// used in search.js and search-page.js; may be worth documenting in HtmlStyle
removeAll(styleSheetNames, "result-highlight", "result-item",
removeAll(styleSheetNames, "result-highlight", "result-item", "copy-header",
"search-tag-desc-result", "search-tag-holder-result", "page-search-header",
"ui-autocomplete", "ui-autocomplete-category", "expanded",
"search-result-link", "two-column-search-results", "ui-static-link");
Expand Down
Expand Up @@ -119,7 +119,7 @@ protected String getSnippetHtmlRepresentation(String pathToHtmlFile,
var idString = id.isEmpty() ? "" : " id=\"%s\"".formatted(id.get());
var langString = lang.isEmpty() ? "" : " class=\"language-%s\"".formatted(lang.get());
return """
<div class="snippet-container"><button class="snippet-copy" onclick="copySnippet(this)">\
<div class="snippet-container"><button class="copy snippet-copy" onclick="copySnippet(this)">\
<span data-copied="Copied!">Copy</span><img src="%s" alt="Copy"></button>
<pre class="snippet"%s><code%s>%s</code></pre>
</div>""".formatted(svgString, idString, langString, content);
Expand Down
Expand Up @@ -87,7 +87,8 @@ private C() { }
"""
Before.
\s
<div class="snippet-container"><button class="snippet-copy" onclick="copySnippet(this)"><span data-copied="Copied!">Copy</span><img src="copy.svg" alt="Copy"></button>
<div class="snippet-container"><button class="copy snippet-copy" onclick="copySnippet\
(this)"><span data-copied="Copied!">Copy</span><img src="copy.svg" alt="Copy"></button>
<pre class="snippet"><code class="language-java">public class S { }</code></pre>
</div>
Expand Down

1 comment on commit 37ecbb4

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.