8259283: use new HtmlId and HtmlIds classes

Reviewed-by: hannesw
This commit is contained in:
Jonathan Gibbons 2021-01-13 17:01:39 +00:00
parent 5df2a949e3
commit 916ab4e7d8
39 changed files with 730 additions and 470 deletions

@ -282,61 +282,4 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
}
return null;
}
/**
* For backward compatibility, include an anchor using the erasures of the
* parameters. NOTE: We won't need this method anymore after we fix
* see tags so that they use the type instead of the erasure.
*
* @param executableElement the ExecutableElement to anchor to.
* @return the 1.4.x style anchor for the executable element.
*/
protected String getErasureAnchor(ExecutableElement executableElement) {
final StringBuilder buf = new StringBuilder(executableElement.getSimpleName());
buf.append("(");
List<? extends VariableElement> parameters = executableElement.getParameters();
boolean foundTypeVariable = false;
for (int i = 0; i < parameters.size(); i++) {
if (i > 0) {
buf.append(",");
}
TypeMirror t = parameters.get(i).asType();
SimpleTypeVisitor9<Boolean, Void> stv = new SimpleTypeVisitor9<>() {
boolean foundTypeVariable = false;
@Override
public Boolean visitArray(ArrayType t, Void p) {
visit(t.getComponentType());
buf.append(utils.getDimension(t));
return foundTypeVariable;
}
@Override
public Boolean visitTypeVariable(TypeVariable t, Void p) {
buf.append(utils.asTypeElement(t).getQualifiedName());
foundTypeVariable = true;
return foundTypeVariable;
}
@Override
public Boolean visitDeclared(DeclaredType t, Void p) {
buf.append(utils.getQualifiedTypeName(t));
return foundTypeVariable;
}
@Override
protected Boolean defaultAction(TypeMirror e, Void p) {
buf.append(e);
return foundTypeVariable;
}
};
boolean isTypeVariable = stv.visit(t);
if (!foundTypeVariable) {
foundTypeVariable = isTypeVariable;
}
}
buf.append(")");
return foundTypeVariable ? writer.links.getName(buf.toString()) : null;
}
}

@ -68,6 +68,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
protected final Contents contents;
protected final Resources resources;
protected final Links links;
protected final HtmlIds htmlIds;
protected final TypeElement typeElement;
@ -80,6 +81,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
this.contents = configuration.getContents();
this.resources = configuration.docResources;
this.links = writer.links;
this.htmlIds = configuration.htmlIds;
}
public AbstractMemberWriter(SubWriterHolderWriter writer) {

@ -117,7 +117,7 @@ public class AllClassesIndexWriter extends HtmlDocletWriter {
Table table = new Table(HtmlStyle.summaryTable)
.setHeader(new TableHeader(contents.classLabel, contents.descriptionLabel))
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast)
.setId("all-classes-table")
.setId(HtmlIds.ALL_CLASSES_TABLE)
.setDefaultTab(resources.getText("doclet.All_Classes"))
.addTab(contents.interfaceSummary, utils::isInterface)
.addTab(contents.classSummary, e -> utils.isOrdinaryClass((TypeElement)e))

@ -77,7 +77,7 @@ public class AnnotationTypeOptionalMemberWriterImpl extends
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.memberSummary,
SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY, summariesList, content);
HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY, summariesList, content);
}
@Override

@ -84,7 +84,7 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.memberSummary,
SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY, summariesList, content);
HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY, summariesList, content);
}
@Override
@ -114,7 +114,7 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
new StringContent(simpleName));
annotationDocTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, annotationDocTree)
.setId(simpleName + utils.signature((ExecutableElement) member, typeElement));
.setId(htmlIds.forMember(typeElement, (ExecutableElement) member));
}
@Override

@ -303,7 +303,8 @@ public class ClassUseWriter extends SubWriterHolderWriter {
HtmlTree ul = new HtmlTree(TagName.UL);
ul.setStyle(HtmlStyle.blockList);
for (PackageElement pkg : pkgSet) {
HtmlTree htmlTree = HtmlTree.SECTION(HtmlStyle.detail).setId(getPackageAnchorName(pkg));
HtmlTree htmlTree = HtmlTree.SECTION(HtmlStyle.detail)
.setId(htmlIds.forPackage(pkg));
Content link = contents.getContent("doclet.ClassUse_Uses.of.0.in.1",
getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER,
typeElement)),
@ -325,7 +326,7 @@ public class ClassUseWriter extends SubWriterHolderWriter {
*/
protected void addPackageUse(PackageElement pkg, Table table) {
Content pkgLink =
links.createLink(getPackageAnchorName(pkg), new StringContent(utils.getPackageName(pkg)));
links.createLink(htmlIds.forPackage(pkg), new StringContent(utils.getPackageName(pkg)));
Content summary = new ContentBuilder();
addSummaryComment(pkg, summary);
table.addRow(pkgLink, summary);

@ -30,20 +30,17 @@ import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor8;
import com.sun.source.doctree.DeprecatedTree;
import com.sun.source.doctree.DocTree;
import javax.lang.model.element.ElementKind;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
@ -59,7 +56,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
/**
* Generate the Class Information Page.
@ -200,7 +196,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
}
if (previewModifiers.contains(modifiersPart)) {
mods.add(modifiersPart);
mods.add(HtmlTree.SUP(links.createLink(getPreviewSectionAnchor(typeElement),
mods.add(HtmlTree.SUP(links.createLink(htmlIds.forPreviewSection(typeElement),
contents.previewMark)));
} else {
mods.add(modifiersPart);
@ -498,7 +494,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
HtmlTree section = HtmlTree.SECTION(HtmlStyle.details, contentTree);
// The following id is required by the Navigation bar
if (utils.isAnnotationType(typeElement)) {
section.setId(SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL.getName());
section.setId(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL);
}
return section;
}

@ -36,6 +36,7 @@ import javax.lang.model.element.VariableElement;
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
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.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@ -108,7 +109,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons
//add link to summary
Content link;
if (pkg.isUnnamed()) {
link = links.createLink(SectionName.UNNAMED_PACKAGE_ANCHOR,
link = links.createLink(HtmlIds.UNNAMED_PACKAGE_ANCHOR,
contents.defaultPackageLabel, "", "");
} else {
String parsedPackageName = utils.parsePackageName(pkg);
@ -145,16 +146,16 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons
@Override
public void addPackageName(PackageElement pkg, Content summariesTree, boolean first) {
Content pkgNameContent;
String anchorName;
HtmlId anchorName;
if (!first) {
summariesTree.add(summaryTree);
}
if (pkg.isUnnamed()) {
anchorName = SectionName.UNNAMED_PACKAGE_ANCHOR.getName();
anchorName = HtmlIds.UNNAMED_PACKAGE_ANCHOR;
pkgNameContent = contents.defaultPackageLabel;
} else {
String parsedPackageName = utils.parsePackageName(pkg);
anchorName = parsedPackageName;
anchorName = htmlIds.forPackage(pkg);
pkgNameContent = getPackageLabel(parsedPackageName);
}
Content headingContent = new StringContent(".*");
@ -162,7 +163,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons
pkgNameContent);
heading.add(headingContent);
summaryTree = HtmlTree.SECTION(HtmlStyle.constantsSummary, heading)
.setId(links.getName(anchorName));
.setId(anchorName);
}
@Override
@ -216,8 +217,8 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons
*/
private Content getTypeColumn(VariableElement member) {
Content typeContent = new ContentBuilder();
String id = currentTypeElement.getQualifiedName() + "." + member.getSimpleName();
Content code = new HtmlTree(TagName.CODE).setId(id);
Content code = new HtmlTree(TagName.CODE)
.setId(htmlIds.forMember(currentTypeElement, member));
for (Modifier mod : member.getModifiers()) {
Content modifier = new StringContent(mod.toString());
code.add(modifier);

@ -34,6 +34,7 @@ import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
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.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@ -101,7 +102,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.constructorSummary,
SectionName.CONSTRUCTOR_SUMMARY, summariesList, content);
HtmlIds.CONSTRUCTOR_SUMMARY, summariesList, content);
}
@Override
@ -116,16 +117,16 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter
@Override
public Content getConstructorDocTreeHeader(ExecutableElement constructor) {
String erasureAnchor;
Content constructorDocTree = new ContentBuilder();
HtmlTree heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING,
new StringContent(name(constructor)));
if ((erasureAnchor = getErasureAnchor(constructor)) != null) {
HtmlId erasureAnchor = htmlIds.forErasure(constructor);
if (erasureAnchor != null) {
heading.setId(erasureAnchor);
}
constructorDocTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, constructorDocTree)
.setId(links.getAnchor(constructor));
.setId(htmlIds.forMember(constructor));
}
@Override
@ -161,7 +162,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter
public Content getConstructorDetails(Content constructorDetailsTreeHeader, Content constructorDetailsTree) {
return writer.getDetailsListItem(
HtmlTree.SECTION(HtmlStyle.constructorDetails)
.setId(SectionName.CONSTRUCTOR_DETAIL.getName())
.setId(HtmlIds.CONSTRUCTOR_DETAIL)
.add(constructorDetailsTreeHeader)
.add(constructorDetailsTree));
}

@ -80,14 +80,14 @@ public class DeprecatedListWriter extends SummaryListWriter<DeprecatedAPIListBui
@Override
protected void addExtraSection(DeprecatedAPIListBuilder list, Content content) {
addSummaryAPI(list.getForRemoval(), "forRemoval",
addSummaryAPI(list.getForRemoval(), HtmlIds.FOR_REMOVAL,
"doclet.For_Removal", "doclet.Element", content);
}
@Override
protected void addExtraIndexLink(DeprecatedAPIListBuilder list, Content target) {
if (!list.getForRemoval().isEmpty()) {
addIndexLink("forRemoval", "doclet.For_Removal", target);
addIndexLink(HtmlIds.FOR_REMOVAL, "doclet.For_Removal", target);
}
}

@ -71,7 +71,7 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.constantsSummary,
SectionName.ENUM_CONSTANT_SUMMARY, summariesList, content);
HtmlIds.ENUM_CONSTANT_SUMMARY, summariesList, content);
}
@Override
@ -93,7 +93,7 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter
new StringContent(name(enumConstant)));
enumConstantsTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, enumConstantsTree)
.setId(name(enumConstant));
.setId(htmlIds.forMember(enumConstant));
}
@Override
@ -129,7 +129,7 @@ public class EnumConstantWriterImpl extends AbstractMemberWriter
Content enumConstantsDetailsTree) {
return writer.getDetailsListItem(
HtmlTree.SECTION(HtmlStyle.constantDetails)
.setId(SectionName.ENUM_CONSTANT_DETAIL.getName())
.setId(HtmlIds.ENUM_CONSTANT_DETAIL)
.add(enumConstantsDetailsTreeHeader)
.add(enumConstantsDetailsTree));
}

