src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlTree.java

Tue, 17 Dec 2013 10:55:59 +0100

author
jlahoda
date
Tue, 17 Dec 2013 10:55:59 +0100
changeset 2413
fe033d997ddf
parent 2116
bf6b11347b1a
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029800: Flags.java uses String.toLowerCase without specifying Locale
Summary: Introducing StringUtils.toLowerCase/toUpperCase independent on the default locale, converting almost all usages of String.toLowerCase/toUpperCase to use the new methods.
Reviewed-by: jjg, bpatel

     1 /*
     2  * Copyright (c) 2010, 2013, 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  */
    26 package com.sun.tools.doclets.formats.html.markup;
    28 import java.io.IOException;
    29 import java.io.Writer;
    30 import java.util.*;
    31 import java.nio.charset.*;
    33 import com.sun.tools.doclets.internal.toolkit.Content;
    34 import com.sun.tools.doclets.internal.toolkit.util.*;
    36 /**
    37  * Class for generating HTML tree for javadoc output.
    38  *
    39  *  <p><b>This is NOT part of any supported API.
    40  *  If you write code that depends on this, you do so at your own risk.
    41  *  This code and its internal interfaces are subject to change or
    42  *  deletion without notice.</b>
    43  *
    44  * @author Bhavesh Patel
    45  */
    46 public class HtmlTree extends Content {
    48     private HtmlTag htmlTag;
    49     private Map<HtmlAttr,String> attrs = Collections.<HtmlAttr,String>emptyMap();
    50     private List<Content> content = Collections.<Content>emptyList();
    51     public static final Content EMPTY = new StringContent("");
    53     /**
    54      * Constructor to construct HtmlTree object.
    55      *
    56      * @param tag HTML tag for the HtmlTree object
    57      */
    58     public HtmlTree(HtmlTag tag) {
    59         htmlTag = nullCheck(tag);
    60     }
    62     /**
    63      * Constructor to construct HtmlTree object.
    64      *
    65      * @param tag HTML tag for the HtmlTree object
    66      * @param contents contents to be added to the tree
    67      */
    68     public HtmlTree(HtmlTag tag, Content... contents) {
    69         this(tag);
    70         for (Content content: contents)
    71             addContent(content);
    72     }
    74     /**
    75      * Adds an attribute for the HTML tag.
    76      *
    77      * @param attrName name of the attribute
    78      * @param attrValue value of the attribute
    79      */
    80     public void addAttr(HtmlAttr attrName, String attrValue) {
    81         if (attrs.isEmpty())
    82             attrs = new LinkedHashMap<HtmlAttr,String>(3);
    83         attrs.put(nullCheck(attrName), escapeHtmlChars(attrValue));
    84     }
    86     public void setTitle(Content body) {
    87         addAttr(HtmlAttr.TITLE, stripHtml(body));
    88     }
    90     /**
    91      * Adds a style for the HTML tag.
    92      *
    93      * @param style style to be added
    94      */
    95     public void addStyle(HtmlStyle style) {
    96         addAttr(HtmlAttr.CLASS, style.toString());
    97     }
    99     /**
   100      * Adds content for the HTML tag.
   101      *
   102      * @param tagContent tag content to be added
   103      */
   104     public void addContent(Content tagContent) {
   105         if (tagContent instanceof ContentBuilder) {
   106             for (Content content: ((ContentBuilder)tagContent).contents) {
   107                 addContent(content);
   108             }
   109         }
   110         else if (tagContent == HtmlTree.EMPTY || tagContent.isValid()) {
   111             if (content.isEmpty())
   112                 content = new ArrayList<Content>();
   113             content.add(tagContent);
   114         }
   115     }
   117     /**
   118      * This method adds a string content to the htmltree. If the last content member
   119      * added is a StringContent, append the string to that StringContent or else
   120      * create a new StringContent and add it to the html tree.
   121      *
   122      * @param stringContent string content that needs to be added
   123      */
   124     public void addContent(String stringContent) {
   125         if (!content.isEmpty()) {
   126             Content lastContent = content.get(content.size() - 1);
   127             if (lastContent instanceof StringContent)
   128                 lastContent.addContent(stringContent);
   129             else
   130                 addContent(new StringContent(stringContent));
   131         }
   132         else
   133             addContent(new StringContent(stringContent));
   134     }
   136     public int charCount() {
   137         int n = 0;
   138         for (Content c : content)
   139             n += c.charCount();
   140         return n;
   141     }
   143     /**
   144      * Given a string, escape all special html characters and
   145      * return the result.
   146      *
   147      * @param s The string to check.
   148      * @return the original string with all of the HTML characters escaped.
   149      */
   150     private static String escapeHtmlChars(String s) {
   151         for (int i = 0; i < s.length(); i++) {
   152             char ch = s.charAt(i);
   153             switch (ch) {
   154                 // only start building a new string if we need to
   155                 case '<': case '>': case '&':
   156                     StringBuilder sb = new StringBuilder(s.substring(0, i));
   157                     for ( ; i < s.length(); i++) {
   158                         ch = s.charAt(i);
   159                         switch (ch) {
   160                             case '<': sb.append("&lt;");  break;
   161                             case '>': sb.append("&gt;");  break;
   162                             case '&': sb.append("&amp;"); break;
   163                             default:  sb.append(ch);      break;
   164                         }
   165                     }
   166                     return sb.toString();
   167             }
   168         }
   169         return s;
   170     }
   172     /**
   173      * A set of ASCII URI characters to be left unencoded.
   174      */
   175     public static final BitSet NONENCODING_CHARS = new BitSet(256);
   177     static {
   178         // alphabetic characters
   179         for (int i = 'a'; i <= 'z'; i++) {
   180             NONENCODING_CHARS.set(i);
   181         }
   182         for (int i = 'A'; i <= 'Z'; i++) {
   183             NONENCODING_CHARS.set(i);
   184         }
   185         // numeric characters
   186         for (int i = '0'; i <= '9'; i++) {
   187             NONENCODING_CHARS.set(i);
   188         }
   189         // Reserved characters as per RFC 3986. These are set of delimiting characters.
   190         String noEnc = ":/?#[]@!$&'()*+,;=";
   191         // Unreserved characters as per RFC 3986 which should not be percent encoded.
   192         noEnc += "-._~";
   193         for (int i = 0; i < noEnc.length(); i++) {
   194             NONENCODING_CHARS.set(noEnc.charAt(i));
   195         }
   196     }
   198     private static String encodeURL(String url) {
   199         byte[] urlBytes = url.getBytes(Charset.forName("UTF-8"));
   200         StringBuilder sb = new StringBuilder();
   201         for (int i = 0; i < urlBytes.length; i++) {
   202             int c = urlBytes[i];
   203             if (NONENCODING_CHARS.get(c & 0xFF)) {
   204                 sb.append((char) c);
   205             } else {
   206                 sb.append(String.format("%%%02X", c & 0xFF));
   207             }
   208         }
   209         return sb.toString();
   210     }
   212     /**
   213      * Generates an HTML anchor tag.
   214      *
   215      * @param ref reference url for the anchor tag
   216      * @param body content for the anchor tag
   217      * @return an HtmlTree object
   218      */
   219     public static HtmlTree A(String ref, Content body) {
   220         HtmlTree htmltree = new HtmlTree(HtmlTag.A, nullCheck(body));
   221         htmltree.addAttr(HtmlAttr.HREF, encodeURL(ref));
   222         return htmltree;
   223     }
   225     /**
   226      * Generates an HTML anchor tag with name attribute and content.
   227      *
   228      * @param name name for the anchor tag
   229      * @param body content for the anchor tag
   230      * @return an HtmlTree object
   231      */
   232     public static HtmlTree A_NAME(String name, Content body) {
   233         HtmlTree htmltree = HtmlTree.A_NAME(name);
   234         htmltree.addContent(nullCheck(body));
   235         return htmltree;
   236     }
   238     /**
   239      * Generates an HTML anchor tag with name attribute.
   240      *
   241      * @param name name for the anchor tag
   242      * @return an HtmlTree object
   243      */
   244     public static HtmlTree A_NAME(String name) {
   245         HtmlTree htmltree = new HtmlTree(HtmlTag.A);
   246         htmltree.addAttr(HtmlAttr.NAME, nullCheck(name));
   247         return htmltree;
   248     }
   250     /**
   251      * Generates a CAPTION tag with some content.
   252      *
   253      * @param body content for the tag
   254      * @return an HtmlTree object for the CAPTION tag
   255      */
   256     public static HtmlTree CAPTION(Content body) {
   257         HtmlTree htmltree = new HtmlTree(HtmlTag.CAPTION, nullCheck(body));
   258         return htmltree;
   259     }
   261     /**
   262      * Generates a CODE tag with some content.
   263      *
   264      * @param body content for the tag
   265      * @return an HtmlTree object for the CODE tag
   266      */
   267     public static HtmlTree CODE(Content body) {
   268         HtmlTree htmltree = new HtmlTree(HtmlTag.CODE, nullCheck(body));
   269         return htmltree;
   270     }
   272     /**
   273      * Generates a DD tag with some content.
   274      *
   275      * @param body content for the tag
   276      * @return an HtmlTree object for the DD tag
   277      */
   278     public static HtmlTree DD(Content body) {
   279         HtmlTree htmltree = new HtmlTree(HtmlTag.DD, nullCheck(body));
   280         return htmltree;
   281     }
   283     /**
   284      * Generates a DL tag with some content.
   285      *
   286      * @param body content for the tag
   287      * @return an HtmlTree object for the DL tag
   288      */
   289     public static HtmlTree DL(Content body) {
   290         HtmlTree htmltree = new HtmlTree(HtmlTag.DL, nullCheck(body));
   291         return htmltree;
   292     }
   294     /**
   295      * Generates a DIV tag with the style class attributes. It also encloses
   296      * a content.
   297      *
   298      * @param styleClass stylesheet class for the tag
   299      * @param body content for the tag
   300      * @return an HtmlTree object for the DIV tag
   301      */
   302     public static HtmlTree DIV(HtmlStyle styleClass, Content body) {
   303         HtmlTree htmltree = new HtmlTree(HtmlTag.DIV, nullCheck(body));
   304         if (styleClass != null)
   305             htmltree.addStyle(styleClass);
   306         return htmltree;
   307     }
   309     /**
   310      * Generates a DIV tag with some content.
   311      *
   312      * @param body content for the tag
   313      * @return an HtmlTree object for the DIV tag
   314      */
   315     public static HtmlTree DIV(Content body) {
   316         return DIV(null, body);
   317     }
   319     /**
   320      * Generates a DT tag with some content.
   321      *
   322      * @param body content for the tag
   323      * @return an HtmlTree object for the DT tag
   324      */
   325     public static HtmlTree DT(Content body) {
   326         HtmlTree htmltree = new HtmlTree(HtmlTag.DT, nullCheck(body));
   327         return htmltree;
   328     }
   330     /**
   331      * Generates a FRAME tag.
   332      *
   333      * @param src the url of the document to be shown in the frame
   334      * @param name specifies the name of the frame
   335      * @param title the title for the frame
   336      * @param scrolling specifies whether to display scrollbars in the frame
   337      * @return an HtmlTree object for the FRAME tag
   338      */
   339     public static HtmlTree FRAME(String src, String name, String title, String scrolling) {
   340         HtmlTree htmltree = new HtmlTree(HtmlTag.FRAME);
   341         htmltree.addAttr(HtmlAttr.SRC, nullCheck(src));
   342         htmltree.addAttr(HtmlAttr.NAME, nullCheck(name));
   343         htmltree.addAttr(HtmlAttr.TITLE, nullCheck(title));
   344         if (scrolling != null)
   345             htmltree.addAttr(HtmlAttr.SCROLLING, scrolling);
   346         return htmltree;
   347     }
   349     /**
   350      * Generates a Frame tag.
   351      *
   352      * @param src the url of the document to be shown in the frame
   353      * @param name specifies the name of the frame
   354      * @param title the title for the frame
   355      * @return an HtmlTree object for the SPAN tag
   356      */
   357     public static HtmlTree FRAME(String src, String name, String title) {
   358         return FRAME(src, name, title, null);
   359     }
   361     /**
   362      * Generates a FRAMESET tag.
   363      *
   364      * @param cols the size of columns in the frameset
   365      * @param rows the size of rows in the frameset
   366      * @param title the title for the frameset
   367      * @param onload the script to run when the document loads
   368      * @return an HtmlTree object for the FRAMESET tag
   369      */
   370     public static HtmlTree FRAMESET(String cols, String rows, String title, String onload) {
   371         HtmlTree htmltree = new HtmlTree(HtmlTag.FRAMESET);
   372         if (cols != null)
   373             htmltree.addAttr(HtmlAttr.COLS, cols);
   374         if (rows != null)
   375             htmltree.addAttr(HtmlAttr.ROWS, rows);
   376         htmltree.addAttr(HtmlAttr.TITLE, nullCheck(title));
   377         htmltree.addAttr(HtmlAttr.ONLOAD, nullCheck(onload));
   378         return htmltree;
   379     }
   381     /**
   382      * Generates a heading tag (h1 to h6) with the title and style class attributes. It also encloses
   383      * a content.
   384      *
   385      * @param headingTag the heading tag to be generated
   386      * @param printTitle true if title for the tag needs to be printed else false
   387      * @param styleClass stylesheet class for the tag
   388      * @param body content for the tag
   389      * @return an HtmlTree object for the tag
   390      */
   391     public static HtmlTree HEADING(HtmlTag headingTag, boolean printTitle,
   392             HtmlStyle styleClass, Content body) {
   393         HtmlTree htmltree = new HtmlTree(headingTag, nullCheck(body));
   394         if (printTitle)
   395             htmltree.setTitle(body);
   396         if (styleClass != null)
   397             htmltree.addStyle(styleClass);
   398         return htmltree;
   399     }
   401     /**
   402      * Generates a heading tag (h1 to h6) with style class attribute. It also encloses
   403      * a content.
   404      *
   405      * @param headingTag the heading tag to be generated
   406      * @param styleClass stylesheet class for the tag
   407      * @param body content for the tag
   408      * @return an HtmlTree object for the tag
   409      */
   410     public static HtmlTree HEADING(HtmlTag headingTag, HtmlStyle styleClass, Content body) {
   411         return HEADING(headingTag, false, styleClass, body);
   412     }
   414     /**
   415      * Generates a heading tag (h1 to h6) with the title attribute. It also encloses
   416      * a content.
   417      *
   418      * @param headingTag the heading tag to be generated
   419      * @param printTitle true if the title for the tag needs to be printed else false
   420      * @param body content for the tag
   421      * @return an HtmlTree object for the tag
   422      */
   423     public static HtmlTree HEADING(HtmlTag headingTag, boolean printTitle, Content body) {
   424         return HEADING(headingTag, printTitle, null, body);
   425     }
   427     /**
   428      * Generates a heading tag (h1 to h6)  with some content.
   429      *
   430      * @param headingTag the heading tag to be generated
   431      * @param body content for the tag
   432      * @return an HtmlTree object for the tag
   433      */
   434     public static HtmlTree HEADING(HtmlTag headingTag, Content body) {
   435         return HEADING(headingTag, false, null, body);
   436     }
   438     /**
   439      * Generates an HTML tag with lang attribute. It also adds head and body
   440      * content to the HTML tree.
   441      *
   442      * @param lang language for the HTML document
   443      * @param head head for the HTML tag
   444      * @param body body for the HTML tag
   445      * @return an HtmlTree object for the HTML tag
   446      */
   447     public static HtmlTree HTML(String lang, Content head, Content body) {
   448         HtmlTree htmltree = new HtmlTree(HtmlTag.HTML, nullCheck(head), nullCheck(body));
   449         htmltree.addAttr(HtmlAttr.LANG, nullCheck(lang));
   450         return htmltree;
   451     }
   453     /**
   454      * Generates a LI tag with some content.
   455      *
   456      * @param body content for the tag
   457      * @return an HtmlTree object for the LI tag
   458      */
   459     public static HtmlTree LI(Content body) {
   460         return LI(null, body);
   461     }
   463     /**
   464      * Generates a LI tag with some content.
   465      *
   466      * @param styleClass style for the tag
   467      * @param body content for the tag
   468      * @return an HtmlTree object for the LI tag
   469      */
   470     public static HtmlTree LI(HtmlStyle styleClass, Content body) {
   471         HtmlTree htmltree = new HtmlTree(HtmlTag.LI, nullCheck(body));
   472         if (styleClass != null)
   473             htmltree.addStyle(styleClass);
   474         return htmltree;
   475     }
   477     /**
   478      * Generates a LINK tag with the rel, type, href and title attributes.
   479      *
   480      * @param rel relevance of the link
   481      * @param type type of link
   482      * @param href the path for the link
   483      * @param title title for the link
   484      * @return an HtmlTree object for the LINK tag
   485      */
   486     public static HtmlTree LINK(String rel, String type, String href, String title) {
   487         HtmlTree htmltree = new HtmlTree(HtmlTag.LINK);
   488         htmltree.addAttr(HtmlAttr.REL, nullCheck(rel));
   489         htmltree.addAttr(HtmlAttr.TYPE, nullCheck(type));
   490         htmltree.addAttr(HtmlAttr.HREF, nullCheck(href));
   491         htmltree.addAttr(HtmlAttr.TITLE, nullCheck(title));
   492         return htmltree;
   493     }
   495     /**
   496      * Generates a META tag with the http-equiv, content and charset attributes.
   497      *
   498      * @param httpEquiv http equiv attribute for the META tag
   499      * @param content type of content
   500      * @param charSet character set used
   501      * @return an HtmlTree object for the META tag
   502      */
   503     public static HtmlTree META(String httpEquiv, String content, String charSet) {
   504         HtmlTree htmltree = new HtmlTree(HtmlTag.META);
   505         String contentCharset = content + "; charset=" + charSet;
   506         htmltree.addAttr(HtmlAttr.HTTP_EQUIV, nullCheck(httpEquiv));
   507         htmltree.addAttr(HtmlAttr.CONTENT, contentCharset);
   508         return htmltree;
   509     }
   511     /**
   512      * Generates a META tag with the name and content attributes.
   513      *
   514      * @param name name attribute
   515      * @param content type of content
   516      * @return an HtmlTree object for the META tag
   517      */
   518     public static HtmlTree META(String name, String content) {
   519         HtmlTree htmltree = new HtmlTree(HtmlTag.META);
   520         htmltree.addAttr(HtmlAttr.NAME, nullCheck(name));
   521         htmltree.addAttr(HtmlAttr.CONTENT, nullCheck(content));
   522         return htmltree;
   523     }
   525     /**
   526      * Generates a NOSCRIPT tag with some content.
   527      *
   528      * @param body content of the noscript tag
   529      * @return an HtmlTree object for the NOSCRIPT tag
   530      */
   531     public static HtmlTree NOSCRIPT(Content body) {
   532         HtmlTree htmltree = new HtmlTree(HtmlTag.NOSCRIPT, nullCheck(body));
   533         return htmltree;
   534     }
   536     /**
   537      * Generates a P tag with some content.
   538      *
   539      * @param body content of the Paragraph tag
   540      * @return an HtmlTree object for the P tag
   541      */
   542     public static HtmlTree P(Content body) {
   543         return P(null, body);
   544     }
   546     /**
   547      * Generates a P tag with some content.
   548      *
   549      * @param styleClass style of the Paragraph tag
   550      * @param body content of the Paragraph tag
   551      * @return an HtmlTree object for the P tag
   552      */
   553     public static HtmlTree P(HtmlStyle styleClass, Content body) {
   554         HtmlTree htmltree = new HtmlTree(HtmlTag.P, nullCheck(body));
   555         if (styleClass != null)
   556             htmltree.addStyle(styleClass);
   557         return htmltree;
   558     }
   560     /**
   561      * Generates a SCRIPT tag with the type and src attributes.
   562      *
   563      * @param type type of link
   564      * @param src the path for the script
   565      * @return an HtmlTree object for the SCRIPT tag
   566      */
   567     public static HtmlTree SCRIPT(String type, String src) {
   568         HtmlTree htmltree = new HtmlTree(HtmlTag.SCRIPT);
   569         htmltree.addAttr(HtmlAttr.TYPE, nullCheck(type));
   570         htmltree.addAttr(HtmlAttr.SRC, nullCheck(src));
   571         return htmltree;
   572     }
   574     /**
   575      * Generates a SMALL tag with some content.
   576      *
   577      * @param body content for the tag
   578      * @return an HtmlTree object for the SMALL tag
   579      */
   580     public static HtmlTree SMALL(Content body) {
   581         HtmlTree htmltree = new HtmlTree(HtmlTag.SMALL, nullCheck(body));
   582         return htmltree;
   583     }
   585     /**
   586      * Generates a SPAN tag with some content.
   587      *
   588      * @param body content for the tag
   589      * @return an HtmlTree object for the SPAN tag
   590      */
   591     public static HtmlTree SPAN(Content body) {
   592         return SPAN(null, body);
   593     }
   595     /**
   596      * Generates a SPAN tag with style class attribute and some content.
   597      *
   598      * @param styleClass style class for the tag
   599      * @param body content for the tag
   600      * @return an HtmlTree object for the SPAN tag
   601      */
   602     public static HtmlTree SPAN(HtmlStyle styleClass, Content body) {
   603         HtmlTree htmltree = new HtmlTree(HtmlTag.SPAN, nullCheck(body));
   604         if (styleClass != null)
   605             htmltree.addStyle(styleClass);
   606         return htmltree;
   607     }
   609     /**
   610      * Generates a SPAN tag with id and style class attributes. It also encloses
   611      * a content.
   612      *
   613      * @param id the id for the tag
   614      * @param styleClass stylesheet class for the tag
   615      * @param body content for the tag
   616      * @return an HtmlTree object for the SPAN tag
   617      */
   618     public static HtmlTree SPAN(String id, HtmlStyle styleClass, Content body) {
   619         HtmlTree htmltree = new HtmlTree(HtmlTag.SPAN, nullCheck(body));
   620         htmltree.addAttr(HtmlAttr.ID, nullCheck(id));
   621         if (styleClass != null)
   622             htmltree.addStyle(styleClass);
   623         return htmltree;
   624     }
   626     /**
   627      * Generates a Table tag with style class, border, cell padding,
   628      * cellspacing and summary attributes and some content.
   629      *
   630      * @param styleClass style of the table
   631      * @param border border for the table
   632      * @param cellPadding cell padding for the table
   633      * @param cellSpacing cell spacing for the table
   634      * @param summary summary for the table
   635      * @param body content for the table
   636      * @return an HtmlTree object for the TABLE tag
   637      */
   638     public static HtmlTree TABLE(HtmlStyle styleClass, int border, int cellPadding,
   639             int cellSpacing, String summary, Content body) {
   640         HtmlTree htmltree = new HtmlTree(HtmlTag.TABLE, nullCheck(body));
   641         if (styleClass != null)
   642             htmltree.addStyle(styleClass);
   643         htmltree.addAttr(HtmlAttr.BORDER, Integer.toString(border));
   644         htmltree.addAttr(HtmlAttr.CELLPADDING, Integer.toString(cellPadding));
   645         htmltree.addAttr(HtmlAttr.CELLSPACING, Integer.toString(cellSpacing));
   646         htmltree.addAttr(HtmlAttr.SUMMARY, nullCheck(summary));
   647         return htmltree;
   648     }
   650     /**
   651      * Generates a TD tag with style class attribute and some content.
   652      *
   653      * @param styleClass style for the tag
   654      * @param body content for the tag
   655      * @return an HtmlTree object for the TD tag
   656      */
   657     public static HtmlTree TD(HtmlStyle styleClass, Content body) {
   658         HtmlTree htmltree = new HtmlTree(HtmlTag.TD, nullCheck(body));
   659         if (styleClass != null)
   660             htmltree.addStyle(styleClass);
   661         return htmltree;
   662     }
   664     /**
   665      * Generates a TD tag for an HTML table with some content.
   666      *
   667      * @param body content for the tag
   668      * @return an HtmlTree object for the TD tag
   669      */
   670     public static HtmlTree TD(Content body) {
   671         return TD(null, body);
   672     }
   674     /**
   675      * Generates a TH tag with style class and scope attributes and some content.
   676      *
   677      * @param styleClass style for the tag
   678      * @param scope scope of the tag
   679      * @param body content for the tag
   680      * @return an HtmlTree object for the TH tag
   681      */
   682     public static HtmlTree TH(HtmlStyle styleClass, String scope, Content body) {
   683         HtmlTree htmltree = new HtmlTree(HtmlTag.TH, nullCheck(body));
   684         if (styleClass != null)
   685             htmltree.addStyle(styleClass);
   686         htmltree.addAttr(HtmlAttr.SCOPE, nullCheck(scope));
   687         return htmltree;
   688     }
   690     /**
   691      * Generates a TH tag with scope attribute and some content.
   692      *
   693      * @param scope scope of the tag
   694      * @param body content for the tag
   695      * @return an HtmlTree object for the TH tag
   696      */
   697     public static HtmlTree TH(String scope, Content body) {
   698         return TH(null, scope, body);
   699     }
   701     /**
   702      * Generates a TITLE tag with some content.
   703      *
   704      * @param body content for the tag
   705      * @return an HtmlTree object for the TITLE tag
   706      */
   707     public static HtmlTree TITLE(Content body) {
   708         HtmlTree htmltree = new HtmlTree(HtmlTag.TITLE, nullCheck(body));
   709         return htmltree;
   710     }
   712     /**
   713      * Generates a TR tag for an HTML table with some content.
   714      *
   715      * @param body content for the tag
   716      * @return an HtmlTree object for the TR tag
   717      */
   718     public static HtmlTree TR(Content body) {
   719         HtmlTree htmltree = new HtmlTree(HtmlTag.TR, nullCheck(body));
   720         return htmltree;
   721     }
   723     /**
   724      * Generates a UL tag with the style class attribute and some content.
   725      *
   726      * @param styleClass style for the tag
   727      * @param body content for the tag
   728      * @return an HtmlTree object for the UL tag
   729      */
   730     public static HtmlTree UL(HtmlStyle styleClass, Content body) {
   731         HtmlTree htmltree = new HtmlTree(HtmlTag.UL, nullCheck(body));
   732         htmltree.addStyle(nullCheck(styleClass));
   733         return htmltree;
   734     }
   736     /**
   737      * {@inheritDoc}
   738      */
   739     public boolean isEmpty() {
   740         return (!hasContent() && !hasAttrs());
   741     }
   743     /**
   744      * Returns true if the HTML tree has content.
   745      *
   746      * @return true if the HTML tree has content else return false
   747      */
   748     public boolean hasContent() {
   749         return (!content.isEmpty());
   750     }
   752     /**
   753      * Returns true if the HTML tree has attributes.
   754      *
   755      * @return true if the HTML tree has attributes else return false
   756      */
   757     public boolean hasAttrs() {
   758         return (!attrs.isEmpty());
   759     }
   761     /**
   762      * Returns true if the HTML tree has a specific attribute.
   763      *
   764      * @param attrName name of the attribute to check within the HTML tree
   765      * @return true if the HTML tree has the specified attribute else return false
   766      */
   767     public boolean hasAttr(HtmlAttr attrName) {
   768         return (attrs.containsKey(attrName));
   769     }
   771     /**
   772      * Returns true if the HTML tree is valid. This check is more specific to
   773      * standard doclet and not exactly similar to W3C specifications. But it
   774      * ensures HTML validation.
   775      *
   776      * @return true if the HTML tree is valid
   777      */
   778     public boolean isValid() {
   779         switch (htmlTag) {
   780             case A :
   781                 return (hasAttr(HtmlAttr.NAME) || (hasAttr(HtmlAttr.HREF) && hasContent()));
   782             case BR :
   783                 return (!hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR)));
   784             case FRAME :
   785                 return (hasAttr(HtmlAttr.SRC) && !hasContent());
   786             case HR :
   787                 return (!hasContent());
   788             case IMG :
   789                 return (hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent());
   790             case LINK :
   791                 return (hasAttr(HtmlAttr.HREF) && !hasContent());
   792             case META :
   793                 return (hasAttr(HtmlAttr.CONTENT) && !hasContent());
   794             case SCRIPT :
   795                 return ((hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) ||
   796                         (hasAttr(HtmlAttr.TYPE) && hasContent()));
   797             default :
   798                 return hasContent();
   799         }
   800     }
   802     /**
   803      * Returns true if the element is an inline element.
   804      *
   805      * @return true if the HTML tag is an inline element
   806      */
   807     public boolean isInline() {
   808         return (htmlTag.blockType == HtmlTag.BlockType.INLINE);
   809     }
   811     /**
   812      * {@inheritDoc}
   813      */
   814     @Override
   815     public boolean write(Writer out, boolean atNewline) throws IOException {
   816         if (!isInline() && !atNewline)
   817             out.write(DocletConstants.NL);
   818         String tagString = htmlTag.toString();
   819         out.write("<");
   820         out.write(tagString);
   821         Iterator<HtmlAttr> iterator = attrs.keySet().iterator();
   822         HtmlAttr key;
   823         String value;
   824         while (iterator.hasNext()) {
   825             key = iterator.next();
   826             value = attrs.get(key);
   827             out.write(" ");
   828             out.write(key.toString());
   829             if (!value.isEmpty()) {
   830                 out.write("=\"");
   831                 out.write(value);
   832                 out.write("\"");
   833             }
   834         }
   835         out.write(">");
   836         boolean nl = false;
   837         for (Content c : content)
   838             nl = c.write(out, nl);
   839         if (htmlTag.endTagRequired()) {
   840             out.write("</");
   841             out.write(tagString);
   842             out.write(">");
   843         }
   844         if (!isInline()) {
   845             out.write(DocletConstants.NL);
   846             return true;
   847         } else {
   848             return false;
   849         }
   850     }
   852     /**
   853      * Given a Content node, strips all html characters and
   854      * return the result.
   855      *
   856      * @param body The content node to check.
   857      * @return the plain text from the content node
   858      *
   859      */
   860     private static String stripHtml(Content body) {
   861         String rawString = body.toString();
   862         // remove HTML tags
   863         rawString = rawString.replaceAll("\\<.*?>", " ");
   864         // consolidate multiple spaces between a word to a single space
   865         rawString = rawString.replaceAll("\\b\\s{2,}\\b", " ");
   866         // remove extra whitespaces
   867         return rawString.trim();
   868     }
   869 }

mercurial