HtmlWriter.java revision 3294:9adfb22ff08f
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.internal.doclets.toolkit.Configuration; 32import jdk.javadoc.internal.doclets.toolkit.Content; 33import jdk.javadoc.internal.doclets.toolkit.util.DocFile; 34import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 35import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; 36import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes; 37 38 39/** 40 * Class for the Html format code generation. 41 * Initializes PrintWriter with FileWriter, to enable print 42 * related methods to generate the code to the named File through FileWriter. 43 * 44 * <p><b>This is NOT part of any supported API. 45 * If you write code that depends on this, you do so at your own risk. 46 * This code and its internal interfaces are subject to change or 47 * deletion without notice.</b> 48 * 49 * @author Atul M Dambalkar 50 * @author Bhavesh Patel (Modified) 51 */ 52public class HtmlWriter { 53 54 /** 55 * The window title of this file 56 */ 57 protected String winTitle; 58 59 /** 60 * The configuration 61 */ 62 protected Configuration configuration; 63 64 /** 65 * The flag to indicate whether a member details list is printed or not. 66 */ 67 protected boolean memberDetailsListPrinted; 68 69 /** 70 * Header for table displaying modules and description.. 71 */ 72 protected final List<String> moduleTableHeader; 73 74 /** 75 * Header for tables displaying packages and description.. 76 */ 77 protected final List<String> packageTableHeader; 78 79 /** 80 * Summary for use tables displaying class and package use. 81 */ 82 protected final String useTableSummary; 83 84 /** 85 * Column header for class docs displaying Modifier and Type header. 86 */ 87 protected final String modifierTypeHeader; 88 89 public final Content overviewLabel; 90 91 public final Content defaultPackageLabel; 92 93 public final Content packageLabel; 94 95 public final Content moduleLabel; 96 97 public final Content useLabel; 98 99 public final Content prevLabel; 100 101 public final Content nextLabel; 102 103 public final Content prevclassLabel; 104 105 public final Content nextclassLabel; 106 107 public final Content summaryLabel; 108 109 public final Content detailLabel; 110 111 public final Content framesLabel; 112 113 public final Content noframesLabel; 114 115 public final Content treeLabel; 116 117 public final Content classLabel; 118 119 public final Content deprecatedLabel; 120 121 public final Content deprecatedPhrase; 122 123 public final Content allclassesLabel; 124 125 public final Content allpackagesLabel; 126 127 public final Content allmodulesLabel; 128 129 public final Content indexLabel; 130 131 public final Content helpLabel; 132 133 public final Content seeLabel; 134 135 public final Content descriptionLabel; 136 137 public final Content prevpackageLabel; 138 139 public final Content nextpackageLabel; 140 141 public final Content prevmoduleLabel; 142 143 public final Content nextmoduleLabel; 144 145 public final Content packagesLabel; 146 147 public final Content modulesLabel; 148 149 public final Content methodDetailsLabel; 150 151 public final Content annotationTypeDetailsLabel; 152 153 public final Content fieldDetailsLabel; 154 155 public final Content propertyDetailsLabel; 156 157 public final Content constructorDetailsLabel; 158 159 public final Content enumConstantsDetailsLabel; 160 161 public final Content specifiedByLabel; 162 163 public final Content overridesLabel; 164 165 public final Content descfrmClassLabel; 166 167 public final Content descfrmInterfaceLabel; 168 169 private final Writer writer; 170 171 protected Content script; 172 173 174 /** 175 * Constructor. 176 * 177 * @param path The directory path to be created for this file 178 * or null if none to be created. 179 * @exception IOException Exception raised by the FileWriter is passed on 180 * to next level. 181 * @exception UnsupportedEncodingException Exception raised by the 182 * OutputStreamWriter is passed on to next level. 183 */ 184 public HtmlWriter(Configuration configuration, DocPath path) 185 throws IOException, UnsupportedEncodingException { 186 writer = DocFile.createFileForOutput(configuration, path).openWriter(); 187 this.configuration = configuration; 188 this.memberDetailsListPrinted = false; 189 moduleTableHeader = Arrays.asList( 190 configuration.getText("doclet.Module"), 191 configuration.getText("doclet.Description")); 192 packageTableHeader = new ArrayList<>(); 193 packageTableHeader.add(configuration.getText("doclet.Package")); 194 packageTableHeader.add(configuration.getText("doclet.Description")); 195 useTableSummary = configuration.getText("doclet.Use_Table_Summary", 196 configuration.getText("doclet.packages")); 197 modifierTypeHeader = configuration.getText("doclet.0_and_1", 198 configuration.getText("doclet.Modifier"), 199 configuration.getText("doclet.Type")); 200 overviewLabel = getResource("doclet.Overview"); 201 defaultPackageLabel = new StringContent(DocletConstants.DEFAULT_PACKAGE_NAME); 202 packageLabel = getResource("doclet.Package"); 203 moduleLabel = getResource("doclet.Module"); 204 useLabel = getResource("doclet.navClassUse"); 205 prevLabel = getResource("doclet.Prev"); 206 nextLabel = getResource("doclet.Next"); 207 prevclassLabel = getNonBreakResource("doclet.Prev_Class"); 208 nextclassLabel = getNonBreakResource("doclet.Next_Class"); 209 summaryLabel = getResource("doclet.Summary"); 210 detailLabel = getResource("doclet.Detail"); 211 framesLabel = getResource("doclet.Frames"); 212 noframesLabel = getNonBreakResource("doclet.No_Frames"); 213 treeLabel = getResource("doclet.Tree"); 214 classLabel = getResource("doclet.Class"); 215 deprecatedLabel = getResource("doclet.navDeprecated"); 216 deprecatedPhrase = getResource("doclet.Deprecated"); 217 allclassesLabel = getNonBreakResource("doclet.All_Classes"); 218 allpackagesLabel = getNonBreakResource("doclet.All_Packages"); 219 allmodulesLabel = getNonBreakResource("doclet.All_Modules"); 220 indexLabel = getResource("doclet.Index"); 221 helpLabel = getResource("doclet.Help"); 222 seeLabel = getResource("doclet.See"); 223 descriptionLabel = getResource("doclet.Description"); 224 prevpackageLabel = getNonBreakResource("doclet.Prev_Package"); 225 nextpackageLabel = getNonBreakResource("doclet.Next_Package"); 226 prevmoduleLabel = getNonBreakResource("doclet.Prev_Module"); 227 nextmoduleLabel = getNonBreakResource("doclet.Next_Module"); 228 packagesLabel = getResource("doclet.Packages"); 229 modulesLabel = getResource("doclet.Modules"); 230 methodDetailsLabel = getResource("doclet.Method_Detail"); 231 annotationTypeDetailsLabel = getResource("doclet.Annotation_Type_Member_Detail"); 232 fieldDetailsLabel = getResource("doclet.Field_Detail"); 233 propertyDetailsLabel = getResource("doclet.Property_Detail"); 234 constructorDetailsLabel = getResource("doclet.Constructor_Detail"); 235 enumConstantsDetailsLabel = getResource("doclet.Enum_Constant_Detail"); 236 specifiedByLabel = getResource("doclet.Specified_By"); 237 overridesLabel = getResource("doclet.Overrides"); 238 descfrmClassLabel = getResource("doclet.Description_From_Class"); 239 descfrmInterfaceLabel = getResource("doclet.Description_From_Interface"); 240 } 241 242 public void write(Content c) throws IOException { 243 c.write(writer, true); 244 } 245 246 public void close() throws IOException { 247 writer.close(); 248 } 249 250 /** 251 * Get the configuration string as a content. 252 * 253 * @param key the key to look for in the configuration file 254 * @return a content tree for the text 255 */ 256 public Content getResource(String key) { 257 return configuration.getResource(key); 258 } 259 260 /** 261 * Get the configuration string as a content, replacing spaces 262 * with non-breaking spaces. 263 * 264 * @param key the key to look for in the configuration file 265 * @return a content tree for the text 266 */ 267 public Content getNonBreakResource(String key) { 268 String text = configuration.getText(key); 269 Content c = configuration.newContent(); 270 int start = 0; 271 int p; 272 while ((p = text.indexOf(" ", start)) != -1) { 273 c.addContent(text.substring(start, p)); 274 c.addContent(RawHtml.nbsp); 275 start = p + 1; 276 } 277 c.addContent(text.substring(start)); 278 return c; 279 } 280 281 /** 282 * Get the configuration string as a content. 283 * 284 * @param key the key to look for in the configuration file 285 * @param o string or content argument added to configuration text 286 * @return a content tree for the text 287 */ 288 public Content getResource(String key, Object o) { 289 return configuration.getResource(key, o); 290 } 291 292 /** 293 * Get the configuration string as a content. 294 * 295 * @param key the key to look for in the configuration file 296 * @param o1 string or content argument added to configuration text 297 * @param o2 string or content argument added to configuration text 298 * @return a content tree for the text 299 */ 300 public Content getResource(String key, Object o0, Object o1) { 301 return configuration.getResource(key, o0, o1); 302 } 303 304 /** 305 * Returns an HtmlTree for the SCRIPT tag. 306 * 307 * @return an HtmlTree for the SCRIPT tag 308 */ 309 protected HtmlTree getWinTitleScript(){ 310 HtmlTree script = HtmlTree.SCRIPT(); 311 if(winTitle != null && winTitle.length() > 0) { 312 String scriptCode = "<!--" + DocletConstants.NL + 313 " try {" + DocletConstants.NL + 314 " if (location.href.indexOf('is-external=true') == -1) {" + DocletConstants.NL + 315 " parent.document.title=\"" + escapeJavaScriptChars(winTitle) + "\";" + DocletConstants.NL + 316 " }" + DocletConstants.NL + 317 " }" + DocletConstants.NL + 318 " catch(err) {" + DocletConstants.NL + 319 " }" + DocletConstants.NL + 320 "//-->" + DocletConstants.NL; 321 RawHtml scriptContent = new RawHtml(scriptCode); 322 script.addContent(scriptContent); 323 } 324 return script; 325 } 326 327 /** 328 * Returns a String with escaped special JavaScript characters. 329 * 330 * @param s String that needs to be escaped 331 * @return a valid escaped JavaScript string 332 */ 333 private static String escapeJavaScriptChars(String s) { 334 StringBuilder sb = new StringBuilder(); 335 for (int i = 0; i < s.length(); i++) { 336 char ch = s.charAt(i); 337 switch (ch) { 338 case '\b': 339 sb.append("\\b"); 340 break; 341 case '\t': 342 sb.append("\\t"); 343 break; 344 case '\n': 345 sb.append("\\n"); 346 break; 347 case '\f': 348 sb.append("\\f"); 349 break; 350 case '\r': 351 sb.append("\\r"); 352 break; 353 case '"': 354 sb.append("\\\""); 355 break; 356 case '\'': 357 sb.append("\\\'"); 358 break; 359 case '\\': 360 sb.append("\\\\"); 361 break; 362 default: 363 if (ch < 32 || ch >= 127) { 364 sb.append(String.format("\\u%04X", (int)ch)); 365 } else { 366 sb.append(ch); 367 } 368 break; 369 } 370 } 371 return sb.toString(); 372 } 373 374 /** 375 * Returns a content tree for the SCRIPT tag for the main page(index.html). 376 * 377 * @return a content for the SCRIPT tag 378 */ 379 protected Content getFramesJavaScript() { 380 HtmlTree script = HtmlTree.SCRIPT(); 381 String scriptCode = DocletConstants.NL + 382 " targetPage = \"\" + window.location.search;" + DocletConstants.NL + 383 " if (targetPage != \"\" && targetPage != \"undefined\")" + DocletConstants.NL + 384 " targetPage = targetPage.substring(1);" + DocletConstants.NL + 385 " if (targetPage.indexOf(\":\") != -1 || (targetPage != \"\" && !validURL(targetPage)))" + DocletConstants.NL + 386 " targetPage = \"undefined\";" + DocletConstants.NL + 387 " function validURL(url) {" + DocletConstants.NL + 388 " try {" + DocletConstants.NL + 389 " url = decodeURIComponent(url);" + DocletConstants.NL + 390 " }" + DocletConstants.NL + 391 " catch (error) {" + DocletConstants.NL + 392 " return false;" + DocletConstants.NL + 393 " }" + DocletConstants.NL + 394 " var pos = url.indexOf(\".html\");" + DocletConstants.NL + 395 " if (pos == -1 || pos != url.length - 5)" + DocletConstants.NL + 396 " return false;" + DocletConstants.NL + 397 " var allowNumber = false;" + DocletConstants.NL + 398 " var allowSep = false;" + DocletConstants.NL + 399 " var seenDot = false;" + DocletConstants.NL + 400 " for (var i = 0; i < url.length - 5; i++) {" + DocletConstants.NL + 401 " var ch = url.charAt(i);" + DocletConstants.NL + 402 " if ('a' <= ch && ch <= 'z' ||" + DocletConstants.NL + 403 " 'A' <= ch && ch <= 'Z' ||" + DocletConstants.NL + 404 " ch == '$' ||" + DocletConstants.NL + 405 " ch == '_' ||" + DocletConstants.NL + 406 " ch.charCodeAt(0) > 127) {" + DocletConstants.NL + 407 " allowNumber = true;" + DocletConstants.NL + 408 " allowSep = true;" + DocletConstants.NL + 409 " } else if ('0' <= ch && ch <= '9'" + DocletConstants.NL + 410 " || ch == '-') {" + DocletConstants.NL + 411 " if (!allowNumber)" + DocletConstants.NL + 412 " return false;" + DocletConstants.NL + 413 " } else if (ch == '/' || ch == '.') {" + DocletConstants.NL + 414 " if (!allowSep)" + DocletConstants.NL + 415 " return false;" + DocletConstants.NL + 416 " allowNumber = false;" + DocletConstants.NL + 417 " allowSep = false;" + DocletConstants.NL + 418 " if (ch == '.')" + DocletConstants.NL + 419 " seenDot = true;" + DocletConstants.NL + 420 " if (ch == '/' && seenDot)" + DocletConstants.NL + 421 " return false;" + DocletConstants.NL + 422 " } else {" + DocletConstants.NL + 423 " return false;"+ DocletConstants.NL + 424 " }" + DocletConstants.NL + 425 " }" + DocletConstants.NL + 426 " return true;" + DocletConstants.NL + 427 " }" + DocletConstants.NL + 428 " function loadFrames() {" + DocletConstants.NL + 429 " if (targetPage != \"\" && targetPage != \"undefined\")" + DocletConstants.NL + 430 " top.classFrame.location = top.targetPage;" + DocletConstants.NL + 431 " }" + DocletConstants.NL; 432 RawHtml scriptContent = new RawHtml(scriptCode); 433 script.addContent(scriptContent); 434 return script; 435 } 436 437 /** 438 * Returns an HtmlTree for the BODY tag. 439 * 440 * @param includeScript set true if printing windowtitle script 441 * @param title title for the window 442 * @return an HtmlTree for the BODY tag 443 */ 444 public HtmlTree getBody(boolean includeScript, String title) { 445 HtmlTree body = new HtmlTree(HtmlTag.BODY); 446 // Set window title string which is later printed 447 this.winTitle = title; 448 // Don't print windowtitle script for overview-frame, allclasses-frame 449 // and package-frame 450 if (includeScript) { 451 this.script = getWinTitleScript(); 452 body.addContent(script); 453 Content noScript = HtmlTree.NOSCRIPT( 454 HtmlTree.DIV(getResource("doclet.No_Script_Message"))); 455 body.addContent(noScript); 456 } 457 return body; 458 } 459 460 /** 461 * Generated javascript variables for the document. 462 * 463 * @param typeMap map comprising of method and type relationship 464 * @param methodTypes set comprising of all methods types for this class 465 */ 466 public void generateMethodTypesScript(Map<String,Integer> typeMap, 467 Set<MethodTypes> methodTypes) { 468 String sep = ""; 469 StringBuilder vars = new StringBuilder("var methods = {"); 470 for (Map.Entry<String,Integer> entry : typeMap.entrySet()) { 471 vars.append(sep); 472 sep = ","; 473 vars.append("\"") 474 .append(entry.getKey()) 475 .append("\":") 476 .append(entry.getValue()); 477 } 478 vars.append("};").append(DocletConstants.NL); 479 sep = ""; 480 vars.append("var tabs = {"); 481 for (MethodTypes entry : methodTypes) { 482 vars.append(sep); 483 sep = ","; 484 vars.append(entry.value()) 485 .append(":") 486 .append("[") 487 .append("\"") 488 .append(entry.tabId()) 489 .append("\"") 490 .append(sep) 491 .append("\"") 492 .append(configuration.getText(entry.resourceKey())) 493 .append("\"]"); 494 } 495 vars.append("};") 496 .append(DocletConstants.NL); 497 addStyles(HtmlStyle.altColor, vars); 498 addStyles(HtmlStyle.rowColor, vars); 499 addStyles(HtmlStyle.tableTab, vars); 500 addStyles(HtmlStyle.activeTableTab, vars); 501 script.addContent(new RawHtml(vars)); 502 } 503 504 /** 505 * Adds javascript style variables to the document. 506 * 507 * @param style style to be added as a javascript variable 508 * @param vars variable string to which the style variable will be added 509 */ 510 public void addStyles(HtmlStyle style, StringBuilder vars) { 511 vars.append("var ").append(style).append(" = \"").append(style) 512 .append("\";").append(DocletConstants.NL); 513 } 514 515 /** 516 * Returns an HtmlTree for the TITLE tag. 517 * 518 * @return an HtmlTree for the TITLE tag 519 */ 520 public HtmlTree getTitle() { 521 HtmlTree title = HtmlTree.TITLE(new StringContent(winTitle)); 522 return title; 523 } 524 525 public String codeText(String text) { 526 return "<code>" + text + "</code>"; 527 } 528 529 /** 530 * Return "&nbsp;", non-breaking space. 531 */ 532 public Content getSpace() { 533 return RawHtml.nbsp; 534 } 535 536 /* 537 * Returns a header for Modifier and Type column of a table. 538 */ 539 public String getModifierTypeHeader() { 540 return modifierTypeHeader; 541 } 542} 543