@ -74,7 +74,7 @@ public class FieldWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.fieldSummary,
SectionName.FIELD_SUMMARY, summariesList, content);
HtmlIds.FIELD_SUMMARY, summariesList, content);
}
@Override
@ -93,7 +93,8 @@ public class FieldWriterImpl extends AbstractMemberWriter
Content heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING,
new StringContent(name(field)));
fieldTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, fieldTree).setId(name(field));
return HtmlTree.SECTION(HtmlStyle.detail, fieldTree)
.setId(htmlIds.forMember(field));
}
@Override
@ -130,7 +131,7 @@ public class FieldWriterImpl extends AbstractMemberWriter
public Content getFieldDetails(Content fieldDetailsTreeHeader, Content fieldDetailsTree) {
return writer.getDetailsListItem(
HtmlTree.SECTION(HtmlStyle.fieldDetails)
.setId(SectionName.FIELD_DETAIL.getName())
.setId(HtmlIds.FIELD_DETAIL)
.add(fieldDetailsTreeHeader)
.add(fieldDetailsTree));
}
@ -175,8 +176,7 @@ public class FieldWriterImpl extends AbstractMemberWriter
}
HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING,
label);
labelHeading.setId(SectionName.FIELDS_INHERITANCE.getName()
+ links.getName(configuration.getClassName(typeElement)));
labelHeading.setId(htmlIds.forInheritedFields(typeElement));
labelHeading.add(Entity.NO_BREAK_SPACE);
labelHeading.add(classLink);
inheritedTree.add(labelHeading);

