8275406: Add copy-to-clipboard feature to snippet UI
Reviewed-by: erikj, jjg
This commit is contained in:
parent
9971a2cab3
commit
8630f55ed7
@ -75,7 +75,7 @@ define SetupInterimModule
|
||||
EXCLUDE_FILES := $(TOPDIR)/src/$1/share/classes/module-info.java \
|
||||
Standard.java, \
|
||||
EXTRA_FILES := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim/module-info.java, \
|
||||
COPY := .gif .png .xml .css .js .js.template .txt javax.tools.JavaCompilerTool, \
|
||||
COPY := .gif .png .xml .css .svg .js .js.template .txt javax.tools.JavaCompilerTool, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_langtools_modules/$1.interim, \
|
||||
DISABLED_WARNINGS := module options, \
|
||||
JAVAC_FLAGS := \
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,4 +23,4 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
COPY += .xml .css .js .js.template .png .txt
|
||||
COPY += .xml .css .svg .js .js.template .png .txt
|
||||
|
@ -290,6 +290,8 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
}
|
||||
f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT);
|
||||
f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true);
|
||||
f = DocFile.createFileForOutput(configuration, DocPaths.CLIPBOARD_SVG);
|
||||
f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.CLIPBOARD_SVG), true, true);
|
||||
if (options.createIndex()) {
|
||||
f = DocFile.createFileForOutput(configuration, DocPaths.SEARCH_JS);
|
||||
f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.SEARCH_JS_TEMPLATE), configuration.docResources);
|
||||
|
@ -53,6 +53,7 @@ import com.sun.source.doctree.SystemPropertyTree;
|
||||
import com.sun.source.doctree.ThrowsTree;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
@ -381,12 +382,23 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
|
||||
@Override
|
||||
protected Content snippetTagOutput(Element element, SnippetTree tag, StyledText content) {
|
||||
HtmlTree result = new HtmlTree(TagName.PRE).setStyle(HtmlStyle.snippet);
|
||||
result.add(Text.of(utils.normalizeNewlines("\n")));
|
||||
String copyText = resources.getText("doclet.Copy_snippet_to_clipboard");
|
||||
String copiedText = resources.getText("doclet.Copied_snippet_to_clipboard");
|
||||
HtmlTree copy = HtmlTree.DIV(HtmlStyle.snippetContainer,
|
||||
HtmlTree.A("#", new HtmlTree(TagName.IMG)
|
||||
.put(HtmlAttr.SRC, htmlWriter.pathToRoot.resolve(DocPaths.CLIPBOARD_SVG).getPath())
|
||||
.put(HtmlAttr.ALT, copyText))
|
||||
.addStyle(HtmlStyle.snippetCopy)
|
||||
.put(HtmlAttr.ONCLICK, "copySnippet(this)")
|
||||
.put(HtmlAttr.ARIA_LABEL, copyText)
|
||||
.put(HtmlAttr.DATA_COPIED, copiedText));
|
||||
HtmlTree pre = new HtmlTree(TagName.PRE)
|
||||
.setStyle(HtmlStyle.snippet);
|
||||
pre.add(Text.of(utils.normalizeNewlines("\n")));
|
||||
content.consumeBy((styles, sequence) -> {
|
||||
CharSequence text = utils.normalizeNewlines(sequence);
|
||||
if (styles.isEmpty()) {
|
||||
result.add(text);
|
||||
pre.add(text);
|
||||
} else {
|
||||
Element e = null;
|
||||
String t = null;
|
||||
@ -431,10 +443,10 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
c = HtmlTree.SPAN(Text.of(sequence));
|
||||
classes.forEach(((HtmlTree) c)::addStyle);
|
||||
}
|
||||
result.add(c);
|
||||
pre.add(c);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
return copy.add(pre);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -47,6 +47,7 @@ public enum HtmlAttr {
|
||||
CLEAR,
|
||||
COLS,
|
||||
CONTENT,
|
||||
DATA_COPIED("data-copied"), // custom HTML5 data attribute
|
||||
DISABLED,
|
||||
FOR,
|
||||
HREF,
|
||||
|
@ -52,6 +52,16 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public enum HtmlStyle {
|
||||
|
||||
/**
|
||||
* The class of the {@code div} element containing a snippet element.
|
||||
*/
|
||||
snippetContainer,
|
||||
|
||||
/**
|
||||
* The class of the {@code a} element to copy snippet content to the clipboard.
|
||||
*/
|
||||
snippetCopy,
|
||||
|
||||
//<editor-fold desc="navigation bar">
|
||||
//
|
||||
// The following constants are used for the main navigation bar that appears in the
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License version 2 only, as
|
||||
published by the Free Software Foundation. Oracle designates this
|
||||
particular file as subject to the "Classpath" exception as provided
|
||||
by Oracle in the LICENSE file that accompanied this code.
|
||||
|
||||
This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
version 2 for more details (a copy is included in the LICENSE file that
|
||||
accompanied this code).
|
||||
|
||||
You should have received a copy of the GNU General Public License version
|
||||
2 along with this work; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
or visit www.oracle.com if you need additional information or have any
|
||||
questions.
|
||||
-->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 460" fill="#505050">
|
||||
<path
|
||||
d="M 346,8 H 108 C 90,8 75,23 75,41 v 316 c 0,18 15,33 33,33 h 238 c 18,0 33,-15 33,-33 V 41 C 379,23 364,8 346,8 Z m -8,344 H 116 c -2,0 -3,-1 -3,-3 V 49 c 0,-2 1,-3 3,-3 h 222 c 2,0 3,1 3,3 v 300 h 10e-4 c 0,2 -1,3 -3,3 z"/>
|
||||
<path
|
||||
d="m 290,389 v 26 h 10e-4 c 0,2 -1,3 -3,3 H 49 c -2,0 -3,-1 -3,-3 V 99 c 0,-2 1,-3 3,-3 h 27 v 0 l -5e-4,-38 H 41 C 23,58 8,73 8,91 v 332 c 10e-4,18 15,33 33,33 h 254 c 18,0 33,-15 33,-33 v -34"/>
|
||||
</svg>
|
@ -54,6 +54,8 @@ for duplicates. Include error messages and the following diagnostic in your repo
|
||||
doclet.File_not_found=File not found: {0}
|
||||
doclet.Copy_Overwrite_warning=File {0} not copied to {1} due to existing file with same name...
|
||||
doclet.Copy_Ignored_warning=File {0} not copied: invalid name
|
||||
doclet.Copy_snippet_to_clipboard=Copy
|
||||
doclet.Copied_snippet_to_clipboard=Copied!
|
||||
doclet.Copying_File_0_To_Dir_1=Copying file {0} to directory {1}...
|
||||
doclet.Copying_File_0_To_File_1=Copying file {0} to file {1}...
|
||||
doclet.No_Public_Classes_To_Document=No public or protected classes found to document.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -106,6 +106,21 @@ function indexFilesLoaded() {
|
||||
&& tagSearchIndex;
|
||||
}
|
||||
|
||||
function copySnippet(link) {
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.style.height = 0;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.value = link.nextElementSibling.innerText;
|
||||
textarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(textarea);
|
||||
link.classList.add("copied");
|
||||
var parent = link.parentElement;
|
||||
parent.onmouseleave = parent.ontouchend = function() {
|
||||
link.classList.remove("copied");
|
||||
};
|
||||
}
|
||||
|
||||
// Workaround for scroll position not being included in browser history (8249133)
|
||||
document.addEventListener("DOMContentLoaded", function(e) {
|
||||
var contentDiv = document.querySelector("div.flex-content");
|
||||
|
@ -933,7 +933,67 @@ pre.snippet {
|
||||
overflow: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
div.snippet-container {
|
||||
position: relative;
|
||||
}
|
||||
a.snippet-copy {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
a.snippet-copy img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0.05em 0;
|
||||
opacity: 50%;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
div.snippet-container:hover a.snippet-copy img {
|
||||
opacity: 80%;
|
||||
}
|
||||
div.snippet-container a.snippet-copy:hover img {
|
||||
opacity: 100%;
|
||||
}
|
||||
a.snippet-copy:active img {
|
||||
background: #d3d3d3;
|
||||
opacity: 100%;
|
||||
}
|
||||
a.snippet-copy::before {
|
||||
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: absolute;
|
||||
opacity: 80%;
|
||||
transition: opacity 0.2s;
|
||||
white-space: nowrap;
|
||||
top: -0.01em;
|
||||
right: 1.5em;
|
||||
display: none;
|
||||
}
|
||||
div.snippet-container:hover a.snippet-copy::before {
|
||||
display: inherit;
|
||||
}
|
||||
div.snippet-container a.snippet-copy:hover::before {
|
||||
opacity: 100%;
|
||||
}
|
||||
a.snippet-copy.copied::before {
|
||||
content: attr(data-copied);
|
||||
}
|
||||
a.snippet-copy:active::before {
|
||||
background-color: #dadada;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
pre.snippet {
|
||||
padding-top: 26px;
|
||||
}
|
||||
a.snippet-copy {
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
}
|
||||
}
|
||||
pre.snippet .italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -97,6 +97,9 @@ public class DocPaths {
|
||||
/** The name of the default javascript file. */
|
||||
public static final DocPath JAVASCRIPT = DocPath.create("script.js");
|
||||
|
||||
/** The name of the copy-to-clipboard icon file. */
|
||||
public static final DocPath CLIPBOARD_SVG = DocPath.create("copy.svg");
|
||||
|
||||
/** The name of the stylesheet file overriding jQuery UI stylesheet. */
|
||||
public static final DocPath JQUERY_OVERRIDES_CSS = DocPath.create("jquery-ui.overrides.css");
|
||||
|
||||
|
@ -211,6 +211,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
Hello, Snippet!
|
||||
</pre>
|
||||
@ -852,6 +855,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
%s</pre>
|
||||
</div>""".formatted(id, t.expectedOutput()));
|
||||
@ -946,6 +952,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
%s</pre>
|
||||
</div>""".formatted(index, expectedOutput));
|
||||
@ -1505,6 +1514,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
%s</pre>
|
||||
</div>""".formatted(index, t.expectedOutput()));
|
||||
@ -1620,6 +1632,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case0</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="copySni\
|
||||
ppet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.svg" alt="\
|
||||
Copy"></a>
|
||||
<pre class="snippet">
|
||||
</pre>
|
||||
</div>""");
|
||||
@ -1627,6 +1642,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case1</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="copySni\
|
||||
ppet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.svg" alt="\
|
||||
Copy"></a>
|
||||
<pre class="snippet">
|
||||
</pre>
|
||||
</div>""");
|
||||
@ -1726,6 +1744,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
2</pre>
|
||||
</div>
|
||||
@ -1808,6 +1829,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
%s</pre>
|
||||
</div>""".formatted(index, t.expectedOutput()));
|
||||
@ -2138,6 +2162,9 @@ public class TestSnippetTag extends JavadocTester {
|
||||
"""
|
||||
<span class="element-name">case%s</span>()</div>
|
||||
<div class="block">
|
||||
<div class="snippet-container"><a href="#" class="snippet-copy" onclick="cop\
|
||||
ySnippet(this)" aria-label="Copy" data-copied="Copied!"><img src="../copy.sv\
|
||||
g" alt="Copy"></a>
|
||||
<pre class="snippet">
|
||||
%s</pre>
|
||||
</div>""".formatted(index, t.expectedOutput()));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -351,7 +351,7 @@ public class LinkChecker extends HtmlChecker {
|
||||
|
||||
void addReference(String name, Path from, int line) {
|
||||
if (checked) {
|
||||
if (name != null) {
|
||||
if (name != null && !name.isEmpty()) {
|
||||
ID id = map.get(name);
|
||||
if (id == null || !id.declared) {
|
||||
error(from, line, "id not found: " + this.name + "#" + name);
|
||||
@ -368,7 +368,7 @@ public class LinkChecker extends HtmlChecker {
|
||||
|
||||
void check() {
|
||||
map.forEach((name, id) -> {
|
||||
if (name != null && !id.declared) {
|
||||
if (name != null && !name.isEmpty() && !id.declared) {
|
||||
//log.error(currFile, 0, "id not declared: " + name);
|
||||
for (Position ref : id.references) {
|
||||
error(ref.path, ref.line, "id not found: " + this.name + "#" + name);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -196,6 +196,7 @@ class APITest {
|
||||
"allclasses-index.html",
|
||||
"allpackages-index.html",
|
||||
"constant-values.html",
|
||||
"copy.svg",
|
||||
"deprecated-list.html",
|
||||
"help-doc.html",
|
||||
"index-all.html",
|
||||
|
Loading…
x
Reference in New Issue
Block a user