8280402: Add new convenience forms to HtmlTree

Reviewed-by: hannesw
This commit is contained in:
Jonathan Gibbons 2022-01-26 17:06:50 +00:00
parent f34f8d4d6a
commit e1d8f55564
3 changed files with 154 additions and 74 deletions

View File

@ -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 = "<unnamed>";
}
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<String> 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)))

View File

@ -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 <T> HtmlTree addAll(Collection<T> items, Function<T, Content> 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 <i>not</i> 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 <T> HtmlTree UL(HtmlStyle style, Collection<T> items, Function<T,Content> 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 <a href="https://www.w3.org/TR/html51/dom.html#kinds-of-content-phrasing-content">Phrasing Content</a>
*/
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 <a href="https://www.w3.org/TR/html51/syntax.html#void-elements">Void Elements</a>
*/
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

View File

@ -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 <T> Content addAll(Collection<T> items, Function<T, Content> mapper) {
items.forEach(item -> add(mapper.apply(item)));
return this;
}
/**
* Writes content to a writer.
*