Skip to content

Commit 0353245

Browse files
committed
8325874: Improve checkbox-based interface in summary pages
Reviewed-by: prappo
1 parent 4d64467 commit 0353245

File tree

9 files changed

+90
-87
lines changed

9 files changed

+90
-87
lines changed

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
import com.sun.source.doctree.DeprecatedTree;
3333

3434
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
35-
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
36-
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
3735
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
3836
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
3937
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
@@ -83,10 +81,19 @@ protected void addContentSelectors(Content target) {
8381
if (releases.size() > 1) {
8482
Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, contents.getContent(
8583
"doclet.Deprecated_API_Checkbox_Label"));
86-
for (int i = 0; i < releases.size(); i++) {
87-
// Table column ids are 1-based
88-
tabs.add(Text.of(" ")).add(getReleaseCheckbox(releases.get(i), i + 1));
84+
// Table column ids are 1-based
85+
int index = 1;
86+
for (String release : releases) {
87+
// Empty string represents other/uncategorized releases. Since we can't make any assumptions
88+
// about release names this is arguably the safest way to avoid naming collisions.
89+
Content label = !release.isEmpty()
90+
? Text.of(release)
91+
: contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases");
92+
String id = release.isEmpty() ? ID_OTHER : String.valueOf(index++);
93+
tabs.add(Text.of(" ")).add(getCheckbox(label, id, "release-"));
8994
}
95+
tabs.add(Text.of(" ")).add(getCheckbox(
96+
contents.getContent("doclet.Deprecated_API_Checkbox_All_Releases"), ID_ALL, "release-"));
9097
target.add(tabs);
9198
}
9299
}
@@ -97,23 +104,6 @@ protected void addExtraSection(Content content) {
97104
TERMINALLY_DEPRECATED_KEY, "doclet.Element", content);
98105
}
99106

