diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 1c325db50e9..7efa7b85992 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -27,6 +27,7 @@ package jdk.javadoc.internal.doclets.formats.html; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -263,7 +264,7 @@ public class HtmlDocletWriter { do { int match = docrootMatcher.start(); // append htmlstr up to start of next {@docroot} - buf.append(htmlstr.substring(prevEnd, match)); + buf.append(htmlstr, prevEnd, match); prevEnd = docrootMatcher.end(); if (options.docrootParent().length() > 0 && htmlstr.startsWith("/..", prevEnd)) { // Insert the absolute link if {@docRoot} is followed by "/..". @@ -549,8 +550,7 @@ public class HtmlDocletWriter { protected Content getNavLinkMainTree(String label) { Content mainTreeContent = links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), Text.of(label)); - Content li = HtmlTree.LI(mainTreeContent); - return li; + return HtmlTree.LI(mainTreeContent); } /** @@ -623,7 +623,7 @@ public class HtmlDocletWriter { } else { flags = EnumSet.noneOf(ElementFlag.class); } - DocLink targetLink = null; + DocLink targetLink; if (included || packageElement == null) { targetLink = new DocLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY)); } else { @@ -1531,18 +1531,11 @@ public class HtmlDocletWriter { return false; } sb.append("="); - String quote; - switch (node.getValueKind()) { - case DOUBLE: - quote = "\""; - break; - case SINGLE: - quote = "'"; - break; - default: - quote = ""; - break; - } + String quote = switch (node.getValueKind()) { + case DOUBLE -> "\""; + case SINGLE -> "'"; + default -> ""; + }; sb.append(quote); result.add(sb); Content docRootContent = new ContentBuilder(); @@ -1794,9 +1787,9 @@ public class HtmlDocletWriter { if (detail.isEmpty() || detail.get().isEmpty()) { return HtmlTree.SPAN(HtmlStyle.invalidTag, Text.of(summary)); } - return new HtmlTree(TagName.DETAILS).addStyle(HtmlStyle.invalidTag) - .add(new HtmlTree(TagName.SUMMARY).add(Text.of(summary))) - .add(new HtmlTree(TagName.PRE).add(detail.get())); + return HtmlTree.DETAILS(HtmlStyle.invalidTag) + .add(HtmlTree.SUMMARY(Text.of(summary))) + .add(HtmlTree.PRE(detail.get())); } /** @@ -2226,17 +2219,13 @@ public class HtmlDocletWriter { for (Element e: chain) { String name; switch (e.getKind()) { - case MODULE: - case PACKAGE: + case MODULE, PACKAGE -> { name = ((QualifiedNameable) e).getQualifiedName().toString(); if (name.length() == 0) { name = ""; } - break; - - default: - name = e.getSimpleName().toString(); - break; + } + default -> name = e.getSimpleName().toString(); } if (sb.length() == 0) { @@ -2444,8 +2433,7 @@ public class HtmlDocletWriter { private Content withPreviewFeatures(String key, String className, String featureName, List features) { String[] sep = new String[] {""}; ContentBuilder featureCodes = new ContentBuilder(); - features.stream() - .forEach(c -> { + features.forEach(c -> { featureCodes.add(sep[0]); featureCodes.add(HtmlTree.CODE(new ContentBuilder().add(c))); sep[0] = ", "; @@ -2460,7 +2448,7 @@ public class HtmlDocletWriter { String[] sep = new String[] {""}; ContentBuilder links = new ContentBuilder(); elements.stream() - .sorted((te1, te2) -> te1.getSimpleName().toString().compareTo(te2.getSimpleName().toString())) + .sorted(Comparator.comparing(te -> te.getSimpleName().toString())) .distinct() .map(te -> getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.CLASS, te) .label(HtmlTree.CODE(Text.of(te.getSimpleName()))).skipPreview(true))) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 9d1ad310767..4b954ef1a31 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, 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 @@ -27,14 +27,17 @@ package jdk.javadoc.internal.doclets.formats.html.markup; import java.io.IOException; import java.io.Writer; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr.Role; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -222,6 +225,20 @@ public class HtmlTree extends Content { return this; } + /** + * Adds each of a collection of items, using a map function to create the content for each item. + * + * @param items the items + * @param mapper the map function to generate the content for each item + * + * @return this object + */ + @Override + public HtmlTree addAll(Collection items, Function mapper) { + items.forEach(item -> add(mapper.apply(item))); + return this; + } + @Override public int charCount() { int n = 0; @@ -301,6 +318,7 @@ public class HtmlTree extends Content { /** * Creates an HTML {@code A} element. + * The {@code ref} argument will be URL-encoded for use as the attribute value. * * @param ref the value for the {@code href} attribute} * @param body the content for element @@ -312,6 +330,22 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code A} element. + * The {@code ref} argument is assumed to be already suitably encoded, + * and will not be additionally URL-encoded, but will be + * {@link URI#toASCIIString() converted} to ASCII for use as the attribute value. + * + * @param ref the value for the {@code href} attribute} + * @param body the content for element + * @return the element + */ + public static HtmlTree A(URI ref, Content body) { + return new HtmlTree(TagName.A) + .put(HtmlAttr.HREF, ref.toASCIIString()) + .add(body); + } + /** * Creates an HTML {@code CAPTION} element with the given content. * @@ -345,6 +379,16 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code DETAILS} element. + * + * @return the element + */ + public static HtmlTree DETAILS(HtmlStyle style) { + return new HtmlTree(TagName.DETAILS) + .setStyle(style); + } + /** * Creates an HTML {@code DL} element with the given style. * @@ -495,12 +539,10 @@ public class HtmlTree extends Content { } private static TagName checkHeading(TagName headingTag) { - switch (headingTag) { - case H1: case H2: case H3: case H4: case H5: case H6: - return headingTag; - default: - throw new IllegalArgumentException(headingTag.toString()); - } + return switch (headingTag) { + case H1, H2, H3, H4, H5, H6 -> headingTag; + default -> throw new IllegalArgumentException(headingTag.toString()); + }; } /** @@ -682,6 +724,16 @@ public class HtmlTree extends Content { .setStyle(style); } + /** + * Creates an HTML {@code PRE} element with some content. + * + * @param body the content + * @return the element + */ + public static HtmlTree PRE(Content body) { + return new HtmlTree(TagName.PRE).add(body); + } + /** * Creates an HTML {@code SCRIPT} element with some script content. * The type of the script is set to {@code text/javascript}. @@ -782,6 +834,17 @@ public class HtmlTree extends Content { .add(body); } + /** + * Creates an HTML {@code SUMMARY} element with the given content. + * + * @param body the content + * @return the element + */ + public static HtmlTree SUMMARY(Content body) { + return new HtmlTree(TagName.SUMMARY) + .add(body); + } + /** * Creates an HTML {@code SUP} element with the given content. * @@ -874,6 +937,21 @@ public class HtmlTree extends Content { return htmlTree; } + /** + * Creates an HTML {@code UL} element with the given style and content generated + * from a collection of items.. + * + * @param style the style + * @param items the items to be added to the list + * @param mapper a mapper to create the content for each item + * @return the element + */ + public static HtmlTree UL(HtmlStyle style, Collection items, Function mapper) { + return new HtmlTree(TagName.UL) + .setStyle(style) + .addAll(items, mapper); + } + @Override public boolean isEmpty() { return (!hasContent() && !hasAttrs()); @@ -916,30 +994,29 @@ public class HtmlTree extends Content { */ @Override public boolean isValid() { - switch (tagName) { - case A: - return (hasAttr(HtmlAttr.ID) || (hasAttr(HtmlAttr.HREF) && hasContent())); - case BR: - return (!hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR))); - case HR: - case INPUT: - return (!hasContent()); - case IMG: - return (hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent()); - case LINK: - return (hasAttr(HtmlAttr.HREF) && !hasContent()); - case META: - return (hasAttr(HtmlAttr.CONTENT) && !hasContent()); - case SCRIPT: - return ((hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) || - (hasAttr(HtmlAttr.TYPE) && hasContent())); - case SPAN: - return (hasAttr(HtmlAttr.ID) || hasContent()); - case WBR: - return (!hasContent()); - default : - return hasContent(); - } + return switch (tagName) { + case A -> + hasAttr(HtmlAttr.ID) || (hasAttr(HtmlAttr.HREF) && hasContent()); + case BR -> + !hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR)); + case HR, INPUT -> + !hasContent(); + case IMG -> + hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent(); + case LINK -> + hasAttr(HtmlAttr.HREF) && !hasContent(); + case META -> + hasAttr(HtmlAttr.CONTENT) && !hasContent(); + case SCRIPT -> + (hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) + || (hasAttr(HtmlAttr.TYPE) && hasContent()); + case SPAN -> + hasAttr(HtmlAttr.ID) || hasContent(); + case WBR -> + !hasContent(); + default -> + hasContent(); + }; } /** @@ -950,14 +1027,10 @@ public class HtmlTree extends Content { * @see Phrasing Content */ public boolean isInline() { - switch (tagName) { - case A: case BUTTON: case BR: case CODE: case EM: case I: case IMG: - case LABEL: case SMALL: case SPAN: case STRONG: case SUB: case SUP: - case WBR: - return true; - default: - return false; - } + return switch (tagName) { + case A, BUTTON, BR, CODE, EM, I, IMG, LABEL, SMALL, SPAN, STRONG, SUB, SUP, WBR -> true; + default -> false; + }; } /** @@ -968,12 +1041,10 @@ public class HtmlTree extends Content { * @see Void Elements */ public boolean isVoid() { - switch (tagName) { - case BR: case HR: case IMG: case INPUT: case LINK: case META: case WBR: - return true; - default: - return false; - } + return switch (tagName) { + case BR, HR, IMG, INPUT, LINK, META, WBR -> true; + default -> false; + }; } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java index 84cc66912b4..80dd9c48587 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java @@ -28,6 +28,8 @@ package jdk.javadoc.internal.doclets.toolkit; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; +import java.util.Collection; +import java.util.function.Function; /** * A class to create content for javadoc output pages. @@ -89,6 +91,25 @@ public abstract class Content { throw new UnsupportedOperationException(); } + /** + * Adds content to the existing content, generated from a collection of items + * This is an optional operation. + * + * @implSpec This implementation delegates to {@link #add(Content)}. + * + * @param items the items to be added + * @param mapper the function to create content for each item + * + * @return this object + * @throws UnsupportedOperationException if this operation is not supported by + * a particular implementation + * @throws IllegalArgumentException if the content is not suitable to be added + */ + public Content addAll(Collection items, Function mapper) { + items.forEach(item -> add(mapper.apply(item))); + return this; + } + /** * Writes content to a writer. *