HtmlTag.java revision 3896:8e4dbcb99277
1/* 2 * Copyright (c) 2010, 2016, 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 attrs(AttrKind.ALL, SRC)), 292 293 SECTION(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 294 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 295 296 SMALL(BlockType.INLINE, EndKind.REQUIRED, 297 EnumSet.of(Flag.EXPECT_CONTENT)), 298 299 SPAN(BlockType.INLINE, EndKind.REQUIRED, 300 EnumSet.of(Flag.EXPECT_CONTENT)), 301 302 STRIKE(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 303 EnumSet.of(Flag.EXPECT_CONTENT)), 304 305 STRONG(BlockType.INLINE, EndKind.REQUIRED, 306 EnumSet.of(Flag.EXPECT_CONTENT)), 307 308 SUB(BlockType.INLINE, EndKind.REQUIRED, 309 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 310 311 SUP(BlockType.INLINE, EndKind.REQUIRED, 312 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 313 314 TABLE(BlockType.BLOCK, EndKind.REQUIRED, 315 EnumSet.of(Flag.EXPECT_CONTENT), 316 attrs(AttrKind.ALL, BORDER), 317 attrs(AttrKind.HTML4, SUMMARY, CELLPADDING, CELLSPACING, Attr.FRAME, RULES, WIDTH), 318 attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) { 319 @Override 320 public boolean accepts(HtmlTag t) { 321 switch (t) { 322 case CAPTION: 323 case COLGROUP: 324 case THEAD: case TBODY: case TFOOT: 325 case TR: // HTML 3.2 326 return true; 327 default: 328 return false; 329 } 330 } 331 }, 332 333 TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED, 334 EnumSet.of(Flag.EXPECT_CONTENT), 335 attrs(AttrKind.ALL, VALIGN), 336 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 337 @Override 338 public boolean accepts(HtmlTag t) { 339 return (t == TR); 340 } 341 }, 342 343 TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 344 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 345 attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, VALIGN), 346 attrs(AttrKind.HTML4, AXIS, Attr.ABBR, SCOPE, ALIGN, CHAR, CHAROFF), 347 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), 348 349 TEMPLATE(HtmlVersion.HTML5, BlockType.BLOCK, EndKind.REQUIRED, 350 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), 351 352 TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED, 353 attrs(AttrKind.ALL, VALIGN), 354 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 355 @Override 356 public boolean accepts(HtmlTag t) { 357 return (t == TR); 358 } 359 }, 360 361 TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 362 EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), 363 attrs(AttrKind.ALL, COLSPAN, ROWSPAN, HEADERS, SCOPE, Attr.ABBR, 364 VALIGN), 365 attrs(AttrKind.HTML4, AXIS, ALIGN, CHAR, CHAROFF), 366 attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), 367 368 THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED, 369 attrs(AttrKind.ALL, VALIGN), 370 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF)) { 371 @Override 372 public boolean accepts(HtmlTag t) { 373 return (t == TR); 374 } 375 }, 376 377 TIME(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 378 379 TITLE(BlockType.OTHER, EndKind.REQUIRED), 380 381 TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL, 382 attrs(AttrKind.ALL, VALIGN), 383 attrs(AttrKind.HTML4, ALIGN, CHAR, CHAROFF), 384 attrs(AttrKind.USE_CSS, BGCOLOR)) { 385 @Override 386 public boolean accepts(HtmlTag t) { 387 return (t == TH) || (t == TD); 388 } 389 }, 390 391 TT(HtmlVersion.HTML4, BlockType.INLINE, EndKind.REQUIRED, 392 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 393 394 U(BlockType.INLINE, EndKind.REQUIRED, 395 EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), 396 397 UL(BlockType.BLOCK, EndKind.REQUIRED, 398 EnumSet.of(Flag.EXPECT_CONTENT), 399 attrs(AttrKind.HTML4, COMPACT, TYPE)) { 400 @Override 401 public boolean accepts(HtmlTag t) { 402 return (t == LI); 403 } 404 }, 405 406 WBR(HtmlVersion.HTML5, BlockType.INLINE, EndKind.REQUIRED), 407 408 VAR(BlockType.INLINE, EndKind.REQUIRED); 409 410 /** 411 * Enum representing the type of HTML element. 412 */ 413 public static enum BlockType { 414 BLOCK, 415 INLINE, 416 LIST_ITEM, 417 TABLE_ITEM, 418 OTHER 419 } 420 421 /** 422 * Enum representing HTML end tag requirement. 423 */ 424 public static enum EndKind { 425 NONE, 426 OPTIONAL, 427 REQUIRED 428 } 429 430 public static enum Flag { 431 ACCEPTS_BLOCK, 432 ACCEPTS_INLINE, 433 EXPECT_CONTENT, 434 NO_NEST 435 } 436 437 public static enum Attr { 438 ABBR, 439 ALIGN, 440 ALINK, 441 ALT, 442 ARIA_ACTIVEDESCENDANT, 443 ARIA_CONTROLS, 444 ARIA_DESCRIBEDBY, 445 ARIA_EXPANDED, 446 ARIA_LABEL, 447 ARIA_LABELLEDBY, 448 ARIA_LEVEL, 449 ARIA_MULTISELECTABLE, 450 ARIA_OWNS, 451 ARIA_POSINSET, 452 ARIA_SETSIZE, 453 ARIA_READONLY, 454 ARIA_REQUIRED, 455 ARIA_SELECTED, 456 ARIA_SORT, 457 AXIS, 458 BACKGROUND, 459 BGCOLOR, 460 BORDER, 461 CELLSPACING, 462 CELLPADDING, 463 CHAR, 464 CHAROFF, 465 CHARSET, 466 CITE, 467 CLEAR, 468 CLASS, 469 COLOR, 470 COLSPAN, 471 COMPACT, 472 COORDS, 473 CROSSORIGIN, 474 DATETIME, 475 FACE, 476 FRAME, 477 FRAMEBORDER, 478 HEADERS, 479 HEIGHT, 480 HREF, 481 HSPACE, 482 ID, 483 LINK, 484 LONGDESC, 485 MARGINHEIGHT, 486 MARGINWIDTH, 487 NAME, 488 NOSHADE, 489 NOWRAP, 490 PROFILE, 491 REV, 492 REVERSED, 493 ROLE, 494 ROWSPAN, 495 RULES, 496 SCHEME, 497 SCOPE, 498 SCROLLING, 499 SHAPE, 500 SIZE, 501 SPACE, 502 SRC, 503 START, 504 STYLE, 505 SUMMARY, 506 TARGET, 507 TEXT, 508 TYPE, 509 VALIGN, 510 VALUE, 511 VERSION, 512 VLINK, 513 VSPACE, 514 WIDTH; 515 516 private final String name; 517 518 Attr() { 519 name = StringUtils.toLowerCase(name().replace("_", "-")); 520 } 521 522 public String getText() { 523 return name; 524 } 525 526 static final Map<String,Attr> index = new HashMap<>(); 527 static { 528 for (Attr t: values()) { 529 index.put(t.getText(), t); 530 } 531 } 532 } 533 534 public static enum AttrKind { 535 HTML4, 536 HTML5, 537 INVALID, 538 OBSOLETE, 539 USE_CSS, 540 ALL 541 } 542 543 // This class exists to avoid warnings from using parameterized vararg type 544 // Map<Attr,AttrKind> in signature of HtmlTag constructor. 545 private static class AttrMap extends EnumMap<Attr,AttrKind> { 546 private static final long serialVersionUID = 0; 547 AttrMap() { 548 super(Attr.class); 549 } 550 } 551 552 553 public final HtmlVersion allowedVersion; 554 public final BlockType blockType; 555 public final EndKind endKind; 556 public final Set<Flag> flags; 557 private final Map<Attr,AttrKind> attrs; 558 559 HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) { 560 this(HtmlVersion.ALL, blockType, endKind, Collections.emptySet(), attrMaps); 561 } 562 563 HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, AttrMap... attrMaps) { 564 this(allowedVersion, blockType, endKind, Collections.emptySet(), attrMaps); 565 } 566 567 HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { 568 this(HtmlVersion.ALL, blockType, endKind, flags, attrMaps); 569 } 570 571 HtmlTag(HtmlVersion allowedVersion, BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { 572 this.allowedVersion = allowedVersion; 573 this.blockType = blockType; 574 this.endKind = endKind; 575 this.flags = flags; 576 this.attrs = new EnumMap<>(Attr.class); 577 for (Map<Attr,AttrKind> m: attrMaps) 578 this.attrs.putAll(m); 579 attrs.put(Attr.CLASS, AttrKind.ALL); 580 attrs.put(Attr.ID, AttrKind.ALL); 581 attrs.put(Attr.STYLE, AttrKind.ALL); 582 attrs.put(Attr.ROLE, AttrKind.HTML5); 583 // for now, assume that all ARIA attributes are allowed on all tags. 584 attrs.put(Attr.ARIA_ACTIVEDESCENDANT, AttrKind.HTML5); 585 attrs.put(Attr.ARIA_CONTROLS, AttrKind.HTML5); 586 attrs.put(Attr.ARIA_DESCRIBEDBY, AttrKind.HTML5); 587 attrs.put(Attr.ARIA_EXPANDED, AttrKind.HTML5); 588 attrs.put(Attr.ARIA_LABEL, AttrKind.HTML5); 589 attrs.put(Attr.ARIA_LABELLEDBY, AttrKind.HTML5); 590 attrs.put(Attr.ARIA_LEVEL, AttrKind.HTML5); 591 attrs.put(Attr.ARIA_MULTISELECTABLE, AttrKind.HTML5); 592 attrs.put(Attr.ARIA_OWNS, AttrKind.HTML5); 593 attrs.put(Attr.ARIA_POSINSET, AttrKind.HTML5); 594 attrs.put(Attr.ARIA_READONLY, AttrKind.HTML5); 595 attrs.put(Attr.ARIA_REQUIRED, AttrKind.HTML5); 596 attrs.put(Attr.ARIA_SELECTED, AttrKind.HTML5); 597 attrs.put(Attr.ARIA_SETSIZE, AttrKind.HTML5); 598 attrs.put(Attr.ARIA_SORT, AttrKind.HTML5); 599 } 600 601 public boolean accepts(HtmlTag t) { 602 if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) { 603 return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); 604 } else if (flags.contains(Flag.ACCEPTS_BLOCK)) { 605 return (t.blockType == BlockType.BLOCK); 606 } else if (flags.contains(Flag.ACCEPTS_INLINE)) { 607 return (t.blockType == BlockType.INLINE); 608 } else 609 switch (blockType) { 610 case BLOCK: 611 case INLINE: 612 return (t.blockType == BlockType.INLINE); 613 case OTHER: 614 // OTHER tags are invalid in doc comments, and will be 615 // reported separately, so silently accept/ignore any content 616 return true; 617 default: 618 // any combination which could otherwise arrive here 619 // ought to have been handled in an overriding method 620 throw new AssertionError(this + ":" + t); 621 } 622 } 623 624 public boolean acceptsText() { 625 // generally, anywhere we can put text we can also put inline tag 626 // so check if a typical inline tag is allowed 627 return accepts(B); 628 } 629 630 public String getText() { 631 return StringUtils.toLowerCase(name()); 632 } 633 634 public Attr getAttr(Name attrName) { 635 return Attr.index.get(StringUtils.toLowerCase(attrName.toString())); 636 } 637 638 public AttrKind getAttrKind(Name attrName) { 639 AttrKind k = attrs.get(getAttr(attrName)); // null-safe 640 return (k == null) ? AttrKind.INVALID : k; 641 } 642 643 private static AttrMap attrs(AttrKind k, Attr... attrs) { 644 AttrMap map = new AttrMap(); 645 for (Attr a: attrs) map.put(a, k); 646 return map; 647 } 648 649 private static final Map<String, HtmlTag> index = new HashMap<>(); 650 static { 651 for (HtmlTag t: values()) { 652 index.put(t.getText(), t); 653 } 654 } 655 656 public static HtmlTag get(Name tagName) { 657 return index.get(StringUtils.toLowerCase(tagName.toString())); 658 } 659} 660