100-
private Content getReleaseCheckbox(String name, int index) {
101-
// Empty string represents other/uncategorized releases. Since we can't make any assumptions
102-
// about release names this is arguably the safest way to avoid naming collisions.
103-
boolean isOtherReleases = name.isEmpty();
104-
Content releaseLabel = isOtherReleases
105-
? contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases")
106-
: Text.of(name);
107-
HtmlId htmlId = HtmlId.of("release-" + index);
108-
String releaseId = isOtherReleases ? "" : Integer.toString(index);
109-
return HtmlTree.LABEL(htmlId.name(),
110-
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
111-
.put(HtmlAttr.CHECKED, "")
112-
.put(HtmlAttr.ONCLICK,
113-
"toggleGlobal(this, '" + releaseId + "', 3)"))
114-
.add(HtmlTree.SPAN(releaseLabel));
115-
}
116-
117107
@Override
118108
protected void addExtraIndexLink(Content target) {
119109
if (!builder.getForRemoval().isEmpty()) {
@@ -139,7 +129,6 @@ protected void addTableTabs(Table<Element> table, String headingKey) {
139129
}
140130
if (releases.size() > 1) {
141131
table.setDefaultTab(getTableCaption(headingKey))
142-
.setAlwaysShowDefaultTab(true)
143132
.setRenderTabs(false);
144133
for (String release : releases) {
145134
Content tab = TERMINALLY_DEPRECATED_KEY.equals(headingKey)

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,17 @@ protected String getTitleKey() {
7979

8080
@Override
8181
protected void addContentSelectors(Content content) {
82-
List<String> releases = configuration.newAPIPageBuilder.releases;
82+
List<String> releases = builder.releases;
8383
if (releases.size() > 1) {
8484
Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes,
8585
contents.getContent("doclet.New_API_Checkbox_Label"));
86-
for (int i = 0; i < releases.size(); i++) {
87-
int releaseIndex = i + 1;
88-
String release = releases.get(i);
89-
HtmlId htmlId = HtmlId.of("release-" + releaseIndex);
90-
tabs.add(Text.of(" ")).add(HtmlTree.LABEL(htmlId.name(),
91-
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
92-
.put(HtmlAttr.CHECKED, "")
93-
.put(HtmlAttr.ONCLICK,
94-
"toggleGlobal(this, '" + releaseIndex + "', 3)"))
95-
.add(HtmlTree.SPAN(Text.of(release))));
86+
// Table column ids are 1-based
87+
int index = 1;
88+
for (String release : releases) {
89+
tabs.add(Text.of(" ")).add(getCheckbox(Text.of(release), String.valueOf(index++), "release-"));
9690
}
91+
Content label = contents.getContent("doclet.New_API_Checkbox_All_Releases");
92+
tabs.add(Text.of(" ")).add(getCheckbox(label, ID_ALL, "release-"));
9793
content.add(tabs);
9894
}
9995
}
@@ -104,7 +100,6 @@ protected void addTableTabs(Table<Element> table, String headingKey) {
104100
List<String> releases = builder.releases;
105101
if (releases.size() > 1) {
106102
table.setDefaultTab(getTableCaption(headingKey))
107-
.setAlwaysShowDefaultTab(true)
108103
.setRenderTabs(false);
109104
for (String release : releases) {
110105
table.addTab(

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@
3333
import com.sun.source.doctree.DocTree;
3434

3535
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
36-
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
37-
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
36+
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
3837
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
3938
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
4039
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
@@ -80,21 +79,17 @@ protected String getTitleKey() {
8079
protected void addContentSelectors(Content target) {
8180
Set<PreviewAPIListBuilder.JEP> jeps = builder.getJEPs();
8281
if (!jeps.isEmpty()) {
83-
int index = 0;
82+
int index = 1;
8483
target.add(HtmlTree.P(contents.getContent("doclet.Preview_API_Checkbox_Label")));
85-
Content list = HtmlTree.UL(HtmlStyle.previewFeatureList);
84+
Content list = HtmlTree.UL(HtmlStyle.previewFeatureList).addStyle(HtmlStyle.checkboxes);
8685
for (var jep : jeps) {
87-
index++;
88-
HtmlId htmlId = HtmlId.of("feature-" + index);
8986
String jepUrl = resources.getText("doclet.Preview_JEP_URL", jep.number());
90-
list.add(HtmlTree.LI(HtmlTree.LABEL(htmlId.name(),
91-
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
92-
.put(HtmlAttr.CHECKED, "")
93-
.put(HtmlAttr.ONCLICK,
94-
"toggleGlobal(this, '" + index + "', 3)"))
95-
.add(HtmlTree.SPAN(Text.of(jep.number() + ": "))
96-
.add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")"))))));
87+
Content label = new ContentBuilder(Text.of(jep.number() + ": "))
88+
.add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")")));
89+
list.add(HtmlTree.LI(getCheckbox(label, String.valueOf(index++), "feature-")));
9790
}
91+
Content label = contents.getContent("doclet.Preview_API_Checkbox_Toggle_All");
92+
list.add(HtmlTree.LI(getCheckbox(label, ID_ALL, "feature-")));
9893
target.add(list);
9994
}
10095
}
@@ -113,7 +108,6 @@ protected void addComments(Element e, Content desc) {
113108
protected void addTableTabs(Table<Element> table, String headingKey) {
114109
table.setGridStyle(HtmlStyle.threeColumnSummary)
115110
.setDefaultTab(getTableCaption(headingKey))
116-
.setAlwaysShowDefaultTab(true)
117111
.setRenderTabs(false);
118112
for (PreviewAPIListBuilder.JEP jep : builder.getJEPs()) {
119113
table.addTab(Text.EMPTY, element -> jep == builder.getJEP(element));
@@ -122,7 +116,7 @@ protected void addTableTabs(Table<Element> table, String headingKey) {
122116

123117
@Override
124118
protected Content getExtraContent(Element element) {
125-
PreviewAPIListBuilder.JEP jep = configuration.previewAPIListBuilder.getJEP(element);
119+
PreviewAPIListBuilder.JEP jep = builder.getJEP(element);
126120
return jep == null ? Text.EMPTY : Text.of(jep.title());
127121
}
128122

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import javax.lang.model.element.PackageElement;
3333

3434
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
35+
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
3536
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
3637
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
3738
import jdk.javadoc.internal.doclets.formats.html.markup.Script;
@@ -54,6 +55,9 @@
5455
*/
5556
public abstract class SummaryListWriter<B extends SummaryAPIListBuilder> extends SubWriterHolderWriter {
5657

58+
final protected String ID_OTHER = "other";
59+
final protected String ID_ALL = "all";
60+
5761
protected String getHeadingKey(SummaryElementKind kind) {
5862
return switch (kind) {
5963
case MODULE -> "doclet.Modules";
@@ -294,6 +298,25 @@ protected Content getSummaryLink(Element e) {
294298
return writer.getSummaryLink(e);
295299
}
296300

301+
/**
302+
* Create a checkbox input element and associated label for selecting content on
303+
* a summary page.
304+
*
305+
* @param label The label
306+
* @param id the id of the selected content
307+
* @param htmlPrefix the prefix for the HTML id
308+
* @return a content object containing the checkbox input
309+
*/
310+
protected Content getCheckbox(Content label, String id, String htmlPrefix) {
311+
String htmlId = htmlPrefix + id;
312+
return HtmlTree.LABEL(htmlId,
313+
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of(htmlId))
314+
.put(HtmlAttr.CHECKED, "")
315+
.put(HtmlAttr.ONCLICK,
316+
"toggleGlobal(this, '" + id + "', 3)"))
317+
.add(HtmlTree.SPAN(label));
318+
}
319+
297320
/**
298321
* Add an extra optional section to the content.
299322
*

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ public class Table<T> extends Content {
8484
private HtmlStyle gridStyle;
8585
private final List<Content> bodyRows;
8686
private HtmlId id;
87-
private boolean alwaysShowDefaultTab = false;
8887

8988
/**
9089
* A record containing the data for a table tab.
@@ -147,16 +146,6 @@ public Table<T> setDefaultTab(Content label) {
147146
return this;
148147
}
149148

150-
/**
151-
* Sets whether to display the default tab even if tabs are empty or only contain a single tab.
152-
* @param showDefaultTab true if default tab should always be shown
153-
* @return this object
154-
*/
155-
public Table<T> setAlwaysShowDefaultTab(boolean showDefaultTab) {
156-
this.alwaysShowDefaultTab = showDefaultTab;
157-
return this;
158-
}
159-
160149
/**
161150
* Allows to set whether tabs should be rendered for this table. Some pages use their
162151
* own controls to select table categories, in which case the tabs are omitted.
@@ -385,7 +374,7 @@ private Content toContent() {
385374
}
386375

387376
var table = HtmlTree.DIV(tableStyle).addStyle(gridStyle);
388-
if ((tabs == null || occurringTabs.size() == 1) && !alwaysShowDefaultTab) {
377+
if ((tabs == null || occurringTabs.size() == 1) && renderTabs) {
389378
if (tabs == null) {
390379
main.add(caption);
391380
} else {
@@ -401,15 +390,13 @@ private Content toContent() {
401390
HtmlId defaultTabId = HtmlIds.forTab(id, 0);
402391
if (renderTabs) {
403392
tablist.add(createTab(defaultTabId, HtmlStyle.activeTableTab, true, defaultTab));
404-
} else {
405-
tablist.add(getCaption(defaultTab));
406-
}
407-
if (renderTabs) {
408393
for (var tab : tabs) {
409394
if (occurringTabs.contains(tab)) {
410395
tablist.add(createTab(HtmlIds.forTab(id, tab.index()), HtmlStyle.tableTab, false, tab.label()));
411396
}
412397
}
398+
} else {
399+
tablist.add(getCaption(defaultTab));
413400
}
414401
if (id == null) {
415402
throw new IllegalStateException("no id set for table");

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,23 @@ function sortTable(header, columnIndex, columns) {
9797

9898
// Toggles the visibility of a table category in all tables in a page
9999
function toggleGlobal(checkbox, selected, columns) {
100-
var display = checkbox.checked ? '' : 'none';
101-
document.querySelectorAll("div.table-tabs").forEach(function(t) {
102-
var id = t.parentElement.getAttribute("id");
103-
var selectedClass = id + "-tab" + selected;
104-
// if selected is empty string it selects all uncategorized entries
105-
var selectUncategorized = !Boolean(selected);
100+
const display = checkbox.checked ? '' : 'none';
101+
const selectOther = selected === "other";
102+
const selectAll = selected === "all";
103+
if (selectAll) {
104+
document.querySelectorAll('.checkboxes input[type="checkbox"]').forEach(c => {
105+
c.checked = checkbox.checked;
106+
});
107+
}
108+
document.querySelectorAll("div.table-tabs").forEach(t => {
109+
const id = t.parentElement.getAttribute("id");
110+
const selectedClass = id + "-tab" + (selectOther ? "" : selected);
106111
var visible = 0;
107-
document.querySelectorAll('div.' + id)
112+
t.parentElement.querySelectorAll('div.' + id)
108113
.forEach(function(elem) {
109-
if (selectUncategorized) {
110-
if (elem.className.indexOf(selectedClass) === -1) {
111-
elem.style.display = display;
112-
}
113-
} else if (elem.classList.contains(selectedClass)) {
114+
if (selectAll
115+
|| (!selectOther && elem.classList.contains(selectedClass))
116+
|| (selectOther && elem.className.indexOf(selectedClass) < 0)) {
114117
elem.style.display = display;
115118
}
116119
if (elem.style.display === '') {

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,20 @@ doclet.tag.invalid_input=invalid input: ''{0}''
116116
doclet.tag.invalid=invalid @{0}
117117
doclet.Deprecated_API=Deprecated API
118118
doclet.Deprecated_API_Checkbox_Label=Show API deprecated in:
119+
doclet.Deprecated_API_Checkbox_All_Releases=all
119120
doclet.Deprecated_API_Checkbox_Other_Releases=other
120121
doclet.Deprecated_Elements=Deprecated {0}
121122
doclet.Deprecated_Elements_Release_Column_Header=Deprecated in
122123
doclet.Deprecated_In_Release=Deprecated in {0}
123124
doclet.New_API=New API
124125
doclet.New_API_Checkbox_Label=Show API added in:
126+
doclet.New_API_Checkbox_All_Releases=all
125127
doclet.New_Elements=New {0}
126128
doclet.New_Elements_Release_Column_Header=Added in
127129
doclet.New_Label=New
128130
doclet.Preview_API=Preview API
129131
doclet.Preview_API_Checkbox_Label=Show preview API for:
132+
doclet.Preview_API_Checkbox_Toggle_All=Toggle all
130133
doclet.Preview_JEP_URL=https://openjdk.org/jeps/{0}
131134
doclet.Preview_Label=Preview
132135
doclet.Preview_Mark=PREVIEW

test/langtools/jdk/javadoc/doclet/testNewApiList/TestNewApiList.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8263468 8269401 8268422 8287524
26+
* @bug 8263468 8269401 8268422 8287524 8325874
2727
* @summary New page for "recent" new API
2828
* @library ../../lib
2929
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -115,7 +115,9 @@ private void checkMultiReleaseContents() {
115115
<input type="checkbox" id="release-5" disabled checked onclick="toggleGlobal(this, '5', 3)">
116116
<span>3.2</span></label> <label for="release-6">
117117
<input type="checkbox" id="release-6" disabled checked onclick="toggleGlobal(this, '6', 3)">
118-
<span>5</span></label></div>
118+
<span>5</span></label> <label for="release-all">
119+
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
120+
<span>all</span></label></div>
119121
<h2 title="Contents">Contents</h2>
120122
<ul class="contents-list">
121123
<li id="contents-module"><a href="#module">Modules</a></li>
@@ -604,9 +606,11 @@ private void checkSingleReleaseDeprecatedElements() {
604606
</div>
605607
<div class="checkboxes">Show API deprecated in: <label for="release-1">
606608
<input type="checkbox" id="release-1" disabled checked onclick="toggleGlobal(this, '1', 3)">
607-
<span>5</span></label> <label for="release-2">
608-
<input type="checkbox" id="release-2" disabled checked onclick="toggleGlobal(this, '', 3)">
609-
<span>other</span></label></div>
609+
<span>5</span></label> <label for="release-other">
610+
<input type="checkbox" id="release-other" disabled checked onclick="toggleGlobal(this, 'other', 3)">
611+
<span>other</span></label> <label for="release-all">
612+
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
613+
<span>all</span></label></div>
610614
<h2 title="Contents">Contents</h2>
611615
<ul class="contents-list">
612616
<li id="contents-for-removal"><a href="#for-removal">Terminally Deprecated</a></li>
@@ -677,7 +681,9 @@ private void checkPackageContents() {
677681
<input type="checkbox" id="release-4" disabled checked onclick="toggleGlobal(this, '4', 3)">
678682
<span>5</span></label> <label for="release-5">
679683
<input type="checkbox" id="release-5" disabled checked onclick="toggleGlobal(this, '5', 3)">
680-
<span>6</span></label></div>
684+
<span>6</span></label> <label for="release-all">
685+
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
686+
<span>all</span></label></div>
681687
<h2 title="Contents">Contents</h2>
682688
<ul class="contents-list">
683689
<li id="contents-class"><a href="#class">Classes</a></li>

test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8250768 8261976 8277300 8282452 8287597 8325325
26+
* @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874
2727
* @summary test generated docs for items declared using preview
2828
* @library ../../lib
2929
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -78,10 +78,13 @@ public void testPreviewAPIJavadoc() {
7878

7979
checkOutput("preview-list.html", true,
8080
"""
81-
<ul class="preview-feature-list">
81+
<ul class="preview-feature-list checkboxes">
8282
<li><label for="feature-1">
8383
<input type="checkbox" id="feature-1" disabled checked onclick="toggleGlobal(this, '1', 3)">
8484
<span>0: <a href="https://openjdk.org/jeps/0">Test Feature (Preview)</a></span></label></li>
85+
<li><label for="feature-all">
86+
<input type="checkbox" id="feature-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
87+
<span>Toggle all</span></label></li>
8588
</ul>
8689
<h2 title="Contents">Contents</h2>
8790
<ul class="contents-list">

0 commit comments

Comments
 (0)