HtmlTag.java revision 3828:d30434bde0a8
1/* 2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.doclint; 27 28import java.util.Collections; 29import java.util.EnumMap; 30import java.util.EnumSet; 31import java.util.HashMap; 32import java.util.Map; 33import java.util.Set; 34import javax.lang.model.element.Name; 35 36import com.sun.tools.javac.util.StringUtils; 37 38import static com.sun.tools.doclint.HtmlTag.Attr.*; 39 40/** 41 * Enum representing HTML tags. 42 * 43 * The intent of this class is to embody the semantics of W3C HTML 4.01 44 * to the extent supported/used by javadoc. 45 * In time, we may wish to transition javadoc and doclint to using HTML 5. 46 * 47 * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag. 48 * Eventually, these two should be merged back together, and possibly made 49 * public. 50 * 51 * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a> 52 * @see <a href="http://www.w3.org/TR/html5/">HTML 5 Specification</a> 53 * @see <a href="http://www.w3.org/TR/wai-aria/ ">WAI-ARIA Specification</a> 54 * @see <a href="http://www.w3.org/TR/aria-in-html/#recommendations-table">WAI-ARIA Recommendations Table</a> 55 * @author Bhavesh Patel 56 * @author Jonathan Gibbons (revised) 57 */ 58public enum HtmlTag { 59 A(BlockType.INLINE, EndKind.REQUIRED, 60 attrs(AttrKind.ALL, HREF, TARGET, ID), 61 attrs(AttrKind.HTML4, REV, CHARSET, SHAPE, COORDS, NAME)), 62 63 ABBR(BlockType.INLINE, EndKind.REQUIRED, 64 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 65 66 ACRONYM(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 67 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 68 69 ADDRESS(BlockType.INLINE, EndKind.REQUIRED, 70 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 71 72 ARTICLE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 73 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 74 75 ASIDE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 76 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 77 78 B(BlockType.INLINE, EndKind.REQUIRED, 79 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 80 81 BDI(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 82 83 BIG(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 84 EnumSet.of(Flag.EXPECT_CONTENT)), 85 86 BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED, 87 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 88 89 BODY(BlockType.OTHER, EndKind.REQUIRED), 90 91 BR(BlockType.INLINE, EndKind.NONE, 92 attrs(AttrKind.USE_CSS, CLEAR)), 93 94 CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED, 95 EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT), 96 attrs(AttrKind.USE_CSS, ALIGN)), 97 98 CENTER(HtmlVersion.HTML4, BlockType.BLOCK, EndKind.REQUIRED, 99 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 100 101 CITE(BlockType.INLINE, EndKind.REQUIRED, 102 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 103 104 CODE(BlockType.INLINE, EndKind.REQUIRED, 105 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 106 107 COL(BlockType.TABLE_ITEM, EndKind.NONE, 108 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF, VALIGN, WIDTH)), 109 110 COLGROUP(BlockType.TABLE_ITEM, EndKind.REQUIRED, 111 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF, VALIGN, WIDTH)) { 112 @Override 113 public boolean accepts(HtmlTag t) { 114 return (t == COL); 115 } 116 }, 117 118 DD(BlockType.LIST_ITEM, EndKind.OPTIONAL, 119 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), 120 121 DEL(BlockType.INLINE, EndKind.REQUIRED, 122 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), 123 attrs(AttrKind.ALL, Attr.CITE, Attr.DATETIME)), 124 125 DFN(BlockType.INLINE, EndKind.REQUIRED, 126 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 127 128 DIV(BlockType.BLOCK, EndKind.REQUIRED, 129 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 130 attrs(AttrKind.USE_CSS, ALIGN)), 131 132 DL(BlockType.BLOCK, EndKind.REQUIRED, 133 EnumSet.of(Flag.EXPECT_CONTENT), 134 attrs(AttrKind.USE_CSS, COMPACT)) { 135 @Override 136 public boolean accepts(HtmlTag t) { 137 return (t == DT) || (t == DD); 138 } 139 }, 140 141 DT(BlockType.LIST_ITEM, EndKind.OPTIONAL, 142 EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), 143 144 EM(BlockType.INLINE, EndKind.REQUIRED, 145 EnumSet.of(Flag.NO_NEST)), 146 147 FONT(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated 148 EnumSet.of(Flag.EXPECT_CONTENT), 149 attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)), 150 151 FOOTER(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 152 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { 153 @Override 154 public boolean accepts(HtmlTag t) { 155 switch (t) { 156 case HEADER: case FOOTER: case MAIN: 157 return false; 158 default: 159 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); 160 } 161 } 162 }, 163 164 FIGURE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 165 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 166 167 FIGCAPTION(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED), 168 169 FRAME(HtmlVersion.HTML4, BlockType.OTHER, EndKind.NONE), 170 171 FRAMESET(HtmlVersion.HTML4, BlockType.OTHER, EndKind.REQUIRED), 172 173 H1(BlockType.BLOCK, EndKind.REQUIRED, 174 attrs(AttrKind.USE_CSS, ALIGN)), 175 H2(BlockType.BLOCK, EndKind.REQUIRED, 176 attrs(AttrKind.USE_CSS, ALIGN)), 177 H3(BlockType.BLOCK, EndKind.REQUIRED, 178 attrs(AttrKind.USE_CSS, ALIGN)), 179 H4(BlockType.BLOCK, EndKind.REQUIRED, 180 attrs(AttrKind.USE_CSS, ALIGN)), 181 H5(BlockType.BLOCK, EndKind.REQUIRED, 182 attrs(AttrKind.USE_CSS, ALIGN)), 183 H6(BlockType.BLOCK, EndKind.REQUIRED, 184 attrs(AttrKind.USE_CSS, ALIGN)), 185 186 HEAD(BlockType.OTHER, EndKind.REQUIRED), 187 188 HEADER(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 189 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { 190 @Override 191 public boolean accepts(HtmlTag t) { 192 switch (t) { 193 case HEADER: case FOOTER: case MAIN: 194 return false; 195 default: 196 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); 197 } 198 } 199 }, 200 201 HR(BlockType.BLOCK, EndKind.NONE, 202 attrs(AttrKind.HTML4, WIDTH), 203 attrs(AttrKind.USE_CSS, ALIGN, NOSHADE, SIZE)), 204 205 HTML(BlockType.OTHER, EndKind.REQUIRED), 206 207 I(BlockType.INLINE, EndKind.REQUIRED, 208 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 209 210 IFRAME(BlockType.OTHER, EndKind.REQUIRED), 211 212 IMG(BlockType.INLINE, EndKind.NONE, 213 attrs(AttrKind.ALL, SRC, ALT, HEIGHT, WIDTH), 214 attrs(AttrKind.HTML5, CROSSORIGIN), 215 attrs(AttrKind.OBSOLETE, NAME), 216 attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)), 217 218 INS(BlockType.INLINE, EndKind.REQUIRED, 219 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), 220 attrs(AttrKind.ALL, Attr.CITE, Attr.DATETIME)), 221 222 KBD(BlockType.INLINE, EndKind.REQUIRED, 223 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 224 225 LI(BlockType.LIST_ITEM, EndKind.OPTIONAL, 226 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 227 attrs(AttrKind.ALL, VALUE), 228 attrs(AttrKind.USE_CSS, TYPE)), 229 230 LINK(BlockType.OTHER, EndKind.NONE), 231 232 MAIN(HtmlVersion.HTML5, BlockType.OTHER, EndKind.REQUIRED), 233 234 MARK(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 235 236 MENU(BlockType.BLOCK, EndKind.REQUIRED) { 237 @Override 238 public boolean accepts(HtmlTag t) { 239 return (t == LI); 240 } 241 }, 242 243 META(BlockType.OTHER, EndKind.NONE), 244 245 NAV(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 246 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 247 248 NOFRAMES(HtmlVersion.HTML4, BlockType.OTHER, EndKind.REQUIRED), 249 250 NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED), 251 252 OL(BlockType.BLOCK, EndKind.REQUIRED, 253 EnumSet.of(Flag.EXPECT_CONTENT), 254 attrs(AttrKind.ALL, START, TYPE), 255 attrs(AttrKind.HTML5, REVERSED), 256 attrs(AttrKind.USE_CSS, COMPACT)) { 257 @Override 258 public boolean accepts(HtmlTag t) { 259 return (t == LI); 260 } 261 }, 262 263 P(BlockType.BLOCK, EndKind.OPTIONAL, 264 EnumSet.of(Flag.EXPECT_CONTENT), 265 attrs(AttrKind.USE_CSS, ALIGN)), 266 267 PRE(BlockType.BLOCK, EndKind.REQUIRED, 268 EnumSet.of(Flag.EXPECT_CONTENT), 269 attrs(AttrKind.USE_CSS, WIDTH)) { 270 @Override 271 public boolean accepts(HtmlTag t) { 272 switch (t) { 273 case IMG: case BIG: case SMALL: case SUB: case SUP: 274 return false; 275 default: 276 return (t.blockType == BlockType.INLINE); 277 } 278 } 279 }, 280 281 Q(BlockType.INLINE, EndKind.REQUIRED, 282 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 283 284 S(BlockType.INLINE, EndKind.REQUIRED, 285 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 286 287 SAMP(BlockType.INLINE, EndKind.REQUIRED, 288 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 289 290 SCRIPT(BlockType.OTHER, EndKind.REQUIRED), 291 292 SECTION(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 293 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 294 295 SMALL(BlockType.INLINE, EndKind.REQUIRED, 296 EnumSet.of(Flag.EXPECT_CONTENT)), 297 298 SPAN(BlockType.INLINE, EndKind.REQUIRED, 299 EnumSet.of(Flag.EXPECT_CONTENT)), 300 301 STRIKE(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 302 EnumSet.of(Flag.EXPECT_CONTENT)), 303 304 STRONG(BlockType.INLINE, EndKind.REQUIRED, 305 EnumSet.of(Flag.EXPECT_CONTENT)), 306 307 SUB(BlockType.INLINE, EndKind.REQUIRED, 308 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 309 310 SUP(BlockType.INLINE, EndKind.REQUIRED, 311 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 312 313 TABLE(BlockType.BLOCK, EndKind.REQUIRED, 314 EnumSet.of(Flag.EXPECT_CONTENT), 315 attrs(AttrKind.ALL, BORDER), 316 attrs(AttrKind.HTML4, SUMMARY, CELLPADDING, CELLSPACING, Attr.FRAME, RULES, WIDTH), 317 attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) { 318 @Override 319 public boolean accepts(HtmlTag t) { 320 switch (t) { 321 case CAPTION: 322 case COLGROUP: 323 case THEAD: case TBODY: case TFOOT: 324 case TR: // HTML 3.2 325 return true; 326 default: 327 return false; 328 } 329 } 330 }, 331 332 TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED, 333 EnumSet.of(Flag.EXPECT_CONTENT), 334 attrs(AttrKind.ALL, VALIGN), 335 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 336 @Override 337 public boolean accepts(HtmlTag t) { 338 return (t == TR); 339 } 340 }, 341 342 TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 343 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 344 attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, VALIGN), 345 attrs(AttrKind.HTML4, AXIS, Attr.ABBR, SCOPE, ALIGN, CHAR, CHAROFF), 346 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), 347 348 TEMPLATE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 349 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 350 351 TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED, 352 attrs(AttrKind.ALL, VALIGN), 353 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 354 @Override 355 public boolean accepts(HtmlTag t) { 356 return (t == TR); 357 } 358 }, 359 360 TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 361 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 362 attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, SCOPE, Attr.ABBR, 363 VALIGN), 364 attrs(AttrKind.HTML4, AXIS, ALIGN, CHAR, CHAROFF), 365 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), 366 367 THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED, 368 attrs(AttrKind.ALL, VALIGN), 369 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 370 @Override 371 public boolean accepts(HtmlTag t) { 372 return (t == TR); 373 } 374 }, 375 376 TIME(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 377 378 TITLE(BlockType.OTHER, EndKind.REQUIRED), 379 380 TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 381 attrs(AttrKind.ALL, VALIGN), 382 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF), 383 attrs(AttrKind.USE_CSS, BGCOLOR)) { 384 @Override 385 public boolean accepts(HtmlTag t) { 386 return (t == TH) || (t == TD); 387 } 388 }, 389 390 TT(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 391 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 392 393 U(BlockType.INLINE, EndKind.REQUIRED, 394 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 395 396 UL(BlockType.BLOCK, EndKind.REQUIRED, 397 EnumSet.of(Flag.EXPECT_CONTENT), 398 attrs(AttrKind.HTML4, COMPACT, TYPE)) { 399 @Override 400 public boolean accepts(HtmlTag t) { 401 return (t == LI); 402 } 403 }, 404 405 WBR(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 406 407 VAR(BlockType.INLINE, EndKind.REQUIRED); 408 409 /** 410 * Enum representing the type of HTML element. 411 */ 412 public static enum BlockType { 413 BLOCK, 414 INLINE, 415 LIST_ITEM, 416 TABLE_ITEM, 417 OTHER 418 } 419 420 /** 421 * Enum representing HTML end tag requirement. 422 */ 423 public static enum EndKind { 424 NONE, 425 OPTIONAL, 426 REQUIRED 427 } 428 429 public static enum Flag { 430 ACCEPTS_BLOCK, 431 ACCEPTS_INLINE, 432 EXPECT_CONTENT, 433 NO_NEST 434 } 435 436 public static enum Attr { 437 ABBR, 438 ALIGN, 439 ALINK, 440 ALT, 441 ARIA_ACTIVEDESCENDANT, 442 ARIA_CONTROLS, 443 ARIA_DESCRIBEDBY, 444 ARIA_EXPANDED, 445 ARIA_LABEL, 446 ARIA_LABELLEDBY, 447 ARIA_LEVEL, 448 ARIA_MULTISELECTABLE, 449 ARIA_OWNS, 450 ARIA_POSINSET, 451 ARIA_SETSIZE, 452 ARIA_READONLY, 453 ARIA_REQUIRED, 454 ARIA_SELECTED, 455 ARIA_SORT, 456 AXIS, 457 BACKGROUND, 458 BGCOLOR, 459 BORDER, 460 CELLSPACING, 461 CELLPADDING, 462 CHAR, 463 CHAROFF, 464 CHARSET, 465 CITE, 466 CLEAR, 467 CLASS, 468 COLOR, 469 COLSPAN, 470 COMPACT, 471 COORDS, 472 CROSSORIGIN, 473 DATETIME, 474 FACE, 475 FRAME, 476 FRAMEBORDER, 477 HEADERS, 478 HEIGHT, 479 HREF, 480 HSPACE, 481 ID, 482 LINK, 483 LONGDESC, 484 MARGINHEIGHT, 485 MARGINWIDTH, 486 NAME, 487 NOSHADE, 488 NOWRAP, 489 PROFILE, 490 REV, 491 REVERSED, 492 ROLE, 493 ROWSPAN, 494 RULES, 495 SCHEME, 496 SCOPE, 497 SCROLLING, 498 SHAPE, 499 SIZE, 500 SPACE, 501 SRC, 502 START, 503 STYLE, 504 SUMMARY, 505 TARGET, 506 TEXT, 507 TYPE, 508 VALIGN, 509 VALUE, 510 VERSION, 511 VLINK, 512 VSPACE, 513 WIDTH; 514 515 private final String name; 516 517 Attr() { 518 name = StringUtils.toLowerCase(name().replace("_", "-")); 519 } 520 521 public String getText() { 522 return name; 523 } 524 525 static final Map<String,Attr> index = new HashMap<>(); 526 static { 527 for (Attr t: values()) { 528 index.put(t.getText(), t); 529 } 530 } 531 } 532 533 public static enum AttrKind { 534 HTML4, 535 HTML5, 536 INVALID, 537 OBSOLETE, 538 USE_CSS, 539 ALL 540 } 541 542 // This class exists to avoid warnings from using parameterized vararg type 543 // Map<Attr,AttrKind> in signature of HtmlTag constructor. 544 private static class AttrMap extends EnumMap<Attr,AttrKind> { 545 private static final long serialVersionUID = 0; 546 AttrMap() { 547 super(Attr.class); 548 } 549 } 550 551 552 public final HtmlVersion allowedVersion; 553 public final BlockType blockType; 554 public final EndKind endKind; 555 public final Set<Flag> flags; 556 private final Map<Attr,AttrKind> attrs; 557 558 HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) { 559 this(HtmlVersion.ALL, blockType, endKind, Collections.emptySet(), attrMaps); 560 } 561 562 HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, AttrMap... attrMaps) { 563 this(allowedVersion, blockType, endKind, Collections.emptySet(), attrMaps); 564 } 565 566 HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { 567 this(HtmlVersion.ALL, blockType, endKind, flags, attrMaps); 568 } 569 570 HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { 571 this.allowedVersion = allowedVersion; 572 this.blockType = blockType; 573 this.endKind = endKind; 574 this.flags = flags; 575 this.attrs = new EnumMap<>(Attr.class); 576 for (Map<Attr,AttrKind> m: attrMaps) 577 this.attrs.putAll(m); 578 attrs.put(Attr.CLASS, AttrKind.ALL); 579 attrs.put(Attr.ID, AttrKind.ALL); 580 attrs.put(Attr.STYLE, AttrKind.ALL); 581 attrs.put(Attr.ROLE, AttrKind.HTML5); 582 // for now, assume that all ARIA attributes are allowed on all tags. 583 attrs.put(Attr.ARIA_ACTIVEDESCENDANT, AttrKind.HTML5); 584 attrs.put(Attr.ARIA_CONTROLS, AttrKind.HTML5); 585 attrs.put(Attr.ARIA_DESCRIBEDBY, AttrKind.HTML5); 586 attrs.put(Attr.ARIA_EXPANDED, AttrKind.HTML5); 587 attrs.put(Attr.ARIA_LABEL, AttrKind.HTML5); 588 attrs.put(Attr.ARIA_LABELLEDBY, AttrKind.HTML5); 589 attrs.put(Attr.ARIA_LEVEL, AttrKind.HTML5); 590 attrs.put(Attr.ARIA_MULTISELECTABLE, AttrKind.HTML5); 591 attrs.put(Attr.ARIA_OWNS, AttrKind.HTML5); 592 attrs.put(Attr.ARIA_POSINSET, AttrKind.HTML5); 593 attrs.put(Attr.ARIA_READONLY, AttrKind.HTML5); 594 attrs.put(Attr.ARIA_REQUIRED, AttrKind.HTML5); 595 attrs.put(Attr.ARIA_SELECTED, AttrKind.HTML5); 596 attrs.put(Attr.ARIA_SETSIZE, AttrKind.HTML5); 597 attrs.put(Attr.ARIA_SORT, AttrKind.HTML5); 598 } 599 600 public boolean accepts(HtmlTag t) { 601 if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) { 602 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); 603 } else if (flags.contains(Flag.ACCEPTS_BLOCK)) { 604 return (t.blockType == BlockType.BLOCK); 605 } else if (flags.contains(Flag.ACCEPTS_INLINE)) { 606 return (t.blockType == BlockType.INLINE); 607 } else 608 switch (blockType) { 609 case BLOCK: 610 case INLINE: 611 return (t.blockType == BlockType.INLINE); 612 case OTHER: 613 // OTHER tags are invalid in doc comments, and will be 614 // reported separately, so silently accept/ignore any content 615 return true; 616 default: 617 // any combination which could otherwise arrive here 618 // ought to have been handled in an overriding method 619 throw new AssertionError(this + ":" + t); 620 } 621 } 622 623 public boolean acceptsText() { 624 // generally, anywhere we can put text we can also put inline tag 625 // so check if a typical inline tag is allowed 626 return accepts(B); 627 } 628 629 public String getText() { 630 return StringUtils.toLowerCase(name()); 631 } 632 633 public Attr getAttr(Name attrName) { 634 return Attr.index.get(StringUtils.toLowerCase(attrName.toString())); 635 } 636 637 public AttrKind getAttrKind(Name attrName) { 638 AttrKind k = attrs.get(getAttr(attrName)); // null-safe 639 return (k == null) ? AttrKind.INVALID : k; 640 } 641 642 private static AttrMap attrs(AttrKind k, Attr... attrs) { 643 AttrMap map = new AttrMap(); 644 for (Attr a: attrs) map.put(a, k); 645 return map; 646 } 647 648 private static final Map<String, HtmlTag> index = new HashMap<>(); 649 static { 650 for (HtmlTag t: values()) { 651 index.put(t.getText(), t); 652 } 653 } 654 655 public static HtmlTag get(Name tagName) { 656 return index.get(StringUtils.toLowerCase(tagName.toString())); 657 } 658} 659