@ -134,6 +134,8 @@ public class HtmlConfiguration extends BaseConfiguration {
public DocPaths docPaths;
public HtmlIds htmlIds;
public Map<Element, List<DocPath>> localStylesheetMap = new HashMap<>();
private final HtmlOptions options;
@ -208,6 +210,7 @@ public class HtmlConfiguration extends BaseConfiguration {
Function<String, String> resourceKeyMapper) {
super.initConfiguration(docEnv, resourceKeyMapper);
contents = new Contents(this);
htmlIds = new HtmlIds(this);
}
private final Runtime.Version docletVersion;

@ -77,6 +77,7 @@ import com.sun.source.doctree.SystemPropertyTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.SimpleDocTreeVisitor;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
import jdk.javadoc.internal.doclint.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
@ -177,6 +178,8 @@ public class HtmlDocletWriter {
protected final Comparators comparators;
protected final HtmlIds htmlIds;
/**
* To check whether annotation heading is printed or not.
*/
@ -224,9 +227,10 @@ public class HtmlDocletWriter {
this.contents = configuration.getContents();
this.messages = configuration.messages;
this.resources = configuration.docResources;
this.links = new Links(path, configuration.utils);
this.links = new Links(path);
this.utils = configuration.utils;
this.comparators = utils.comparators;
this.htmlIds = configuration.htmlIds;
this.path = path;
this.pathToRoot = path.parent().invert();
this.filename = path.basename();
@ -606,17 +610,6 @@ public class HtmlDocletWriter {
return pathToRoot.resolve(docPaths.forPackage(packageElement).resolve(name));
}
/**
* Given a package, return the name to be used in HTML anchor tag.
* @param packageElement the package.
* @return the name to be used in HTML anchor tag.
*/
public String getPackageAnchorName(PackageElement packageElement) {
return packageElement == null || packageElement.isUnnamed()
? SectionName.UNNAMED_PACKAGE_ANCHOR.getName()
: utils.getPackageName(packageElement);
}
/**
* Return the link to the given package.
*
@ -668,7 +661,7 @@ public class HtmlDocletWriter {
if (flags.contains(ElementFlag.PREVIEW)) {
return new ContentBuilder(
links.createLink(targetLink, label),
HtmlTree.SUP(links.createLink(targetLink.withFragment(getPreviewSectionAnchor(packageElement)),
HtmlTree.SUP(links.createLink(targetLink.withFragment(htmlIds.forPreviewSection(packageElement).name()),
contents.previewMark))
);
}
@ -701,7 +694,7 @@ public class HtmlDocletWriter {
if (flags.contains(ElementFlag.PREVIEW) && label != contents.moduleLabel) {
link = new ContentBuilder(
link,
HtmlTree.SUP(links.createLink(targetLink.withFragment(getPreviewSectionAnchor(mdle)),
HtmlTree.SUP(links.createLink(targetLink.withFragment(htmlIds.forPreviewSection(mdle).name()),
contents.previewMark))
);
}
@ -1007,9 +1000,10 @@ public class HtmlDocletWriter {
if (utils.isExecutableElement(element)) {
ExecutableElement ee = (ExecutableElement)element;
HtmlId id = isProperty ? htmlIds.forProperty(ee) : htmlIds.forMember(ee);
return getLink(new LinkInfoImpl(configuration, context, typeElement)
.label(label)
.where(links.getAnchor(ee, isProperty))
.where(id.name())
.targetMember(element)
.strong(strong));
}
@ -1017,7 +1011,7 @@ public class HtmlDocletWriter {
if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
return getLink(new LinkInfoImpl(configuration, context, typeElement)
.label(label)
.where(links.getName(element.getSimpleName().toString()))
.where(element.getSimpleName().toString())
.targetMember(element)
.strong(strong));
}
@ -1038,17 +1032,19 @@ public class HtmlDocletWriter {
*/
public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element,
Content label) {
if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) {
if (!(utils.isIncluded(element) || utils.isLinkable(typeElement))) {
return label;
} else if (utils.isExecutableElement(element)) {
ExecutableElement emd = (ExecutableElement) element;
return getLink(new LinkInfoImpl(configuration, context, typeElement)
.label(label)
.where(links.getAnchor(emd))
.targetMember(element));
.label(label)
.where(htmlIds.forMember(emd).name())
.targetMember(element));
} else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
return getLink(new LinkInfoImpl(configuration, context, typeElement)
.label(label).where(links.getName(element.getSimpleName().toString())).targetMember(element));
.label(label)
.where(element.getSimpleName().toString())
.targetMember(element));
} else {
return label;
}
@ -1102,8 +1098,8 @@ public class HtmlDocletWriter {
: null;
if (elementCrossLink != null) {
// Element cross link found
return links.createLink(elementCrossLink,
(label.isEmpty() ? text : label), true);
return links.createExternalLink(elementCrossLink,
(label.isEmpty() ? text : label));
} else {
// No cross link found so print warning
messages.warning(ch.getDocTreePath(see),
@ -2187,7 +2183,7 @@ public class HtmlDocletWriter {
if (utils.isPreviewAPI(forWhat)) {
//in Java platform:
HtmlTree previewDiv = HtmlTree.DIV(HtmlStyle.previewBlock);
previewDiv.setId(getPreviewSectionAnchor(forWhat));
previewDiv.setId(htmlIds.forPreviewSection(forWhat));
String name = (switch (forWhat.getKind()) {
case PACKAGE, MODULE ->
((QualifiedNameable) forWhat).getQualifiedName();
@ -2218,7 +2214,7 @@ public class HtmlDocletWriter {
Name name = forWhat.getSimpleName();
Content nameCode = HtmlTree.CODE(new StringContent(name));
HtmlTree previewDiv = HtmlTree.DIV(HtmlStyle.previewBlock);
previewDiv.setId(getPreviewSectionAnchor(forWhat));
previewDiv.setId(htmlIds.forPreviewSection(forWhat));
Content leadingNote = contents.getContent("doclet.PreviewLeadingNote", nameCode);
previewDiv.add(HtmlTree.SPAN(HtmlStyle.previewLabel,
leadingNote));
@ -2320,13 +2316,4 @@ public class HtmlDocletWriter {
links);
}
public String getPreviewSectionAnchor(Element el) {
return "preview-" + switch (el.getKind()) {
case CONSTRUCTOR, METHOD ->
links.getAnchor((ExecutableElement) el);
case PACKAGE -> getPackageAnchorName((PackageElement) el);
default -> utils.getFullyQualifiedName(el, false);
};
}
}

@ -0,0 +1,452 @@
/*
* 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.
*/
package jdk.javadoc.internal.doclets.formats.html;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.SimpleTypeVisitor9;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
/**
* Centralized constants and factory methods for HTML ids.
*
* <p>To ensure consistency, these constants and methods should be used
* both when declaring ids (for example, {@code HtmlTree.setId})
* and creating references (for example, {@code Links.createLink}).
*
* <p>Most ids are mostly for internal use within the pages of a documentation
* bundle. However, the ids for member declarations may be referred to
* from other documentation using {@code {@link}}, and should not be
* changed without due consideration for the compatibility impact.
*
* <p>The use of punctuating characters is inconsistent and could be improved.
*
* <p>Constants and methods are {@code static} where possible.
* However, some methods require access to {@code utils} and are
* better provided as instance methods.
*/
public class HtmlIds {
private final HtmlConfiguration configuration;
private final Utils utils;
static final HtmlId ALL_CLASSES_TABLE = HtmlId.of("all-classes-table");
static final HtmlId ALL_MODULES_TABLE = HtmlId.of("all-modules-table");
static final HtmlId ALL_PACKAGES_TABLE = HtmlId.of("all-packages-table");
static final HtmlId ANNOTATION_TYPE_ELEMENT_DETAIL = HtmlId.of("annotation.interface.element.detail");
static final HtmlId ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY = HtmlId.of("annotation.interface.optional.element.summary");
static final HtmlId ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY = HtmlId.of("annotation.interface.required.element.summary");
static final HtmlId CONSTRUCTOR_DETAIL = HtmlId.of("constructor.detail");
static final HtmlId CONSTRUCTOR_SUMMARY = HtmlId.of("constructor.summary");
static final HtmlId ENUM_CONSTANT_DETAIL = HtmlId.of("enum.constant.detail");
static final HtmlId ENUM_CONSTANT_SUMMARY = HtmlId.of("enum.constant.summary");
static final HtmlId FIELD_DETAIL = HtmlId.of("field.detail");
static final HtmlId FIELD_SUMMARY = HtmlId.of("field.summary");
static final HtmlId FOR_REMOVAL = HtmlId.of("forRemoval");
static final HtmlId METHOD_DETAIL = HtmlId.of("method.detail");
static final HtmlId METHOD_SUMMARY = HtmlId.of("method.summary");
static final HtmlId METHOD_SUMMARY_TABLE = HtmlId.of("method-summary-table");
static final HtmlId MODULES = HtmlId.of("modules.summary");
static final HtmlId MODULE_DESCRIPTION = HtmlId.of("module.description");
static final HtmlId NAVBAR_TOP = HtmlId.of("navbar.top");
static final HtmlId NAVBAR_TOP_FIRSTROW = HtmlId.of("navbar.top.firstrow");
static final HtmlId NESTED_CLASS_SUMMARY = HtmlId.of("nested.class.summary");
static final HtmlId PACKAGES = HtmlId.of("packages.summary");
static final HtmlId PACKAGE_DESCRIPTION = HtmlId.of("package.description");
static final HtmlId PACKAGE_SUMMARY_TABLE = HtmlId.of("package-summary-table");
static final HtmlId PROPERTY_DETAIL = HtmlId.of("property.detail");
static final HtmlId PROPERTY_SUMMARY = HtmlId.of("property.summary");
static final HtmlId SERVICES = HtmlId.of("services.summary");
static final HtmlId SKIP_NAVBAR_TOP = HtmlId.of("skip.navbar.top");
static final HtmlId UNNAMED_PACKAGE_ANCHOR = HtmlId.of("unnamed.package");
private static final String ENUM_CONSTANTS_INHERITANCE = "enum.constants.inherited.from.class.";
private static final String FIELDS_INHERITANCE = "fields.inherited.from.class.";
private static final String METHODS_INHERITANCE = "methods.inherited.from.class.";
private static final String NESTED_CLASSES_INHERITANCE = "nested.classes.inherited.from.class.";
private static final String PROPERTIES_INHERITANCE = "properties.inherited.from.class.";
/**
* Creates a factory for element-specific ids.
*
* @param configuration the configuration
*/
HtmlIds(HtmlConfiguration configuration) {
this.configuration = configuration;
this.utils = configuration.utils;
}
/**
* Returns an id for a package.
*
* @param element the package
*
* @return the id
*/
HtmlId forPackage(PackageElement element) {
return element == null || element.isUnnamed()
? UNNAMED_PACKAGE_ANCHOR
: HtmlId.of(element.getQualifiedName().toString());
}
/**
* Returns an id for a class or interface.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forClass(TypeElement element) {
return HtmlId.of(utils.getFullyQualifiedName(element));
}
/**
* Returns an id for an executable element, suitable for use when the
* simple name and argument list will be unique within the page, such as
* in the page for the declaration of the enclosing class or interface.
*
* @param element the element
*
* @return the id
*/
HtmlId forMember(ExecutableElement element) {
String a = element.getSimpleName()
+ utils.makeSignature(element, null, true, true);
// utils.makeSignature includes spaces
return HtmlId.of(a.replaceAll("\\s", ""));
}
/**
* Returns an id for an executable element, including the context
* of its documented enclosing class or interface.
*
* @param typeElement the enclosing class or interface
* @param member the element
*
* @return the id
*/
HtmlId forMember(TypeElement typeElement, ExecutableElement member) {
return HtmlId.of(utils.getSimpleName(member) + utils.signature(member, typeElement));
}
/**
* Returns an id for a field, suitable for use when the simple name
* will be unique within the page, such as in the page for the
* declaration of the enclosing class or interface.
*
* <p>Warning: the name may not be unique if a property with the same
* name is also being documented in the same class.
*
* @param element the element
*
* @return the id
*
* @see #forProperty(ExecutableElement)
*/
HtmlId forMember(VariableElement element) {
return HtmlId.of(element.getSimpleName().toString());
}
/**
* Returns an id for a field, including the context
* of its documented enclosing class or interface.
*
* @param typeElement the enclosing class or interface
* @param member the element
*
* @return the id
*/
HtmlId forMember(TypeElement typeElement, VariableElement member) {
return HtmlId.of(typeElement.getQualifiedName() + "." + member.getSimpleName());
}
/**
* Returns an id for the erasure of an executable element,
* or {@code null} if there are no type variables in the signature.
*
* For backward compatibility, include an anchor using the erasures of the
* parameters. NOTE: We won't need this method anymore after we fix
* {@code @see} tags so that they use the type instead of the erasure.
*
* @param executableElement the element to anchor to
* @return the 1.4.x style anchor for the executable element
*/
protected HtmlId forErasure(ExecutableElement executableElement) {
final StringBuilder buf = new StringBuilder(executableElement.getSimpleName());
buf.append("(");
List<? extends VariableElement> parameters = executableElement.getParameters();
boolean foundTypeVariable = false;
for (int i = 0; i < parameters.size(); i++) {
if (i > 0) {
buf.append(",");
}
TypeMirror t = parameters.get(i).asType();
SimpleTypeVisitor9<Boolean, Void> stv = new SimpleTypeVisitor9<>() {
boolean foundTypeVariable = false;
@Override
public Boolean visitArray(ArrayType t, Void p) {
visit(t.getComponentType());
buf.append(utils.getDimension(t));
return foundTypeVariable;
}
@Override
public Boolean visitTypeVariable(TypeVariable t, Void p) {
buf.append(utils.asTypeElement(t).getQualifiedName());
foundTypeVariable = true;
return foundTypeVariable;
}
@Override
public Boolean visitDeclared(DeclaredType t, Void p) {
buf.append(utils.getQualifiedTypeName(t));
return foundTypeVariable;
}
@Override
protected Boolean defaultAction(TypeMirror e, Void p) {
buf.append(e);
return foundTypeVariable;
}
};
boolean isTypeVariable = stv.visit(t);
if (!foundTypeVariable) {
foundTypeVariable = isTypeVariable;
}
}
buf.append(")");
return foundTypeVariable ? HtmlId.of(buf.toString()) : null;
}
/**
* Returns an id for a property, suitable for use when the simple name
* will be unique within the page, such as in the page for the
* declaration of the enclosing class or interface.
*
* <p>Warning: the name may not be unique if a field with the same
* name is also being documented in the same class.
*
* @param element the element
*
* @return the id
*
* @see #forMember(VariableElement)
*/
HtmlId forProperty(ExecutableElement element) {
return HtmlId.of(element.getSimpleName().toString());
}
/**
* Returns an id for the list of classes and interfaces inherited from
* a class or interface.
*
* <p>Note: the use of {@code utils} may not be strictly necessary.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forInheritedClasses(TypeElement element) {
return HtmlId.of(NESTED_CLASSES_INHERITANCE + utils.getFullyQualifiedName(element));
}
/**
* Returns an id for the list of fields inherited from a class or interface.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forInheritedFields(TypeElement element) {
return forInherited(FIELDS_INHERITANCE, element);
}
/**
* Returns an id for the list of enum constants inherited from a class or interface.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forInheritedEnumConstants(TypeElement element) {
return forInherited(ENUM_CONSTANTS_INHERITANCE, element);
}
/**
* Returns an id for the list of methods inherited from a class or interface.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forInheritedMethods(TypeElement element) {
return forInherited(METHODS_INHERITANCE, element);
}
/**
* Returns an id for the list of properties inherited from a class or interface.
*
* @param element the class or interface
*
* @return the id
*/
HtmlId forInheritedProperties(TypeElement element) {
return forInherited(PROPERTIES_INHERITANCE, element);
}
// Note: the use of {@code configuration} may not be strictly necessary as
// compared to just using the fully qualified name, but would be a change in the value.
private HtmlId forInherited(String prefix, TypeElement element) {
return HtmlId.of(prefix + configuration.getClassName(element));
}
/**
* Returns an id for a character on the A-Z Index page.
*
* @param character the character
*
* @return the id
*/
static HtmlId forIndexChar(char character) {
return HtmlId.of("I:" + character);
}
/**
* Returns an id for a line in a source-code listing.
*
* @param lineNumber the line number
*
* @return the id
*/
static HtmlId forLine(int lineNumber) {
return HtmlId.of("line." + lineNumber);
}
/**
* Returns an id for a parameter, such as a component of a record.
*
* <p>Warning: this may not be unique on the page if used when there are
* other like-named parameters.
*
* @param paramName the parameter name
*
* @return the id
*/
static HtmlId forParam(String paramName) {
return HtmlId.of("param-" + paramName);
}
/**
* Returns an id for a fragment of text, such as in an {@code @index} tag,
* using a map of counts to ensure the id is unique.
*
* @param text the text
* @param counts the map of counts
*
* @return the id
*/
static HtmlId forText(String text, Map<String, Integer> counts) {
String base = text.replaceAll("\\s+", "");
int count = counts.compute(base, (k, v) -> v == null ? 0 : v + 1);
return HtmlId.of(count == 0 ? base : base + "-" + count);
}
/**
* Returns an id for one of the kinds of section in the pages for item group summaries.
*
* <p>Note: while the use of simple names (that are not keywords)
* may seem undesirable, they cannot conflict with the unqualified names
* of fields and properties, which should not also appear on the same page.
*
* @param kind the kind of deprecated items in the section
*
* @return the id
*/
static HtmlId forSummaryKind(SummaryAPIListBuilder.SummaryElementKind kind) {
return HtmlId.of(switch (kind) {
case MODULE -> "module";
case PACKAGE -> "package";
case INTERFACE -> "interface";
case CLASS -> "class";
case ENUM -> "enum.class";
case EXCEPTION -> "exception";
case ERROR -> "error";
case ANNOTATION_TYPE -> "annotation.interface";
case FIELD -> "field";
case METHOD -> "method";
case CONSTRUCTOR -> "constructor";
case ENUM_CONSTANT -> "enum.constant";
case ANNOTATION_TYPE_MEMBER -> "annotation.interface.member";
case RECORD_CLASS -> "record.class";
});
}
/**
* Returns an id for a "tab" in a table.
*
* @param tableId the id for the table
* @param tabIndex the index of the tab
*
* @return the id
*/
public static HtmlId forTab(HtmlId tableId, int tabIndex) {
return HtmlId.of(tableId.name() + "-tab" + tabIndex);
}
/**
* Returns an id for the "tab panel" in a table.
*
* @param tableId the id for the table
*
* @return the id
*/
public static HtmlId forTabPanel(HtmlId tableId) {
return HtmlId.of(tableId.name() + ".tabpanel");
}
public HtmlId forPreviewSection(Element el) {
return HtmlId.of("preview-" + switch (el.getKind()) {
case CONSTRUCTOR, METHOD -> forMember((ExecutableElement) el).name();
case PACKAGE -> forPackage((PackageElement) el).name();
default -> utils.getFullyQualifiedName(el, false);
});
}
}

@ -59,9 +59,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
public class HtmlIndexBuilder extends IndexBuilder {
private final HtmlConfiguration configuration;
private final Links links;
private final Resources resources;
private final Utils utils;
private final HtmlIds htmlIds;
/**
* Creates a new {@code HtmlIndexBuilder}.
@ -71,9 +71,9 @@ public class HtmlIndexBuilder extends IndexBuilder {
HtmlIndexBuilder(HtmlConfiguration configuration) {
super(configuration, configuration.getOptions().noDeprecated());
this.configuration = configuration;
links = new Links(DocPath.empty, configuration.utils);
resources = configuration.docResources;
utils = configuration.utils;
htmlIds = configuration.htmlIds;
}
/**
@ -142,7 +142,7 @@ public class HtmlIndexBuilder extends IndexBuilder {
item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
}
if (utils.isExecutableElement(element)) {
String url = HtmlTree.encodeURL(links.getAnchor((ExecutableElement) element));
String url = HtmlTree.encodeURL(htmlIds.forMember((ExecutableElement) element).name());
if (!url.equals(item.getLabel())) {
item.setUrl(url);
}

@ -167,7 +167,7 @@ public class IndexWriter extends HtmlDocletWriter {
protected void addHeading(char ch, Content contentTree) {
Content headContent = new StringContent(String.valueOf(ch));
HtmlTree heading = HtmlTree.HEADING(Headings.CONTENT_HEADING, HtmlStyle.title, headContent)
.setId(getNameForIndex(ch));
.setId(HtmlIds.forIndexChar(ch));
contentTree.add(heading);
}
@ -355,7 +355,7 @@ public class IndexWriter extends HtmlDocletWriter {
Content label = new StringContent(Character.toString(ch));
Content link = splitIndex
? links.createLink(DocPaths.indexN(iter.nextIndex()), label)
: links.createLink(getNameForIndex(ch), label);
: links.createLink(HtmlIds.forIndexChar(ch), label);
contentTree.add(link);
contentTree.add(Entity.NO_BREAK_SPACE);
}
@ -370,15 +370,4 @@ public class IndexWriter extends HtmlDocletWriter {
.collect(Collectors.toList());
contentTree.add(contents.join(getVerticalSeparator(), pageLinks));
}
/**
* Returns the anchor name for a first character of names in the index.
*
* @param firstCharacter the character
* @return a name
*/
protected String getNameForIndex(char firstCharacter) {
return "I:" + links.getName(Character.toString(firstCharacter));
}
}

@ -119,7 +119,7 @@ public class LinkFactoryImpl extends LinkFactory {
classLinkInfo.target));
if (flags.contains(ElementFlag.PREVIEW)) {
link.add(HtmlTree.SUP(m_writer.links.createLink(
filename.fragment(m_writer.getPreviewSectionAnchor(target)),
filename.fragment(m_writer.htmlIds.forPreviewSection(target).name()),
m_writer.contents.previewMark)));
}
if (noLabel && !classLinkInfo.excludeTypeParameterLinks) {
@ -137,7 +137,7 @@ public class LinkFactoryImpl extends LinkFactory {
if (flags.contains(ElementFlag.PREVIEW)) {
link.add(HtmlTree.SUP(m_writer.getCrossClassLink(
typeElement,
m_writer.getPreviewSectionAnchor(target),
m_writer.htmlIds.forPreviewSection(target).name(),
m_writer.contents.previewMark,
false, false)));
}

@ -37,6 +37,7 @@ import javax.lang.model.type.TypeMirror;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
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.StringContent;
@ -89,7 +90,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.methodSummary,
SectionName.METHOD_SUMMARY, summariesList, content);
HtmlIds.METHOD_SUMMARY, summariesList, content);
}
@Override
@ -104,16 +105,16 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
@Override
public Content getMethodDocTreeHeader(ExecutableElement method) {
String erasureAnchor;
Content methodDocTree = new ContentBuilder();
HtmlTree heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING,
new StringContent(name(method)));
if ((erasureAnchor = getErasureAnchor(method)) != null) {
HtmlId erasureAnchor;
if ((erasureAnchor = htmlIds.forErasure(method)) != null) {
heading.setId(erasureAnchor);
}
methodDocTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, methodDocTree)
.setId(links.getAnchor(method));
.setId(htmlIds.forMember(method));
}
/**
@ -181,7 +182,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
public Content getMethodDetails(Content methodDetailsTreeHeader, Content methodDetailsTree) {
Content methodDetails = new ContentBuilder(methodDetailsTreeHeader, methodDetailsTree);
return getMemberTree(HtmlTree.SECTION(HtmlStyle.methodDetails, methodDetails)
.setId(SectionName.METHOD_DETAIL.getName()));
.setId(HtmlIds.METHOD_DETAIL));
}
@Override
@ -202,7 +203,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
return new Table(HtmlStyle.summaryTable)
.setHeader(getSummaryTableHeader(typeElement))
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast)
.setId("method-summary-table")
.setId(HtmlIds.METHOD_SUMMARY_TABLE)
.setDefaultTab(resources.getText("doclet.All_Methods"))
.addTab(resources.getText("doclet.Static_Methods"), utils::isStatic)
.addTab(resources.getText("doclet.Instance_Methods"), e -> !utils.isStatic(e))
@ -230,8 +231,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
}
HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING,
label);
labelHeading.setId(SectionName.METHODS_INHERITANCE.getName()
+ links.getName(configuration.getClassName(typeElement)));
labelHeading.setId(htmlIds.forInheritedMethods(typeElement));
labelHeading.add(Entity.NO_BREAK_SPACE);
labelHeading.add(classLink);
inheritedTree.add(labelHeading);
@ -290,7 +290,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink);
Content methlink = writer.getLink(
new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder)
.where(writer.links.getAnchor(method))
.where(writer.htmlIds.forMember(method).name())
.label(method.getSimpleName()));
Content codeMethLink = HtmlTree.CODE(methlink);
Content dd = HtmlTree.DD(codeMethLink);

@ -93,7 +93,7 @@ public class ModuleIndexWriter extends AbstractOverviewIndexWriter {
Table table = new Table(HtmlStyle.summaryTable)
.setHeader(tableHeader)
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast)
.setId("all-modules-table")
.setId(HtmlIds.ALL_MODULES_TABLE)
.setDefaultTab(resources.getText("doclet.All_Modules"));
// add the tabs in command-line order

@ -477,7 +477,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
new TableHeader(contents.modifierLabel, contents.moduleLabel,
contents.descriptionLabel);
HtmlTree section = HtmlTree.SECTION(HtmlStyle.modulesSummary)
.setId(SectionName.MODULES.getName());
.setId(HtmlIds.MODULES);
addSummaryHeader(MarkerComments.START_OF_MODULES_SUMMARY, contents.navModules, section);
if (display(requires)) {
String text = resources.getText("doclet.Requires_Summary");
@ -519,7 +519,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
if (display(packages)
|| display(indirectPackages) || display(indirectOpenPackages)) {
HtmlTree section = HtmlTree.SECTION(HtmlStyle.packagesSummary)
.setId(SectionName.PACKAGES.getName());;
.setId(HtmlIds.PACKAGES);
addSummaryHeader(MarkerComments.START_OF_PACKAGES_SUMMARY, contents.navPackages, section);
if (display(packages)) {
addPackageSummary(section);
@ -549,7 +549,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
*/
public void addPackageSummary(HtmlTree li) {
Table table = new Table(HtmlStyle.summaryTable)
.setId("package-summary-table")
.setId(HtmlIds.PACKAGE_SUMMARY_TABLE)
.setDefaultTab(resources.getText("doclet.All_Packages"))
.addTab(resources.getText("doclet.Exported_Packages_Summary"), this::isExported)
.addTab(resources.getText("doclet.Opened_Packages_Summary"), this::isOpened)
@ -692,7 +692,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
if (haveProvides || haveUses) {
HtmlTree section = HtmlTree.SECTION(HtmlStyle.servicesSummary)
.setId(SectionName.SERVICES.getName());
.setId(HtmlIds.SERVICES);
addSummaryHeader(MarkerComments.START_OF_SERVICES_SUMMARY, contents.navServices, section);
TableHeader usesProvidesTableHeader =
new TableHeader(contents.typeLabel, contents.descriptionLabel);
@ -814,8 +814,8 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
public void addModuleDescription(Content moduleContentTree) {
addPreviewInfo(mdle, moduleContentTree);
if (!utils.getFullBody(mdle).isEmpty()) {
HtmlTree tree = HtmlTree.SECTION(HtmlStyle.moduleDescription);
tree.setId(SectionName.MODULE_DESCRIPTION.getName());
HtmlTree tree = HtmlTree.SECTION(HtmlStyle.moduleDescription)
.setId(HtmlIds.MODULE_DESCRIPTION);
addDeprecationInfo(tree);
tree.add(MarkerComments.START_OF_MODULE_DESCRIPTION);
addInlineComment(mdle, tree);

@ -67,6 +67,7 @@ public class Navigation {
private final HtmlOptions options;
private final Element element;
private final Contents contents;
private final HtmlIds htmlIds;
private final DocPath path;
private final DocPath pathToRoot;
private final Links links;
@ -116,10 +117,11 @@ public class Navigation {
this.options = configuration.getOptions();
this.element = element;
this.contents = configuration.getContents();
this.htmlIds = configuration.htmlIds;
this.documentedPage = page;
this.path = path;
this.pathToRoot = path.parent().invert();
this.links = new Links(path, configuration.utils);
this.links = new Links(path);
this.rowListTitle = configuration.getDocResources().getText("doclet.Navigation");
this.searchLabel = contents.getContent("doclet.search");
}
@ -388,25 +390,25 @@ public class Navigation {
case MODULE:
if (displaySummaryModuleDescLink) {
addContentToList(listContents,
links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription));
links.createLink(HtmlIds.MODULE_DESCRIPTION, contents.navModuleDescription));
} else {
addContentToList(listContents, contents.navModuleDescription);
}
if (displaySummaryModulesLink) {
addContentToList(listContents,
links.createLink(SectionName.MODULES, contents.navModules));
links.createLink(HtmlIds.MODULES, contents.navModules));
} else {
addContentToList(listContents, contents.navModules);
}
if (displaySummaryPackagesLink) {
addContentToList(listContents,
links.createLink(SectionName.PACKAGES, contents.navPackages));
links.createLink(HtmlIds.PACKAGES, contents.navPackages));
} else {
addContentToList(listContents, contents.navPackages);
}
if (displaySummaryServicesLink) {
addContentToList(listContents,
links.createLink(SectionName.SERVICES, contents.navServices));
links.createLink(HtmlIds.SERVICES, contents.navServices));
} else {
addContentToList(listContents, contents.navServices);
}
@ -460,8 +462,8 @@ public class Navigation {
switch (kind) {
case CONSTRUCTORS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
contents.navConstructor));
addContentToList(listContents,
links.createLink(HtmlIds.CONSTRUCTOR_SUMMARY, contents.navConstructor));
} else {
addContentToList(listContents, contents.navConstructor);
}
@ -469,12 +471,11 @@ public class Navigation {
case ENUM_CONSTANTS:
if (link) {
if (typeElement == null) {
addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
contents.navEnum));
addContentToList(listContents,
links.createLink(HtmlIds.ENUM_CONSTANT_SUMMARY, contents.navEnum));
} else {
addContentToList(listContents, links.createLink(
SectionName.ENUM_CONSTANTS_INHERITANCE,
configuration.getClassName(typeElement), contents.navEnum));
addContentToList(listContents,
links.createLink( htmlIds.forInheritedEnumConstants(typeElement), contents.navEnum));
}
} else {
addContentToList(listContents, contents.navEnum);
@ -484,10 +485,10 @@ public class Navigation {
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(SectionName.FIELD_SUMMARY, contents.navField));
links.createLink(HtmlIds.FIELD_SUMMARY, contents.navField));
} else {
addContentToList(listContents, links.createLink(SectionName.FIELDS_INHERITANCE,
configuration.getClassName(typeElement), contents.navField));
addContentToList(listContents,
links.createLink(htmlIds.forInheritedFields(typeElement), contents.navField));
}
} else {
addContentToList(listContents, contents.navField);
@ -497,10 +498,10 @@ public class Navigation {
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(SectionName.METHOD_SUMMARY, contents.navMethod));
links.createLink(HtmlIds.METHOD_SUMMARY, contents.navMethod));
} else {
addContentToList(listContents, links.createLink(SectionName.METHODS_INHERITANCE,
configuration.getClassName(typeElement), contents.navMethod));
addContentToList(listContents,
links.createLink(htmlIds.forInheritedMethods(typeElement), contents.navMethod));
}
} else {
addContentToList(listContents, contents.navMethod);
@ -510,10 +511,10 @@ public class Navigation {
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(SectionName.NESTED_CLASS_SUMMARY, contents.navNested));
links.createLink(HtmlIds.NESTED_CLASS_SUMMARY, contents.navNested));
} else {
addContentToList(listContents, links.createLink(SectionName.NESTED_CLASSES_INHERITANCE,
configuration.utils.getFullyQualifiedName(typeElement), contents.navNested));
addContentToList(listContents,
links.createLink(htmlIds.forInheritedClasses(typeElement), contents.navNested));
}
} else {
addContentToList(listContents, contents.navNested);
@ -523,10 +524,10 @@ public class Navigation {
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(SectionName.PROPERTY_SUMMARY, contents.navProperty));
links.createLink(HtmlIds.PROPERTY_SUMMARY, contents.navProperty));
} else {
addContentToList(listContents, links.createLink(SectionName.PROPERTIES_INHERITANCE,
configuration.getClassName(typeElement), contents.navProperty));
addContentToList(listContents,
links.createLink(htmlIds.forInheritedProperties(typeElement), contents.navProperty));
}
} else {
addContentToList(listContents, contents.navProperty);
@ -554,7 +555,7 @@ public class Navigation {
switch (kind) {
case FIELDS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.FIELD_SUMMARY,
addContentToList(listContents, links.createLink(HtmlIds.FIELD_SUMMARY,
contents.navField));
} else {
addContentToList(listContents, contents.navField);
@ -563,7 +564,7 @@ public class Navigation {
case ANNOTATION_TYPE_MEMBER_REQUIRED:
if (link) {
addContentToList(listContents, links.createLink(
SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
contents.navAnnotationTypeRequiredMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeRequiredMember);
@ -572,7 +573,7 @@ public class Navigation {
case ANNOTATION_TYPE_MEMBER_OPTIONAL:
if (link) {
addContentToList(listContents, links.createLink(
SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
contents.navAnnotationTypeOptionalMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeOptionalMember);
@ -637,35 +638,35 @@ public class Navigation {
switch (kind) {
case CONSTRUCTORS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_DETAIL, contents.navConstructor));
addContentToList(listContents, links.createLink(HtmlIds.CONSTRUCTOR_DETAIL, contents.navConstructor));
} else {
addContentToList(listContents, contents.navConstructor);
}
break;
case ENUM_CONSTANTS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_DETAIL, contents.navEnum));
addContentToList(listContents, links.createLink(HtmlIds.ENUM_CONSTANT_DETAIL, contents.navEnum));
} else {
addContentToList(listContents, contents.navEnum);
}
break;
case FIELDS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL, contents.navField));
addContentToList(listContents, links.createLink(HtmlIds.FIELD_DETAIL, contents.navField));
} else {
addContentToList(listContents, contents.navField);
}
break;
case METHODS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.METHOD_DETAIL, contents.navMethod));
addContentToList(listContents, links.createLink(HtmlIds.METHOD_DETAIL, contents.navMethod));
} else {
addContentToList(listContents, contents.navMethod);
}
break;
case PROPERTIES:
if (link) {
addContentToList(listContents, links.createLink(SectionName.PROPERTY_DETAIL, contents.navProperty));
addContentToList(listContents, links.createLink(HtmlIds.PROPERTY_DETAIL, contents.navProperty));
} else {
addContentToList(listContents, contents.navProperty);
}
@ -720,8 +721,8 @@ public class Navigation {
switch (type) {
case FIELDS:
if (link) {
addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL,
contents.navField));
addContentToList(listContents,
links.createLink(HtmlIds.FIELD_DETAIL, contents.navField));
} else {
addContentToList(listContents, contents.navField);
}
@ -729,7 +730,7 @@ public class Navigation {
case ANNOTATION_TYPE_MEMBER_REQUIRED:
case ANNOTATION_TYPE_MEMBER_OPTIONAL:
if (link) {
addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
addContentToList(listContents, links.createLink(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL,
contents.navAnnotationTypeMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeMember);
@ -914,18 +915,17 @@ public class Navigation {
Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links");
tree.add(MarkerComments.START_OF_TOP_NAVBAR);
navDiv.setStyle(HtmlStyle.topNav)
.setId(SectionName.NAVBAR_TOP.getName())
.setId(HtmlIds.NAVBAR_TOP)
.add(HtmlTree.DIV(HtmlStyle.skipNav,
links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
links.createLink(HtmlIds.SKIP_NAVBAR_TOP, skipNavLinks,
skipNavLinks.toString(), "")));
SectionName navListSection = SectionName.NAVBAR_TOP_FIRSTROW;
Content aboutContent = userHeader;
boolean addSearch = options.createIndex();
Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, aboutContent);
navDiv.add(aboutDiv);
HtmlTree navList = new HtmlTree(TagName.UL)
.setId(navListSection.getName())
.setId(HtmlIds.NAVBAR_TOP_FIRSTROW)
.setStyle(HtmlStyle.navList)
.put(HtmlAttr.TITLE, rowListTitle);
addMainNavLinks(navList);
@ -952,7 +952,7 @@ public class Navigation {
tree.add(MarkerComments.END_OF_TOP_NAVBAR);
tree.add(HtmlTree.SPAN(HtmlStyle.skipNav, HtmlTree.EMPTY)
.setId(SectionName.SKIP_NAVBAR_TOP.getName()));
.setId(HtmlIds.SKIP_NAVBAR_TOP));
return tree;
}

@ -72,7 +72,7 @@ public class NestedClassWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.nestedClassSummary,
SectionName.NESTED_CLASS_SUMMARY, summariesList, content);
HtmlIds.NESTED_CLASS_SUMMARY, summariesList, content);
}
@Override
@ -116,8 +116,7 @@ public class NestedClassWriterImpl extends AbstractMemberWriter
: resources.getText("doclet.Nested_Classes_Interfaces_Inherited_From_Class"));
}
HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING, label);
labelHeading.setId(SectionName.NESTED_CLASSES_INHERITANCE.getName()
+ links.getName(utils.getFullyQualifiedName(typeElement)));
labelHeading.setId(htmlIds.forInheritedClasses(typeElement));
labelHeading.add(Entity.NO_BREAK_SPACE);
labelHeading.add(classLink);
inheritedTree.add(labelHeading);

