HtmlWriter.java revision 3831:209b0eab0e1f
1/* 2 * Copyright (c) 1997, 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 jdk.javadoc.internal.doclets.formats.html.markup; 27 28import java.io.*; 29import java.util.*; 30 31import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; 32import jdk.javadoc.internal.doclets.toolkit.Configuration; 33import jdk.javadoc.internal.doclets.toolkit.Content; 34import jdk.javadoc.internal.doclets.toolkit.Resources; 35import jdk.javadoc.internal.doclets.toolkit.util.DocFile; 36import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 37import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 38import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; 39import jdk.javadoc.internal.doclets.toolkit.util.ModulePackageTypes; 40import jdk.javadoc.internal.doclets.toolkit.util.TableTabTypes; 41 42 43/** 44 * Class for the Html format code generation. 45 * Initializes PrintWriter with FileWriter, to enable print 46 * related methods to generate the code to the named File through FileWriter. 47 * 48 * <p><b>This is NOT part of any supported API. 49 * If you write code that depends on this, you do so at your own risk. 50 * This code and its internal interfaces are subject to change or 51 * deletion without notice.</b> 52 * 53 * @author Atul M Dambalkar 54 * @author Bhavesh Patel (Modified) 55 */ 56public class HtmlWriter { 57 58 /** 59 * The window title of this file 60 */ 61 protected String winTitle; 62 63 /** 64 * The configuration 65 */ 66 protected Configuration configuration; 67 68 /** 69 * Header for table displaying modules and description. 70 */ 71 protected final List<String> moduleTableHeader; 72 73 /** 74 * Header for tables displaying packages and description. 75 */ 76 protected final List<String> packageTableHeader; 77 78 /** 79 * Header for tables displaying modules and description. 80 */ 81 protected final List<String> requiresTableHeader; 82 83 /** 84 * Header for tables displaying packages and description. 85 */ 86 protected final List<String> exportedPackagesTableHeader; 87 88 /** 89 * Header for tables displaying modules and exported packages. 90 */ 91 protected final List<String> additionalPackagesTableHeader; 92 93 /** 94 * Header for tables displaying types and description. 95 */ 96 protected final List<String> usesTableHeader; 97 98 /** 99 * Header for tables displaying types and description. 100 */ 101 protected final List<String> providesTableHeader; 102 103 /** 104 * Summary for use tables displaying class and package use. 105 */ 106 protected final String useTableSummary; 107 108 /** 109 * Column header for class docs displaying Modifier and Type header. 110 */ 111 protected final String modifierTypeHeader; 112 113 private final DocFile docFile; 114 115 protected Content script; 116 117 118 /** 119 * Constructor. 120 * 121 * @param path The directory path to be created for this file 122 * or null if none to be created. 123 */ 124 public HtmlWriter(Configuration configuration, DocPath path) { 125 docFile = DocFile.createFileForOutput(configuration, path); 126 this.configuration = configuration; 127 128 // The following should be converted to shared Content objects 129 // and moved to Contents, but that will require additional 130 // changes at the use sites. 131 Resources resources = configuration.getResources(); 132 moduleTableHeader = Arrays.asList( 133 resources.getText("doclet.Module"), 134 resources.getText("doclet.Description")); 135 packageTableHeader = new ArrayList<>(); 136 packageTableHeader.add(resources.getText("doclet.Package")); 137 packageTableHeader.add(resources.getText("doclet.Description")); 138 requiresTableHeader = new ArrayList<>(); 139 requiresTableHeader.add(resources.getText("doclet.Modifier")); 140 requiresTableHeader.add(resources.getText("doclet.Module")); 141 requiresTableHeader.add(resources.getText("doclet.Description")); 142 exportedPackagesTableHeader = new ArrayList<>(); 143 exportedPackagesTableHeader.add(resources.getText("doclet.Package")); 144 if (configuration.docEnv.getModuleMode() == ModuleMode.ALL) { 145 exportedPackagesTableHeader.add(resources.getText("doclet.Module")); 146 } 147 exportedPackagesTableHeader.add(resources.getText("doclet.Description")); 148 additionalPackagesTableHeader = new ArrayList<>(); 149 additionalPackagesTableHeader.add(resources.getText("doclet.Module")); 150 additionalPackagesTableHeader.add(resources.getText("doclet.Packages")); 151 usesTableHeader = new ArrayList<>(); 152 usesTableHeader.add(resources.getText("doclet.Type")); 153 usesTableHeader.add(resources.getText("doclet.Description")); 154 providesTableHeader = new ArrayList<>(); 155 providesTableHeader.add(resources.getText("doclet.Type")); 156 providesTableHeader.add(resources.getText("doclet.Description")); 157 useTableSummary = resources.getText("doclet.Use_Table_Summary", 158 resources.getText("doclet.packages")); 159 modifierTypeHeader = resources.getText("doclet.0_and_1", 160 resources.getText("doclet.Modifier"), 161 resources.getText("doclet.Type")); 162 } 163 164 public void write(Content c) throws DocFileIOException { 165 try (Writer writer = docFile.openWriter()) { 166 c.write(writer, true); 167 } catch (IOException e) { 168 throw new DocFileIOException(docFile, DocFileIOException.Mode.WRITE, e); 169 } 170 } 171 172 /** 173 * Returns an HtmlTree for the SCRIPT tag. 174 * 175 * @return an HtmlTree for the SCRIPT tag 176 */ 177 protected HtmlTree getWinTitleScript(){ 178 HtmlTree scriptTree = HtmlTree.SCRIPT(); 179 if(winTitle != null && winTitle.length() > 0) { 180 String scriptCode = "<!--\n" + 181 " try {\n" + 182 " if (location.href.indexOf('is-external=true') == -1) {\n" + 183 " parent.document.title=\"" + escapeJavaScriptChars(winTitle) + "\";\n" + 184 " }\n" + 185 " }\n" + 186 " catch(err) {\n" + 187 " }\n" + 188 "//-->\n"; 189 RawHtml scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); 190 scriptTree.addContent(scriptContent); 191 } 192 return scriptTree; 193 } 194 195 /** 196 * Returns a String with escaped special JavaScript characters. 197 * 198 * @param s String that needs to be escaped 199 * @return a valid escaped JavaScript string 200 */ 201 private static String escapeJavaScriptChars(String s) { 202 StringBuilder sb = new StringBuilder(); 203 for (int i = 0; i < s.length(); i++) { 204 char ch = s.charAt(i); 205 switch (ch) { 206 case '\b': 207 sb.append("\\b"); 208 break; 209 case '\t': 210 sb.append("\\t"); 211 break; 212 case '\n': 213 sb.append("\\n"); 214 break; 215 case '\f': 216 sb.append("\\f"); 217 break; 218 case '\r': 219 sb.append("\\r"); 220 break; 221 case '"': 222 sb.append("\\\""); 223 break; 224 case '\'': 225 sb.append("\\\'"); 226 break; 227 case '\\': 228 sb.append("\\\\"); 229 break; 230 default: 231 if (ch < 32 || ch >= 127) { 232 sb.append(String.format("\\u%04X", (int)ch)); 233 } else { 234 sb.append(ch); 235 } 236 break; 237 } 238 } 239 return sb.toString(); 240 } 241 242 /** 243 * Returns a content tree for the SCRIPT tag for the main page(index.html). 244 * 245 * @return a content for the SCRIPT tag 246 */ 247 protected Content getFramesJavaScript() { 248 HtmlTree scriptTree = HtmlTree.SCRIPT(); 249 String scriptCode = "\n" + 250 " tmpTargetPage = \"\" + window.location.search;\n" + 251 " if (tmpTargetPage != \"\" && tmpTargetPage != \"undefined\")\n" + 252 " tmpTargetPage = tmpTargetPage.substring(1);\n" + 253 " if (tmpTargetPage.indexOf(\":\") != -1 || (tmpTargetPage != \"\" && !validURL(tmpTargetPage)))\n" + 254 " tmpTargetPage = \"undefined\";\n" + 255 " targetPage = tmpTargetPage;\n" + 256 " function validURL(url) {\n" + 257 " try {\n" + 258 " url = decodeURIComponent(url);\n" + 259 " }\n" + 260 " catch (error) {\n" + 261 " return false;\n" + 262 " }\n" + 263 " var pos = url.indexOf(\".html\");\n" + 264 " if (pos == -1 || pos != url.length - 5)\n" + 265 " return false;\n" + 266 " var allowNumber = false;\n" + 267 " var allowSep = false;\n" + 268 " var seenDot = false;\n" + 269 " for (var i = 0; i < url.length - 5; i++) {\n" + 270 " var ch = url.charAt(i);\n" + 271 " if ('a' <= ch && ch <= 'z' ||\n" + 272 " 'A' <= ch && ch <= 'Z' ||\n" + 273 " ch == '$' ||\n" + 274 " ch == '_' ||\n" + 275 " ch.charCodeAt(0) > 127) {\n" + 276 " allowNumber = true;\n" + 277 " allowSep = true;\n" + 278 " } else if ('0' <= ch && ch <= '9'\n" + 279 " || ch == '-') {\n" + 280 " if (!allowNumber)\n" + 281 " return false;\n" + 282 " } else if (ch == '/' || ch == '.') {\n" + 283 " if (!allowSep)\n" + 284 " return false;\n" + 285 " allowNumber = false;\n" + 286 " allowSep = false;\n" + 287 " if (ch == '.')\n" + 288 " seenDot = true;\n" + 289 " if (ch == '/' && seenDot)\n" + 290 " return false;\n" + 291 " } else {\n" + 292 " return false;\n" + 293 " }\n" + 294 " }\n" + 295 " return true;\n" + 296 " }\n" + 297 " function loadFrames() {\n" + 298 " if (targetPage != \"\" && targetPage != \"undefined\")\n" + 299 " top.classFrame.location = top.targetPage;\n" + 300 " }\n"; 301 RawHtml scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); 302 scriptTree.addContent(scriptContent); 303 return scriptTree; 304 } 305 306 /** 307 * Returns an HtmlTree for the BODY tag. 308 * 309 * @param includeScript set true if printing windowtitle script 310 * @param title title for the window 311 * @return an HtmlTree for the BODY tag 312 */ 313 public HtmlTree getBody(boolean includeScript, String title) { 314 HtmlTree body = new HtmlTree(HtmlTag.BODY); 315 // Set window title string which is later printed 316 this.winTitle = title; 317 // Don't print windowtitle script for overview-frame, allclasses-frame 318 // and package-frame 319 if (includeScript) { 320 this.script = getWinTitleScript(); 321 body.addContent(script); 322 Content noScript = HtmlTree.NOSCRIPT( 323 HtmlTree.DIV(configuration.getContent("doclet.No_Script_Message"))); 324 body.addContent(noScript); 325 } 326 return body; 327 } 328 329 /** 330 * Generated javascript variables for the document. 331 * 332 * @param typeMap map comprising of method and type relationship 333 * @param tabTypes set comprising of all table tab types for this class 334 * @param elementName packages or methods table for which tabs need to be displayed 335 */ 336 public void generateTableTabTypesScript(Map<String,Integer> typeMap, 337 Set<? extends TableTabTypes> tabTypes, String elementName) { 338 String sep = ""; 339 StringBuilder vars = new StringBuilder("var "); 340 vars.append(elementName) 341 .append(" = {"); 342 for (Map.Entry<String,Integer> entry : typeMap.entrySet()) { 343 vars.append(sep); 344 sep = ","; 345 vars.append("\"") 346 .append(entry.getKey()) 347 .append("\":") 348 .append(entry.getValue()); 349 } 350 vars.append("};").append(DocletConstants.NL); 351 sep = ""; 352 vars.append("var tabs = {"); 353 for (TableTabTypes entry : tabTypes) { 354 vars.append(sep); 355 sep = ","; 356 vars.append(entry.tableTabs().value()) 357 .append(":") 358 .append("[") 359 .append("\"") 360 .append(entry.tableTabs().tabId()) 361 .append("\"") 362 .append(sep) 363 .append("\"") 364 .append(configuration.getText(entry.tableTabs().resourceKey())) 365 .append("\"]"); 366 } 367 vars.append("};") 368 .append(DocletConstants.NL); 369 addStyles(HtmlStyle.altColor, vars); 370 addStyles(HtmlStyle.rowColor, vars); 371 addStyles(HtmlStyle.tableTab, vars); 372 addStyles(HtmlStyle.activeTableTab, vars); 373 script.addContent(new RawHtml(vars)); 374 } 375 376 /** 377 * Adds javascript style variables to the document. 378 * 379 * @param style style to be added as a javascript variable 380 * @param vars variable string to which the style variable will be added 381 */ 382 public void addStyles(HtmlStyle style, StringBuilder vars) { 383 vars.append("var ").append(style).append(" = \"").append(style) 384 .append("\";").append(DocletConstants.NL); 385 } 386 387 /** 388 * Returns an HtmlTree for the TITLE tag. 389 * 390 * @return an HtmlTree for the TITLE tag 391 */ 392 public HtmlTree getTitle() { 393 HtmlTree title = HtmlTree.TITLE(new StringContent(winTitle)); 394 return title; 395 } 396 397 /* 398 * Returns a header for Modifier and Type column of a table. 399 */ 400 public String getModifierTypeHeader() { 401 return modifierTypeHeader; 402 } 403} 404