| /* |
| * Copyright (c) 2010, 2016, 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 com.sun.tools.doclint; |
| |
| import java.util.Collections; |
| import java.util.EnumMap; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| import javax.lang.model.element.Name; |
| |
| import com.sun.tools.javac.util.StringUtils; |
| |
| import static com.sun.tools.doclint.HtmlTag.Attr.*; |
| |
| /** |
| * Enum representing HTML tags. |
| * |
| * The intent of this class is to embody the semantics of W3C HTML 4.01 |
| * to the extent supported/used by javadoc. |
| * In time, we may wish to transition javadoc and doclint to using HTML 5. |
| * |
| * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag. |
| * Eventually, these two should be merged back together, and possibly made |
| * public. |
| * |
| * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a> |
| * @see <a href="http://www.w3.org/TR/html5/">HTML 5 Specification</a> |
| * @see <a href="http://www.w3.org/TR/wai-aria/ ">WAI-ARIA Specification</a> |
| * @see <a href="http://www.w3.org/TR/aria-in-html/#recommendations-table">WAI-ARIA Recommendations Table</a> |
| * @author Bhavesh Patel |
| * @author Jonathan Gibbons (revised) |
| */ |
| public enum HtmlTag { |
| A(BlockType.INLINE, EndKind.REQUIRED, |
| attrs(AttrKind.ALL, HREF, TARGET, ID), |
| attrs(AttrKind.HTML4, REV, CHARSET, SHAPE, COORDS, NAME)), |
| |
| ABBR(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| ACRONYM(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| ADDRESS(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| ARTICLE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| ASIDE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| B(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| BDI(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), |
| |
| BIG(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT)), |
| |
| BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| BODY(BlockType.OTHER, EndKind.REQUIRED), |
| |
| BR(BlockType.INLINE, EndKind.NONE, |
| attrs(AttrKind.USE_CSS, CLEAR)), |
| |
| CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT), |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| |
| CENTER(HtmlVersion.HTML4, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| CITE(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| CODE(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| COL(BlockType.TABLE_ITEM, EndKind.NONE, |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF, VALIGN, WIDTH)), |
| |
| COLGROUP(BlockType.TABLE_ITEM, EndKind.REQUIRED, |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF, VALIGN, WIDTH)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == COL); |
| } |
| }, |
| |
| DD(BlockType.LIST_ITEM, EndKind.OPTIONAL, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), |
| |
| DEL(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), |
| attrs(AttrKind.ALL, Attr.CITE, Attr.DATETIME)), |
| |
| DFN(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| DIV(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| |
| DL(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.USE_CSS, COMPACT)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == DT) || (t == DD); |
| } |
| }, |
| |
| DT(BlockType.LIST_ITEM, EndKind.OPTIONAL, |
| EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), |
| |
| EM(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.NO_NEST)), |
| |
| FONT(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)), |
| |
| FOOTER(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| switch (t) { |
| case HEADER: case FOOTER: case MAIN: |
| return false; |
| default: |
| return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); |
| } |
| } |
| }, |
| |
| FIGURE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| FIGCAPTION(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED), |
| |
| FRAME(HtmlVersion.HTML4, BlockType.OTHER, EndKind.NONE), |
| |
| FRAMESET(HtmlVersion.HTML4, BlockType.OTHER, EndKind.REQUIRED), |
| |
| H1(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| H2(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| H3(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| H4(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| H5(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| H6(BlockType.BLOCK, EndKind.REQUIRED, |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| |
| HEAD(BlockType.OTHER, EndKind.REQUIRED), |
| |
| HEADER(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| switch (t) { |
| case HEADER: case FOOTER: case MAIN: |
| return false; |
| default: |
| return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); |
| } |
| } |
| }, |
| |
| HR(BlockType.BLOCK, EndKind.NONE, |
| attrs(AttrKind.HTML4, WIDTH), |
| attrs(AttrKind.USE_CSS, ALIGN, NOSHADE, SIZE)), |
| |
| HTML(BlockType.OTHER, EndKind.REQUIRED), |
| |
| I(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| IFRAME(BlockType.OTHER, EndKind.REQUIRED), |
| |
| IMG(BlockType.INLINE, EndKind.NONE, |
| attrs(AttrKind.ALL, SRC, ALT, HEIGHT, WIDTH), |
| attrs(AttrKind.HTML5, CROSSORIGIN), |
| attrs(AttrKind.OBSOLETE, NAME), |
| attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)), |
| |
| INS(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), |
| attrs(AttrKind.ALL, Attr.CITE, Attr.DATETIME)), |
| |
| KBD(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| LI(BlockType.LIST_ITEM, EndKind.OPTIONAL, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), |
| attrs(AttrKind.ALL, VALUE), |
| attrs(AttrKind.USE_CSS, TYPE)), |
| |
| LINK(BlockType.OTHER, EndKind.NONE), |
| |
| MAIN(HtmlVersion.HTML5, BlockType.OTHER, EndKind.REQUIRED), |
| |
| MARK(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), |
| |
| MENU(BlockType.BLOCK, EndKind.REQUIRED) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == LI); |
| } |
| }, |
| |
| META(BlockType.OTHER, EndKind.NONE), |
| |
| NAV(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| NOFRAMES(HtmlVersion.HTML4, BlockType.OTHER, EndKind.REQUIRED), |
| |
| NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED), |
| |
| OL(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.ALL, START, TYPE), |
| attrs(AttrKind.HTML5, REVERSED), |
| attrs(AttrKind.USE_CSS, COMPACT)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == LI); |
| } |
| }, |
| |
| P(BlockType.BLOCK, EndKind.OPTIONAL, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.USE_CSS, ALIGN)), |
| |
| PRE(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.USE_CSS, WIDTH)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| switch (t) { |
| case IMG: case BIG: case SMALL: case SUB: case SUP: |
| return false; |
| default: |
| return (t.blockType == BlockType.INLINE); |
| } |
| } |
| }, |
| |
| Q(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| S(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| SAMP(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| SCRIPT(BlockType.OTHER, EndKind.REQUIRED, |
| attrs(AttrKind.ALL, SRC)), |
| |
| SECTION(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| SMALL(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT)), |
| |
| SPAN(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT)), |
| |
| STRIKE(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT)), |
| |
| STRONG(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT)), |
| |
| SUB(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| SUP(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| TABLE(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.ALL, BORDER), |
| attrs(AttrKind.HTML4, SUMMARY, CELLPADDING, CELLSPACING, Attr.FRAME, RULES, WIDTH), |
| attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| switch (t) { |
| case CAPTION: |
| case COLGROUP: |
| case THEAD: case TBODY: case TFOOT: |
| case TR: // HTML 3.2 |
| return true; |
| default: |
| return false; |
| } |
| } |
| }, |
| |
| TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.ALL, VALIGN), |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == TR); |
| } |
| }, |
| |
| TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), |
| attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, VALIGN), |
| attrs(AttrKind.HTML4, AXIS, Attr.ABBR, SCOPE, ALIGN, CHAR, CHAROFF), |
| attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), |
| |
| TEMPLATE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), |
| |
| TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED, |
| attrs(AttrKind.ALL, VALIGN), |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == TR); |
| } |
| }, |
| |
| TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL, |
| EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), |
| attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, SCOPE, Attr.ABBR, |
| VALIGN), |
| attrs(AttrKind.HTML4, AXIS, ALIGN, CHAR, CHAROFF), |
| attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), |
| |
| THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED, |
| attrs(AttrKind.ALL, VALIGN), |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == TR); |
| } |
| }, |
| |
| TIME(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), |
| |
| TITLE(BlockType.OTHER, EndKind.REQUIRED), |
| |
| TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL, |
| attrs(AttrKind.ALL, VALIGN), |
| attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF), |
| attrs(AttrKind.USE_CSS, BGCOLOR)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == TH) || (t == TD); |
| } |
| }, |
| |
| TT(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| U(BlockType.INLINE, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), |
| |
| UL(BlockType.BLOCK, EndKind.REQUIRED, |
| EnumSet.of(Flag.EXPECT_CONTENT), |
| attrs(AttrKind.HTML4, COMPACT, TYPE)) { |
| @Override |
| public boolean accepts(HtmlTag t) { |
| return (t == LI); |
| } |
| }, |
| |
| WBR(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), |
| |
| VAR(BlockType.INLINE, EndKind.REQUIRED); |
| |
| /** |
| * Enum representing the type of HTML element. |
| */ |
| public static enum BlockType { |
| BLOCK, |
| INLINE, |
| LIST_ITEM, |
| TABLE_ITEM, |
| OTHER |
| } |
| |
| /** |
| * Enum representing HTML end tag requirement. |
| */ |
| public static enum EndKind { |
| NONE, |
| OPTIONAL, |
| REQUIRED |
| } |
| |
| public static enum Flag { |
| ACCEPTS_BLOCK, |
| ACCEPTS_INLINE, |
| EXPECT_CONTENT, |
| NO_NEST |
| } |
| |
| public static enum Attr { |
| ABBR, |
| ALIGN, |
| ALINK, |
| ALT, |
| ARIA_ACTIVEDESCENDANT, |
| ARIA_CONTROLS, |
| ARIA_DESCRIBEDBY, |
| ARIA_EXPANDED, |
| ARIA_LABEL, |
| ARIA_LABELLEDBY, |
| ARIA_LEVEL, |
| ARIA_MULTISELECTABLE, |
| ARIA_OWNS, |
| ARIA_POSINSET, |
| ARIA_SETSIZE, |
| ARIA_READONLY, |
| ARIA_REQUIRED, |
| ARIA_SELECTED, |
| ARIA_SORT, |
| AXIS, |
| BACKGROUND, |
| BGCOLOR, |
| BORDER, |
| CELLSPACING, |
| CELLPADDING, |
| CHAR, |
| CHAROFF, |
| CHARSET, |
| CITE, |
| CLEAR, |
| CLASS, |
| COLOR, |
| COLSPAN, |
| COMPACT, |
| COORDS, |
| CROSSORIGIN, |
| DATETIME, |
| FACE, |
| FRAME, |
| FRAMEBORDER, |
| HEADERS, |
| HEIGHT, |
| HREF, |
| HSPACE, |
| ID, |
| LINK, |
| LONGDESC, |
| MARGINHEIGHT, |
| MARGINWIDTH, |
| NAME, |
| NOSHADE, |
| NOWRAP, |
| PROFILE, |
| REV, |
| REVERSED, |
| ROLE, |
| ROWSPAN, |
| RULES, |
| SCHEME, |
| SCOPE, |
| SCROLLING, |
| SHAPE, |
| SIZE, |
| SPACE, |
| SRC, |
| START, |
| STYLE, |
| SUMMARY, |
| TARGET, |
| TEXT, |
| TYPE, |
| VALIGN, |
| VALUE, |
| VERSION, |
| VLINK, |
| VSPACE, |
| WIDTH; |
| |
| private final String name; |
| |
| Attr() { |
| name = StringUtils.toLowerCase(name().replace("_", "-")); |
| } |
| |
| public String getText() { |
| return name; |
| } |
| |
| static final Map<String,Attr> index = new HashMap<>(); |
| static { |
| for (Attr t: values()) { |
| index.put(t.getText(), t); |
| } |
| } |
| } |
| |
| public static enum AttrKind { |
| HTML4, |
| HTML5, |
| INVALID, |
| OBSOLETE, |
| USE_CSS, |
| ALL |
| } |
| |
| // This class exists to avoid warnings from using parameterized vararg type |
| // Map<Attr,AttrKind> in signature of HtmlTag constructor. |
| private static class AttrMap extends EnumMap<Attr,AttrKind> { |
| private static final long serialVersionUID = 0; |
| AttrMap() { |
| super(Attr.class); |
| } |
| } |
| |
| |
| public final HtmlVersion allowedVersion; |
| public final BlockType blockType; |
| public final EndKind endKind; |
| public final Set<Flag> flags; |
| private final Map<Attr,AttrKind> attrs; |
| |
| HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) { |
| this(HtmlVersion.ALL, blockType, endKind, Collections.emptySet(), attrMaps); |
| } |
| |
| HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, AttrMap... attrMaps) { |
| this(allowedVersion, blockType, endKind, Collections.emptySet(), attrMaps); |
| } |
| |
| HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { |
| this(HtmlVersion.ALL, blockType, endKind, flags, attrMaps); |
| } |
| |
| HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { |
| this.allowedVersion = allowedVersion; |
| this.blockType = blockType; |
| this.endKind = endKind; |
| this.flags = flags; |
| this.attrs = new EnumMap<>(Attr.class); |
| for (Map<Attr,AttrKind> m: attrMaps) |
| this.attrs.putAll(m); |
| attrs.put(Attr.CLASS, AttrKind.ALL); |
| attrs.put(Attr.ID, AttrKind.ALL); |
| attrs.put(Attr.STYLE, AttrKind.ALL); |
| attrs.put(Attr.ROLE, AttrKind.HTML5); |
| // for now, assume that all ARIA attributes are allowed on all tags. |
| attrs.put(Attr.ARIA_ACTIVEDESCENDANT, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_CONTROLS, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_DESCRIBEDBY, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_EXPANDED, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_LABEL, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_LABELLEDBY, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_LEVEL, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_MULTISELECTABLE, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_OWNS, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_POSINSET, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_READONLY, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_REQUIRED, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_SELECTED, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_SETSIZE, AttrKind.HTML5); |
| attrs.put(Attr.ARIA_SORT, AttrKind.HTML5); |
| } |
| |
| public boolean accepts(HtmlTag t) { |
| if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) { |
| return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); |
| } else if (flags.contains(Flag.ACCEPTS_BLOCK)) { |
| return (t.blockType == BlockType.BLOCK); |
| } else if (flags.contains(Flag.ACCEPTS_INLINE)) { |
| return (t.blockType == BlockType.INLINE); |
| } else |
| switch (blockType) { |
| case BLOCK: |
| case INLINE: |
| return (t.blockType == BlockType.INLINE); |
| case OTHER: |
| // OTHER tags are invalid in doc comments, and will be |
| // reported separately, so silently accept/ignore any content |
| return true; |
| default: |
| // any combination which could otherwise arrive here |
| // ought to have been handled in an overriding method |
| throw new AssertionError(this + ":" + t); |
| } |
| } |
| |
| public boolean acceptsText() { |
| // generally, anywhere we can put text we can also put inline tag |
| // so check if a typical inline tag is allowed |
| return accepts(B); |
| } |
| |
| public String getText() { |
| return StringUtils.toLowerCase(name()); |
| } |
| |
| public Attr getAttr(Name attrName) { |
| return Attr.index.get(StringUtils.toLowerCase(attrName.toString())); |
| } |
| |
| public AttrKind getAttrKind(Name attrName) { |
| AttrKind k = attrs.get(getAttr(attrName)); // null-safe |
| return (k == null) ? AttrKind.INVALID : k; |
| } |
| |
| private static AttrMap attrs(AttrKind k, Attr... attrs) { |
| AttrMap map = new AttrMap(); |
| for (Attr a: attrs) map.put(a, k); |
| return map; |
| } |
| |
| private static final Map<String, HtmlTag> index = new HashMap<>(); |
| static { |
| for (HtmlTag t: values()) { |
| index.put(t.getText(), t); |
| } |
| } |
| |
| public static HtmlTag get(Name tagName) { |
| return index.get(StringUtils.toLowerCase(tagName.toString())); |
| } |
| } |