@ -94,7 +94,7 @@ public class PackageIndexWriter extends AbstractOverviewIndexWriter {
Table table = new Table(HtmlStyle.summaryTable)
.setHeader(getPackageTableHeader())
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast)
.setId("all-packages-table")
.setId(HtmlIds.ALL_PACKAGES_TABLE)
.setDefaultTab(resources.getText("doclet.All_Packages"));
// add the tabs in command-line order

@ -162,7 +162,7 @@ public class PackageUseWriter extends SubWriterHolderWriter {
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
for (String pkgname: usingPackageToUsedClasses.keySet()) {
PackageElement pkg = utils.elementUtils.getPackageElement(pkgname);
Content packageLink = links.createLink(getPackageAnchorName(pkg),
Content packageLink = links.createLink(htmlIds.forPackage(pkg),
new StringContent(utils.getPackageName(pkg)));
Content summary = new ContentBuilder();
if (pkg != null && !pkg.isUnnamed()) {
@ -188,7 +188,7 @@ public class PackageUseWriter extends SubWriterHolderWriter {
for (String packageName : usingPackageToUsedClasses.keySet()) {
PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName);
HtmlTree section = HtmlTree.SECTION(HtmlStyle.detail)
.setId(getPackageAnchorName(usingPackage));
.setId(htmlIds.forPackage(usingPackage));
Content caption = contents.getContent(
"doclet.ClassUse_Classes.in.0.used.by.1",
getPackageLink(packageElement, utils.getPackageName(packageElement)),
@ -201,7 +201,7 @@ public class PackageUseWriter extends SubWriterHolderWriter {
DocPath dp = pathString(te,
DocPaths.CLASS_USE.resolve(docPaths.forName(te)));
Content stringContent = new StringContent(utils.getSimpleName(te));
Content typeContent = links.createLink(dp.fragment(getPackageAnchorName(usingPackage)),
Content typeContent = links.createLink(dp.fragment(htmlIds.forPackage(usingPackage).name()),
stringContent);
Content summary = new ContentBuilder();
addIndexComment(te, summary);

@ -239,7 +239,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
addPreviewInfo(packageElement, packageContentTree);
if (!utils.getBody(packageElement).isEmpty()) {
HtmlTree tree = sectionTree;
tree.setId(SectionName.PACKAGE_DESCRIPTION.getName());
tree.setId(HtmlIds.PACKAGE_DESCRIPTION);
addDeprecationInfo(tree);
addInlineComment(packageElement, tree);
}

@ -66,7 +66,7 @@ public class PropertyWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.propertySummary,
SectionName.PROPERTY_SUMMARY, summariesList, content);
HtmlIds.PROPERTY_SUMMARY, summariesList, content);
}
@Override
@ -86,7 +86,7 @@ public class PropertyWriterImpl extends AbstractMemberWriter
new StringContent(utils.getPropertyLabel(name(property))));
propertyDocTree.add(heading);
return HtmlTree.SECTION(HtmlStyle.detail, propertyDocTree)
.setId(name(property));
.setId(htmlIds.forProperty(property));
}
@Override
@ -141,7 +141,7 @@ public class PropertyWriterImpl extends AbstractMemberWriter
public Content getPropertyDetails(Content propertyDetailsTreeHeader, Content propertyDetailsTree) {
return writer.getDetailsListItem(
HtmlTree.SECTION(HtmlStyle.propertyDetails)
.setId(SectionName.PROPERTY_DETAIL.getName())
.setId(HtmlIds.PROPERTY_DETAIL)
.add(propertyDetailsTreeHeader)
.add(propertyDetailsTree));
}
@ -181,12 +181,11 @@ public class PropertyWriterImpl extends AbstractMemberWriter
? resources.getText("doclet.Properties_Inherited_From_Class")
: resources.getText("doclet.Properties_Inherited_From_Interface"));
}
HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING,
label);
labelHeading.setId(SectionName.PROPERTIES_INHERITANCE.getName()
+ links.getName(configuration.getClassName(typeElement)));
labelHeading.add(Entity.NO_BREAK_SPACE);
labelHeading.add(classLink);
HtmlTree labelHeading =
HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, label)
.setId(htmlIds.forInheritedProperties(typeElement))
.add(Entity.NO_BREAK_SPACE)
.add(classLink);
inheritedTree.add(labelHeading);
}

