8325874: Improve checkbox-based interface in summary pages
Reviewed-by: prappo
This commit is contained in:
parent
4d64467444
commit
035324503f
@ -32,8 +32,6 @@ import javax.lang.model.element.Element;
|
||||
import com.sun.source.doctree.DeprecatedTree;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
||||
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;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||
@ -83,10 +81,19 @@ public class DeprecatedListWriter extends SummaryListWriter<DeprecatedAPIListBui
|
||||
if (releases.size() > 1) {
|
||||
Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, contents.getContent(
|
||||
"doclet.Deprecated_API_Checkbox_Label"));
|
||||
for (int i = 0; i < releases.size(); i++) {
|
||||
// Table column ids are 1-based
|
||||
tabs.add(Text.of(" ")).add(getReleaseCheckbox(releases.get(i), i + 1));
|
||||
// Table column ids are 1-based
|
||||
int index = 1;
|
||||
for (String release : releases) {
|
||||
// Empty string represents other/uncategorized releases. Since we can't make any assumptions
|
||||
// about release names this is arguably the safest way to avoid naming collisions.
|
||||
Content label = !release.isEmpty()
|
||||
? Text.of(release)
|
||||
: contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases");
|
||||
String id = release.isEmpty() ? ID_OTHER : String.valueOf(index++);
|
||||
tabs.add(Text.of(" ")).add(getCheckbox(label, id, "release-"));
|
||||
}
|
||||
tabs.add(Text.of(" ")).add(getCheckbox(
|
||||
contents.getContent("doclet.Deprecated_API_Checkbox_All_Releases"), ID_ALL, "release-"));
|
||||
target.add(tabs);
|
||||
}
|
||||
}
|
||||
@ -97,23 +104,6 @@ public class DeprecatedListWriter extends SummaryListWriter<DeprecatedAPIListBui
|
||||
TERMINALLY_DEPRECATED_KEY, "doclet.Element", content);
|
||||
}
|
||||
|
||||
private Content getReleaseCheckbox(String name, int index) {
|
||||
// Empty string represents other/uncategorized releases. Since we can't make any assumptions
|
||||
// about release names this is arguably the safest way to avoid naming collisions.
|
||||
boolean isOtherReleases = name.isEmpty();
|
||||
Content releaseLabel = isOtherReleases
|
||||
? contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases")
|
||||
: Text.of(name);
|
||||
HtmlId htmlId = HtmlId.of("release-" + index);
|
||||
String releaseId = isOtherReleases ? "" : Integer.toString(index);
|
||||
return HtmlTree.LABEL(htmlId.name(),
|
||||
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
|
||||
.put(HtmlAttr.CHECKED, "")
|
||||
.put(HtmlAttr.ONCLICK,
|
||||
"toggleGlobal(this, '" + releaseId + "', 3)"))
|
||||
.add(HtmlTree.SPAN(releaseLabel));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addExtraIndexLink(Content target) {
|
||||
if (!builder.getForRemoval().isEmpty()) {
|
||||
@ -139,7 +129,6 @@ public class DeprecatedListWriter extends SummaryListWriter<DeprecatedAPIListBui
|
||||
}
|
||||
if (releases.size() > 1) {
|
||||
table.setDefaultTab(getTableCaption(headingKey))
|
||||
.setAlwaysShowDefaultTab(true)
|
||||
.setRenderTabs(false);
|
||||
for (String release : releases) {
|
||||
Content tab = TERMINALLY_DEPRECATED_KEY.equals(headingKey)
|
||||
|
@ -79,21 +79,17 @@ public class NewAPIListWriter extends SummaryListWriter<NewAPIBuilder> {
|
||||
|
||||
@Override
|
||||
protected void addContentSelectors(Content content) {
|
||||
List<String> releases = configuration.newAPIPageBuilder.releases;
|
||||
List<String> releases = builder.releases;
|
||||
if (releases.size() > 1) {
|
||||
Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes,
|
||||
contents.getContent("doclet.New_API_Checkbox_Label"));
|
||||
for (int i = 0; i < releases.size(); i++) {
|
||||
int releaseIndex = i + 1;
|
||||
String release = releases.get(i);
|
||||
HtmlId htmlId = HtmlId.of("release-" + releaseIndex);
|
||||
tabs.add(Text.of(" ")).add(HtmlTree.LABEL(htmlId.name(),
|
||||
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
|
||||
.put(HtmlAttr.CHECKED, "")
|
||||
.put(HtmlAttr.ONCLICK,
|
||||
"toggleGlobal(this, '" + releaseIndex + "', 3)"))
|
||||
.add(HtmlTree.SPAN(Text.of(release))));
|
||||
// Table column ids are 1-based
|
||||
int index = 1;
|
||||
for (String release : releases) {
|
||||
tabs.add(Text.of(" ")).add(getCheckbox(Text.of(release), String.valueOf(index++), "release-"));
|
||||
}
|
||||
Content label = contents.getContent("doclet.New_API_Checkbox_All_Releases");
|
||||
tabs.add(Text.of(" ")).add(getCheckbox(label, ID_ALL, "release-"));
|
||||
content.add(tabs);
|
||||
}
|
||||
}
|
||||
@ -104,7 +100,6 @@ public class NewAPIListWriter extends SummaryListWriter<NewAPIBuilder> {
|
||||
List<String> releases = builder.releases;
|
||||
if (releases.size() > 1) {
|
||||
table.setDefaultTab(getTableCaption(headingKey))
|
||||
.setAlwaysShowDefaultTab(true)
|
||||
.setRenderTabs(false);
|
||||
for (String release : releases) {
|
||||
table.addTab(
|
||||
|
@ -33,8 +33,7 @@ import javax.lang.model.element.Element;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
||||
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.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||
@ -80,21 +79,17 @@ public class PreviewListWriter extends SummaryListWriter<PreviewAPIListBuilder>
|
||||
protected void addContentSelectors(Content target) {
|
||||
Set<PreviewAPIListBuilder.JEP> jeps = builder.getJEPs();
|
||||
if (!jeps.isEmpty()) {
|
||||
int index = 0;
|
||||
int index = 1;
|
||||
target.add(HtmlTree.P(contents.getContent("doclet.Preview_API_Checkbox_Label")));
|
||||
Content list = HtmlTree.UL(HtmlStyle.previewFeatureList);
|
||||
Content list = HtmlTree.UL(HtmlStyle.previewFeatureList).addStyle(HtmlStyle.checkboxes);
|
||||
for (var jep : jeps) {
|
||||
index++;
|
||||
HtmlId htmlId = HtmlId.of("feature-" + index);
|
||||
String jepUrl = resources.getText("doclet.Preview_JEP_URL", jep.number());
|
||||
list.add(HtmlTree.LI(HtmlTree.LABEL(htmlId.name(),
|
||||
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId)
|
||||
.put(HtmlAttr.CHECKED, "")
|
||||
.put(HtmlAttr.ONCLICK,
|
||||
"toggleGlobal(this, '" + index + "', 3)"))
|
||||
.add(HtmlTree.SPAN(Text.of(jep.number() + ": "))
|
||||
.add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")"))))));
|
||||
Content label = new ContentBuilder(Text.of(jep.number() + ": "))
|
||||
.add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")")));
|
||||
list.add(HtmlTree.LI(getCheckbox(label, String.valueOf(index++), "feature-")));
|
||||
}
|
||||
Content label = contents.getContent("doclet.Preview_API_Checkbox_Toggle_All");
|
||||
list.add(HtmlTree.LI(getCheckbox(label, ID_ALL, "feature-")));
|
||||
target.add(list);
|
||||
}
|
||||
}
|
||||
@ -113,7 +108,6 @@ public class PreviewListWriter extends SummaryListWriter<PreviewAPIListBuilder>
|
||||
protected void addTableTabs(Table<Element> table, String headingKey) {
|
||||
table.setGridStyle(HtmlStyle.threeColumnSummary)
|
||||
.setDefaultTab(getTableCaption(headingKey))
|
||||
.setAlwaysShowDefaultTab(true)
|
||||
.setRenderTabs(false);
|
||||
for (PreviewAPIListBuilder.JEP jep : builder.getJEPs()) {
|
||||
table.addTab(Text.EMPTY, element -> jep == builder.getJEP(element));
|
||||
@ -122,7 +116,7 @@ public class PreviewListWriter extends SummaryListWriter<PreviewAPIListBuilder>
|
||||
|
||||
@Override
|
||||
protected Content getExtraContent(Element element) {
|
||||
PreviewAPIListBuilder.JEP jep = configuration.previewAPIListBuilder.getJEP(element);
|
||||
PreviewAPIListBuilder.JEP jep = builder.getJEP(element);
|
||||
return jep == null ? Text.EMPTY : Text.of(jep.title());
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
|
||||
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.Script;
|
||||
@ -54,6 +55,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder.SummaryEl
|
||||
*/
|
||||
public abstract class SummaryListWriter<B extends SummaryAPIListBuilder> extends SubWriterHolderWriter {
|
||||
|
||||
final protected String ID_OTHER = "other";
|
||||
final protected String ID_ALL = "all";
|
||||
|
||||
protected String getHeadingKey(SummaryElementKind kind) {
|
||||
return switch (kind) {
|
||||
case MODULE -> "doclet.Modules";
|
||||
@ -294,6 +298,25 @@ public abstract class SummaryListWriter<B extends SummaryAPIListBuilder> extends
|
||||
return writer.getSummaryLink(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a checkbox input element and associated label for selecting content on
|
||||
* a summary page.
|
||||
*
|
||||
* @param label The label
|
||||
* @param id the id of the selected content
|
||||
* @param htmlPrefix the prefix for the HTML id
|
||||
* @return a content object containing the checkbox input
|
||||
*/
|
||||
protected Content getCheckbox(Content label, String id, String htmlPrefix) {
|
||||
String htmlId = htmlPrefix + id;
|
||||
return HtmlTree.LABEL(htmlId,
|
||||
HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of(htmlId))
|
||||
.put(HtmlAttr.CHECKED, "")
|
||||
.put(HtmlAttr.ONCLICK,
|
||||
"toggleGlobal(this, '" + id + "', 3)"))
|
||||
.add(HtmlTree.SPAN(label));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an extra optional section to the content.
|
||||
*
|
||||
|
@ -84,7 +84,6 @@ public class Table<T> extends Content {
|
||||
private HtmlStyle gridStyle;
|
||||
private final List<Content> bodyRows;
|
||||
private HtmlId id;
|
||||
private boolean alwaysShowDefaultTab = false;
|
||||
|
||||
/**
|
||||
* A record containing the data for a table tab.
|
||||
@ -147,16 +146,6 @@ public class Table<T> extends Content {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to display the default tab even if tabs are empty or only contain a single tab.
|
||||
* @param showDefaultTab true if default tab should always be shown
|
||||
* @return this object
|
||||
*/
|
||||
public Table<T> setAlwaysShowDefaultTab(boolean showDefaultTab) {
|
||||
this.alwaysShowDefaultTab = showDefaultTab;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set whether tabs should be rendered for this table. Some pages use their
|
||||
* own controls to select table categories, in which case the tabs are omitted.
|
||||
@ -385,7 +374,7 @@ public class Table<T> extends Content {
|
||||
}
|
||||
|
||||
var table = HtmlTree.DIV(tableStyle).addStyle(gridStyle);
|
||||
if ((tabs == null || occurringTabs.size() == 1) && !alwaysShowDefaultTab) {
|
||||
if ((tabs == null || occurringTabs.size() == 1) && renderTabs) {
|
||||
if (tabs == null) {
|
||||
main.add(caption);
|
||||
} else {
|
||||
@ -401,15 +390,13 @@ public class Table<T> extends Content {
|
||||
HtmlId defaultTabId = HtmlIds.forTab(id, 0);
|
||||
if (renderTabs) {
|
||||
tablist.add(createTab(defaultTabId, HtmlStyle.activeTableTab, true, defaultTab));
|
||||
} else {
|
||||
tablist.add(getCaption(defaultTab));
|
||||
}
|
||||
if (renderTabs) {
|
||||
for (var tab : tabs) {
|
||||
if (occurringTabs.contains(tab)) {
|
||||
tablist.add(createTab(HtmlIds.forTab(id, tab.index()), HtmlStyle.tableTab, false, tab.label()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tablist.add(getCaption(defaultTab));
|
||||
}
|
||||
if (id == null) {
|
||||
throw new IllegalStateException("no id set for table");
|
||||
|
@ -97,20 +97,23 @@ function sortTable(header, columnIndex, columns) {
|
||||
|
||||
// Toggles the visibility of a table category in all tables in a page
|
||||
function toggleGlobal(checkbox, selected, columns) {
|
||||
var display = checkbox.checked ? '' : 'none';
|
||||
document.querySelectorAll("div.table-tabs").forEach(function(t) {
|
||||
var id = t.parentElement.getAttribute("id");
|
||||
var selectedClass = id + "-tab" + selected;
|
||||
// if selected is empty string it selects all uncategorized entries
|
||||
var selectUncategorized = !Boolean(selected);
|
||||
const display = checkbox.checked ? '' : 'none';
|
||||
const selectOther = selected === "other";
|
||||
const selectAll = selected === "all";
|
||||
if (selectAll) {
|
||||
document.querySelectorAll('.checkboxes input[type="checkbox"]').forEach(c => {
|
||||
c.checked = checkbox.checked;
|
||||
});
|
||||
}
|
||||
document.querySelectorAll("div.table-tabs").forEach(t => {
|
||||
const id = t.parentElement.getAttribute("id");
|
||||
const selectedClass = id + "-tab" + (selectOther ? "" : selected);
|
||||
var visible = 0;
|
||||
document.querySelectorAll('div.' + id)
|
||||
t.parentElement.querySelectorAll('div.' + id)
|
||||
.forEach(function(elem) {
|
||||
if (selectUncategorized) {
|
||||
if (elem.className.indexOf(selectedClass) === -1) {
|
||||
elem.style.display = display;
|
||||
}
|
||||
} else if (elem.classList.contains(selectedClass)) {
|
||||
if (selectAll
|
||||
|| (!selectOther && elem.classList.contains(selectedClass))
|
||||
|| (selectOther && elem.className.indexOf(selectedClass) < 0)) {
|
||||
elem.style.display = display;
|
||||
}
|
||||
if (elem.style.display === '') {
|
||||
|
@ -116,17 +116,20 @@ doclet.tag.invalid_input=invalid input: ''{0}''
|
||||
doclet.tag.invalid=invalid @{0}
|
||||
doclet.Deprecated_API=Deprecated API
|
||||
doclet.Deprecated_API_Checkbox_Label=Show API deprecated in:
|
||||
doclet.Deprecated_API_Checkbox_All_Releases=all
|
||||
doclet.Deprecated_API_Checkbox_Other_Releases=other
|
||||
doclet.Deprecated_Elements=Deprecated {0}
|
||||
doclet.Deprecated_Elements_Release_Column_Header=Deprecated in
|
||||
doclet.Deprecated_In_Release=Deprecated in {0}
|
||||
doclet.New_API=New API
|
||||
doclet.New_API_Checkbox_Label=Show API added in:
|
||||
doclet.New_API_Checkbox_All_Releases=all
|
||||
doclet.New_Elements=New {0}
|
||||
doclet.New_Elements_Release_Column_Header=Added in
|
||||
doclet.New_Label=New
|
||||
doclet.Preview_API=Preview API
|
||||
doclet.Preview_API_Checkbox_Label=Show preview API for:
|
||||
doclet.Preview_API_Checkbox_Toggle_All=Toggle all
|
||||
doclet.Preview_JEP_URL=https://openjdk.org/jeps/{0}
|
||||
doclet.Preview_Label=Preview
|
||||
doclet.Preview_Mark=PREVIEW
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2024, 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,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8263468 8269401 8268422 8287524
|
||||
* @bug 8263468 8269401 8268422 8287524 8325874
|
||||
* @summary New page for "recent" new API
|
||||
* @library ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
@ -115,7 +115,9 @@ public class TestNewApiList extends JavadocTester {
|
||||
<input type="checkbox" id="release-5" disabled checked onclick="toggleGlobal(this, '5', 3)">
|
||||
<span>3.2</span></label> <label for="release-6">
|
||||
<input type="checkbox" id="release-6" disabled checked onclick="toggleGlobal(this, '6', 3)">
|
||||
<span>5</span></label></div>
|
||||
<span>5</span></label> <label for="release-all">
|
||||
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
|
||||
<span>all</span></label></div>
|
||||
<h2 title="Contents">Contents</h2>
|
||||
<ul class="contents-list">
|
||||
<li id="contents-module"><a href="#module">Modules</a></li>
|
||||
@ -604,9 +606,11 @@ public class TestNewApiList extends JavadocTester {
|
||||
</div>
|
||||
<div class="checkboxes">Show API deprecated in: <label for="release-1">
|
||||
<input type="checkbox" id="release-1" disabled checked onclick="toggleGlobal(this, '1', 3)">
|
||||
<span>5</span></label> <label for="release-2">
|
||||
<input type="checkbox" id="release-2" disabled checked onclick="toggleGlobal(this, '', 3)">
|
||||
<span>other</span></label></div>
|
||||
<span>5</span></label> <label for="release-other">
|
||||
<input type="checkbox" id="release-other" disabled checked onclick="toggleGlobal(this, 'other', 3)">
|
||||
<span>other</span></label> <label for="release-all">
|
||||
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
|
||||
<span>all</span></label></div>
|
||||
<h2 title="Contents">Contents</h2>
|
||||
<ul class="contents-list">
|
||||
<li id="contents-for-removal"><a href="#for-removal">Terminally Deprecated</a></li>
|
||||
@ -677,7 +681,9 @@ public class TestNewApiList extends JavadocTester {
|
||||
<input type="checkbox" id="release-4" disabled checked onclick="toggleGlobal(this, '4', 3)">
|
||||
<span>5</span></label> <label for="release-5">
|
||||
<input type="checkbox" id="release-5" disabled checked onclick="toggleGlobal(this, '5', 3)">
|
||||
<span>6</span></label></div>
|
||||
<span>6</span></label> <label for="release-all">
|
||||
<input type="checkbox" id="release-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
|
||||
<span>all</span></label></div>
|
||||
<h2 title="Contents">Contents</h2>
|
||||
<ul class="contents-list">
|
||||
<li id="contents-class"><a href="#class">Classes</a></li>
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8250768 8261976 8277300 8282452 8287597 8325325
|
||||
* @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874
|
||||
* @summary test generated docs for items declared using preview
|
||||
* @library ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
@ -78,10 +78,13 @@ public class TestPreview extends JavadocTester {
|
||||
|
||||
checkOutput("preview-list.html", true,
|
||||
"""
|
||||
<ul class="preview-feature-list">
|
||||
<ul class="preview-feature-list checkboxes">
|
||||
<li><label for="feature-1">
|
||||
<input type="checkbox" id="feature-1" disabled checked onclick="toggleGlobal(this, '1', 3)">
|
||||
<span>0: <a href="https://openjdk.org/jeps/0">Test Feature (Preview)</a></span></label></li>
|
||||
<li><label for="feature-all">
|
||||
<input type="checkbox" id="feature-all" disabled checked onclick="toggleGlobal(this, 'all', 3)">
|
||||
<span>Toggle all</span></label></li>
|
||||
</ul>
|
||||
<h2 title="Contents">Contents</h2>
|
||||
<ul class="contents-list">
|
||||
|
Loading…
Reference in New Issue
Block a user