@ -1,80 +0,0 @@
/*
* Copyright (c) 2013, 2019, 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.
*/
package jdk.javadoc.internal.doclets.formats.html;
/**
* Enum representing various section names of generated API documentation.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public enum SectionName {
ANNOTATION_TYPE_ELEMENT_DETAIL("annotation.interface.element.detail"),
ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY("annotation.interface.optional.element.summary"),
ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY("annotation.interface.required.element.summary"),
CONSTRUCTOR_DETAIL("constructor.detail"),
CONSTRUCTOR_SUMMARY("constructor.summary"),
ENUM_CONSTANT_DETAIL("enum.constant.detail"),
ENUM_CONSTANTS_INHERITANCE("enum.constants.inherited.from.class."),
ENUM_CONSTANT_SUMMARY("enum.constant.summary"),
FIELD_DETAIL("field.detail"),
FIELDS_INHERITANCE("fields.inherited.from.class."),
FIELD_SUMMARY("field.summary"),
METHOD_DETAIL("method.detail"),
METHODS_INHERITANCE("methods.inherited.from.class."),
METHOD_SUMMARY("method.summary"),
MODULE_DESCRIPTION("module.description"),
MODULES("modules.summary"),
PACKAGES("packages.summary"),
SERVICES("services.summary"),
NAVBAR_BOTTOM("navbar.bottom"),
NAVBAR_BOTTOM_FIRSTROW("navbar.bottom.firstrow"),
NAVBAR_TOP("navbar.top"),
NAVBAR_TOP_FIRSTROW("navbar.top.firstrow"),
NESTED_CLASSES_INHERITANCE("nested.classes.inherited.from.class."),
NESTED_CLASS_SUMMARY("nested.class.summary"),
OVERVIEW_DESCRIPTION("overview.description"),
PACKAGE_DESCRIPTION("package.description"),
PROPERTY_DETAIL("property.detail"),
PROPERTIES_INHERITANCE("properties.inherited.from.class."),
PROPERTY_SUMMARY("property.summary"),
SKIP_NAVBAR_BOTTOM("skip.navbar.bottom"),
SKIP_NAVBAR_TOP("skip.navbar.top"),
UNNAMED_PACKAGE_ANCHOR("unnamed.package");
private final String value;
SectionName(String sName) {
this.value = sName;
}
public String getName() {
return this.value;
}
}

@ -29,7 +29,6 @@ import java.util.Set;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
@ -154,7 +153,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter
.label(configuration.getClassName(typeElement)))
: new StringContent(utils.getFullyQualifiedName(typeElement));
Content section = HtmlTree.SECTION(HtmlStyle.serializedClassDetails)
.setId(utils.getFullyQualifiedName(typeElement));
.setId(htmlIds.forClass(typeElement));
Content superClassLink = typeElement.getSuperclass() != null
? getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.SERIALIZED_FORM,
typeElement.getSuperclass()))

@ -158,7 +158,7 @@ public class Signatures {
content.add(DocletConstants.NL);
permitsSpan.add("permits");
Content link =
classWriter.links.createLink(classWriter.getPreviewSectionAnchor(typeElement),
classWriter.links.createLink(classWriter.htmlIds.forPreviewSection(typeElement),
classWriter.contents.previewMark);
permitsSpan.add(HtmlTree.SUP(link));
permitsSpan.add(" ");

@ -37,6 +37,7 @@ import javax.tools.FileObject;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
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.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@ -312,7 +313,7 @@ public class SourceToHTMLConverter {
private void addLine(Content pre, String line, int currentLineNo) {
if (line != null) {
Content anchor = HtmlTree.SPAN_ID(
"line." + Integer.toString(currentLineNo),
HtmlIds.forLine(currentLineNo),
new StringContent(utils.replaceTabs(line)));
pre.add(anchor);
pre.add(NEW_LINE);

@ -34,6 +34,7 @@ import com.sun.source.doctree.DeprecatedTree;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
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.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@ -283,13 +284,13 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
* Adds a section for a summary tree with the given CSS {@code class} and {@code id} attribute.
*
* @param style the CSS class for the section
* @param sectionName the section name to use for the section id attribute
* @param htmlId the id for the section
* @param summariesList the list of summary sections to which the summary will be added
* @param content the content tree representing the summary
*/
public void addSummary(HtmlStyle style, SectionName sectionName, Content summariesList, Content content) {
public void addSummary(HtmlStyle style, HtmlId htmlId, Content summariesList, Content content) {
HtmlTree htmlTree = HtmlTree.SECTION(style, content)
.setId(sectionName.getName());
.setId(htmlId);
summariesList.add(getSummariesListItem(htmlTree));
}

@ -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.HtmlId;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.Table;
import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader;
@ -46,37 +47,16 @@ import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder.SummaryElementKind;
/**
* Generate File to list all the summary elements with the
* appropriate links.
* Base class for generating a summary page that lists elements with a common characteristic,
* such as deprecated elements, preview elements, and so on.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*
* @see java.util.List
*/
public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends SubWriterHolderWriter {
private String getAnchorName(SummaryElementKind kind) {
return switch (kind) {
case MODULE -> "module";
case PACKAGE -> "package";
case INTERFACE -> "interface";
case CLASS -> "class";
case ENUM -> "enum.class";
case EXCEPTION -> "exception";
case ERROR -> "error";
case ANNOTATION_TYPE -> "annotation.interface";
case FIELD -> "field";
case METHOD -> "method";
case CONSTRUCTOR -> "constructor";
case ENUM_CONSTANT -> "enum.constant";
case ANNOTATION_TYPE_MEMBER -> "annotation.interface.member";
case RECORD_CLASS -> "record.class";
};
}
private String getHeadingKey(SummaryElementKind kind) {
return switch (kind) {
case MODULE -> "doclet.Modules";
@ -155,7 +135,7 @@ public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends
addExtraSection(summaryapi, content);
for (SummaryElementKind kind : SummaryElementKind.values()) {
if (summaryapi.hasDocumentation(kind)) {
addSummaryAPI(summaryapi.getSet(kind), getAnchorName(kind),
addSummaryAPI(summaryapi.getSet(kind), HtmlIds.forSummaryKind(kind),
getHeadingKey(kind), getHeaderKey(kind), content);
}
}
@ -168,13 +148,12 @@ public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends
/**
* Add the index link.
*
* @param builder the summary list builder
* @param kind the kind of list being documented
* @param id the id for the link
* @param headingKey
* @param contentTree the content tree to which the index link will be added
*/
protected void addIndexLink(String anchorName, String headingKey,
Content contentTree) {
Content li = HtmlTree.LI(links.createLink(anchorName,
protected void addIndexLink(HtmlId id, String headingKey, Content contentTree) {
Content li = HtmlTree.LI(links.createLink(id,
contents.getContent(headingKey)));
contentTree.add(li);
}
@ -182,10 +161,10 @@ public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends
/**
* Get the contents list.
*
* @param apisummary the summary list builder
* @param apiSummary the summary list builder
* @return a content tree for the contents list
*/
public Content getContentsList(L apisummary) {
public Content getContentsList(L apiSummary) {
Content heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING,
HtmlStyle.title, headContent);
Content div = HtmlTree.DIV(HtmlStyle.header, heading);
@ -193,10 +172,10 @@ public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends
div.add(HtmlTree.HEADING_TITLE(Headings.CONTENT_HEADING,
headingContent));
Content ul = new HtmlTree(TagName.UL);
addExtraIndexLink(apisummary, ul);
addExtraIndexLink(apiSummary, ul);
for (SummaryElementKind kind : SummaryElementKind.values()) {
if (apisummary.hasDocumentation(kind)) {
addIndexLink(getAnchorName(kind), getHeadingKey(kind), ul);
if (apiSummary.hasDocumentation(kind)) {
addIndexLink(HtmlIds.forSummaryKind(kind), getHeadingKey(kind), ul);
}
}
div.add(ul);
@ -224,7 +203,7 @@ public abstract class SummaryListWriter<L extends SummaryAPIListBuilder> extends
* @param headerKey table header key for the summary table
* @param contentTree the content tree to which the summary table will be added
*/
protected void addSummaryAPI(SortedSet<Element> apiList, String id,
protected void addSummaryAPI(SortedSet<Element> apiList, HtmlId id,
String headingKey, String headerKey,
Content contentTree) {
if (apiList.size() > 0) {

@ -47,6 +47,7 @@ import com.sun.source.doctree.SeeTree;
import com.sun.source.doctree.SystemPropertyTree;
import com.sun.source.doctree.ThrowsTree;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
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.RawHtml;
@ -85,10 +86,26 @@ public class TagletWriterImpl extends TagletWriter {
private final Resources resources;
private final Contents contents;
/**
* Creates a taglet writer.
*
* @param htmlWriter the {@code HtmlDocletWriter} for the page
* @param isFirstSentence {@code true} if this taglet writer is being used for a
* "first sentence" summary
*/
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence) {
this(htmlWriter, isFirstSentence, false);
}
/**
* Creates a taglet writer.
*
* @param htmlWriter the {@code HtmlDocletWriter} for the page
* @param isFirstSentence {@code true} if this taglet writer is being used for a
* "first sentence" summary, and {@code false} otherwise
* @param inSummary {@code true} if this taglet writer is being used for the content
* of a {@code {@summary ...}} tag, and {@code false} otherwise
*/
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence, boolean inSummary) {
super(isFirstSentence);
this.htmlWriter = htmlWriter;
@ -202,7 +219,7 @@ public class TagletWriterImpl extends TagletWriter {
boolean defineID = (element.getKind() == ElementKind.RECORD)
&& !paramTag.isTypeParameter();
Content nameTree = new StringContent(paramName);
body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID("param-" + paramName, nameTree) : nameTree));
body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID(HtmlIds.forParam(paramName), nameTree) : nameTree));
body.add(" - ");
List<? extends DocTree> description = ch.getDescription(paramTag);
body.add(htmlWriter.commentTagsToContent(paramTag, element, description, false, inSummary));
@ -375,13 +392,8 @@ public class TagletWriterImpl extends TagletWriter {
if (isFirstSentence && inSummary) {
result = new StringContent(tagText);
} else {
String anchorName = htmlWriter.links.getName(tagText);
int count = htmlWriter.indexAnchorTable
.compute(anchorName, (k, v) -> v == null ? 0 : v + 1);
if (count > 0) {
anchorName += "-" + count;
}
result = HtmlTree.SPAN(anchorName, HtmlStyle.searchTagResult, new StringContent(tagText));
HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable);
result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, new StringContent(tagText));
if (options.createIndex() && !tagText.isEmpty()) {
String holder = new SimpleElementVisitor14<String, Void>() {
@ -435,7 +447,7 @@ public class TagletWriterImpl extends TagletWriter {
}
}.visit(element);
IndexItem item = IndexItem.of(element, tree, tagText, holder, desc,
new DocLink(htmlWriter.path, anchorName));
new DocLink(htmlWriter.path, id.name()));
configuration.mainIndex.add(item);
}
}

@ -0,0 +1,50 @@
/*
* 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.
*/
package jdk.javadoc.internal.doclets.formats.html.markup;
/**
* A type-safe wrapper around a {@code String}, for use as an "id"
* in {@code HtmlTree} objects.
*
* @see HtmlTree#setId(HtmlId)
*/
public interface HtmlId {
/**
* Creates an id with the given name.
*
* @param name the name
* @return the id
*/
static HtmlId of(String name) {
assert name.indexOf(' ') == -1;
return () -> name;
}
/**
* {@return the name of the id}
*/
String name();
}

@ -119,8 +119,8 @@ public class HtmlTree extends Content {
* @param id the value for the attribute
* @return this object
*/
public HtmlTree setId(String id) {
return put(HtmlAttr.ID, id);
public HtmlTree setId(HtmlId id) {
return put(HtmlAttr.ID, id.name());
}
/**
@ -762,7 +762,7 @@ public class HtmlTree extends Content {
* @param body the content
* @return the element
*/
public static HtmlTree SPAN_ID(String id, Content body) {
public static HtmlTree SPAN_ID(HtmlId id, Content body) {
return new HtmlTree(TagName.SPAN)
.setId(id)
.add(body);
@ -776,7 +776,7 @@ public class HtmlTree extends Content {
* @param body the content
* @return the element
*/
public static HtmlTree SPAN(String id, HtmlStyle style, Content body) {
public static HtmlTree SPAN(HtmlId id, HtmlStyle style, Content body) {
return new HtmlTree(TagName.SPAN)
.setId(id)
.setStyle(style)

@ -25,22 +25,12 @@
package jdk.javadoc.internal.doclets.formats.html.markup;
import javax.lang.model.element.ExecutableElement;
import jdk.javadoc.internal.doclets.formats.html.SectionName;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
/**
* Factory for HTML A elements, both links (with a {@code href} attribute)
* and anchors (with an {@code id} or {@code name} attribute).
*
* Most methods in this class are static factory methods.
* The exceptions are those methods that directly or indirectly depend on the HTML version
* being used, when determining valid HTML names (ids),
* and those methods that generate anchors.
* Factory for HTML A elements: links (with a {@code href} attribute).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
@ -50,71 +40,41 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
public class Links {
private final DocPath file;
private final Utils utils;
/**
* Creates a {@code Links} object for a specific file, to be written in a specific HTML version.
* The version is used by the {@link #getName(String) getName} method
* to help determine valid HTML names (ids), and to determine whether
* to use an {@code id} or {@code name} attribute when creating anchors.
* Creates a {@code Links} object for a specific file.
* Links to other files will be made relative to this file where possible.
*
* @param file the file
*/
public Links(DocPath file, Utils utils) {
public Links(DocPath file) {
this.file = file;
this.utils = utils;
}
/**
* Creates a link of the form {@code <a href="#where">label</a>}.
* Creates a link of the form {@code <a href="#id">label</a>}.
*
* @param where the position of the link in the file
* @param id the position of the link in the file
* @param label the content for the link
* @return a content tree for the link
*/
public Content createLink(String where, Content label) {
DocLink l = DocLink.fragment(getName(where));
public Content createLink(HtmlId id, Content label) {
DocLink l = DocLink.fragment(id.name());
return createLink(l, label, "", "");
}
/**
* Creates a link of the form {@code <a href="#sectionName">label</a>}.
* Creates a link of the form {@code <a href="#id" title="title" target="target">label</a>}.
*
* @param id the id to which the link will be created
* @param label the content for the link
* @param title the title for the link
* @param target the target for the link, or null
*
* @param sectionName the section name to which the link will be created
* @param label the content for the link
* @return a content tree for the link
*/
public Content createLink(SectionName sectionName, Content label) {
DocLink l = DocLink.fragment(sectionName.getName());
return createLink(l, label, "", "");
}
/**
* Creates a link of the form {@code <a href="#sectionNameWhere">label</a>}.
*
* @param sectionName the section name combined with where to which the link
* will be created
* @param where the fragment combined with sectionName to which the link
* will be created
* @param label the content for the link
* @return a content tree for the link
*/
public Content createLink(SectionName sectionName, String where, Content label) {
DocLink l = DocLink.fragment(sectionName.getName() + getName(where));
return createLink(l, label, "", "");
}
/**
* Creates a link of the form {@code <a href="#stylename" title="title" target="target">label</a>}.
*
* @param sectionName the section name to which the link will be created
* @param label the content for the link
* @param title the title for the link
* @param target the target for the link, or null
* @return a content tree for the link
*/
public Content createLink(SectionName sectionName, Content label, String title, String target) {
DocLink l = DocLink.fragment(sectionName.getName());
public Content createLink(HtmlId id, Content label, String title, String target) {
DocLink l = DocLink.fragment(id.name());
return createLink(l, label, title, target);
}
@ -251,54 +211,14 @@ public class Links {
}
/**
* Creates a link.
* Creates an external link.
*
* @param link the details for the link
* @param label the content for the link
* @param isExternal is the link external to the generated documentation
* @return a content tree for the link
*/
public Content createLink(DocLink link, Content label, boolean isExternal) {
HtmlTree anchor = HtmlTree.A(link.relativizeAgainst(file).toString(), label);
anchor.setStyle(HtmlStyle.externalLink);
return anchor;
public Content createExternalLink(DocLink link, Content label) {
return HtmlTree.A(link.relativizeAgainst(file).toString(), label)
.setStyle(HtmlStyle.externalLink);
}
/**
* Returns the HTML id to use for an executable element.
*
* @param executableElement the element
*
* @return the id
*/
public String getAnchor(ExecutableElement executableElement) {
return getAnchor(executableElement, false);
}
/**
* Returns the HTML id to use for an executable element.
*
* @param executableElement the element
* @param isProperty whether or not the element represents a property
*
* @return the id
*/
public String getAnchor(ExecutableElement executableElement, boolean isProperty) {
String a = isProperty
? executableElement.getSimpleName().toString()
: executableElement.getSimpleName()
+ utils.makeSignature(executableElement, null, true, true);
return getName(a);
}
/**
* Converts a name to a valid HTML id.
*
* @param name the string that needs to be converted to a valid HTML id
* @return a valid HTML name
*/
public String getName(String name) {
return name.replaceAll("\\s+", "");
}
}

@ -34,11 +34,11 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import javax.lang.model.element.Element;
import jdk.javadoc.internal.doclets.formats.html.HtmlIds;
import jdk.javadoc.internal.doclets.toolkit.Content;
/**
@ -77,12 +77,11 @@ public class Table extends Content {
private HtmlStyle tabListStyle = HtmlStyle.tableTabs;
private HtmlStyle activeTabStyle = HtmlStyle.activeTableTab;
private HtmlStyle tabStyle = HtmlStyle.tableTab;
private BiFunction<String, Integer, String> tabId = (tableId, tabIndex) -> tableId + "-tab" + tabIndex;
private TableHeader header;
private List<HtmlStyle> columnStyles;
private List<HtmlStyle> stripedStyles = Arrays.asList(HtmlStyle.evenRowColor, HtmlStyle.oddRowColor);
private final List<Content> bodyRows;
private String id;
private HtmlId id;
/**
* Creates a builder for an HTML element representing a table.
@ -222,7 +221,7 @@ public class Table extends Content {
* @param id the id
* @return this object
*/
public Table setId(String id) {
public Table setId(HtmlId id) {
this.id = id;
return this;
}
@ -275,7 +274,7 @@ public class Table extends Content {
/**
* Adds a row of data to the table.
* Each item of content should be suitable for use as the content of a
* {@code <th>} or {@code <td>} cell.
* {@code <div>} cell.
*
* If tabs have been added to the table, the specified element will be used
* to determine whether the row should be displayed when any particular tab
@ -299,16 +298,21 @@ public class Table extends Content {
int rowIndex = bodyRows.size();
rowStyle = stripedStyles.get(rowIndex % 2);
}
Set<String> tabClasses = new HashSet<>();
Set<String> tabClasses = new HashSet<>(); // !! would be better as a List
if (tabMap != null) {
tabClasses.add(id);
// Construct a series of CSS classes to add to the cells of this row,
// such that there is a default value and a value corresponding to each
// tab whose predicate matches the element. The classes correspond to
// the equivalent ids. The classes are used to determine the cells to
// make visible when a tab is selected.
tabClasses.add(id.name());
int tabIndex = 1;
for (Map.Entry<String, Predicate<Element>> e : tabMap.entrySet()) {
String name = e.getKey();
Predicate<Element> predicate = e.getValue();
if (predicate.test(element)) {
tabs.add(name);
tabClasses.add(tabId.apply(id, tabIndex));
tabClasses.add(HtmlIds.forTab(id, tabIndex).name());
}
tabIndex++;
}
@ -382,12 +386,12 @@ public class Table extends Content {
.put(HtmlAttr.ARIA_ORIENTATION, "horizontal");
int tabIndex = 0;
tablist.add(createTab(tabId.apply(id, tabIndex), activeTabStyle, true, defaultTab));
table.put(HtmlAttr.ARIA_LABELLEDBY, tabId.apply(id, tabIndex));
tablist.add(createTab(HtmlIds.forTab(id, tabIndex), activeTabStyle, true, defaultTab));
table.put(HtmlAttr.ARIA_LABELLEDBY, HtmlIds.forTab(id, tabIndex).name());
for (String tabName : tabMap.keySet()) {
tabIndex++;
if (tabs.contains(tabName)) {
HtmlTree tab = createTab(tabId.apply(id, tabIndex), tabStyle, false, tabName);
HtmlTree tab = createTab(HtmlIds.forTab(id, tabIndex), tabStyle, false, tabName);
tablist.add(tab);
}
}
@ -395,7 +399,7 @@ public class Table extends Content {
throw new IllegalStateException("no id set for table");
}
HtmlTree tabpanel = new HtmlTree(TagName.DIV)
.put(HtmlAttr.ID, id + ".tabpanel")
.setId(HtmlIds.forTabPanel(id))
.put(HtmlAttr.ROLE, "tabpanel");
table.add(getTableBody());
tabpanel.add(table);
@ -405,15 +409,15 @@ public class Table extends Content {
return main;
}
private HtmlTree createTab(String tabId, HtmlStyle style, boolean defaultTab, String tabName) {
private HtmlTree createTab(HtmlId tabId, HtmlStyle style, boolean defaultTab, String tabName) {
HtmlTree tab = new HtmlTree(TagName.BUTTON)
.put(HtmlAttr.ID, tabId)
.setId(tabId)
.put(HtmlAttr.ROLE, "tab")
.put(HtmlAttr.ARIA_SELECTED, defaultTab ? "true" : "false")
.put(HtmlAttr.ARIA_CONTROLS, id + ".tabpanel")
.put(HtmlAttr.ARIA_CONTROLS, HtmlIds.forTabPanel(id).name())
.put(HtmlAttr.TABINDEX, defaultTab ? "0" : "-1")
.put(HtmlAttr.ONKEYDOWN, "switchTab(event)")
.put(HtmlAttr.ONCLICK, "show('" + id + "', '" + (defaultTab ? id : tabId)
.put(HtmlAttr.ONCLICK, "show('" + id.name() + "', '" + (defaultTab ? id : tabId).name()
+ "', " + columnStyles.size() + ")")
.setStyle(style);
tab.add(tabName);

@ -52,6 +52,7 @@ public class SummaryAPIListBuilder {
private final BaseConfiguration configuration;
protected final Utils utils;
private final Predicate<Element> belongsToSummary;
public enum SummaryElementKind {
MODULE,
PACKAGE,
@ -68,6 +69,7 @@ public class SummaryAPIListBuilder {
ENUM_CONSTANT,
ANNOTATION_TYPE_MEMBER // no ElementKind mapping
};
/**
* Constructor.
*
@ -175,9 +177,8 @@ public class SummaryAPIListBuilder {
/**
* Add the members into a single list of summary members.
*
* @param rset set of elements summary for removal.
* @param sset set of summary elements.
* @param members members to be added in the list.
* @param sset set of summary elements
* @param members members to be added in the list
*/
private void composeSummaryList(SortedSet<Element> sset, List<? extends Element> members) {
for (Element member : members) {