| /* |
| * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package jdk.javadoc.internal.doclets.formats.html.markup; |
| |
| import java.io.*; |
| import java.util.*; |
| |
| import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; |
| import jdk.javadoc.internal.doclets.toolkit.Configuration; |
| import jdk.javadoc.internal.doclets.toolkit.Content; |
| import jdk.javadoc.internal.doclets.toolkit.Resources; |
| import jdk.javadoc.internal.doclets.toolkit.util.DocFile; |
| import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; |
| import jdk.javadoc.internal.doclets.toolkit.util.DocPath; |
| import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; |
| import jdk.javadoc.internal.doclets.toolkit.util.TableTabTypes; |
| |
| |
| /** |
| * Class for the Html format code generation. |
| * Initializes PrintWriter with FileWriter, to enable print |
| * related methods to generate the code to the named File through FileWriter. |
| * |
| * <p><b>This is NOT part of any supported API. |
| * If you write code that depends on this, you do so at your own risk. |
| * This code and its internal interfaces are subject to change or |
| * deletion without notice.</b> |
| * |
| * @author Atul M Dambalkar |
| * @author Bhavesh Patel (Modified) |
| */ |
| public class HtmlWriter { |
| |
| /** |
| * The window title of this file |
| */ |
| protected String winTitle; |
| |
| /** |
| * The configuration |
| */ |
| protected Configuration configuration; |
| |
| /** |
| * Header for table displaying modules and description. |
| */ |
| protected final List<String> moduleTableHeader; |
| |
| /** |
| * Header for tables displaying packages and description. |
| */ |
| protected final List<String> packageTableHeader; |
| |
| /** |
| * Header for tables displaying modules and description. |
| */ |
| protected final List<String> requiresTableHeader; |
| |
| /** |
| * Header for tables displaying packages and description. |
| */ |
| protected final List<String> exportedPackagesTableHeader; |
| |
| /** |
| * Header for tables displaying modules and exported packages. |
| */ |
| protected final List<String> indirectPackagesTableHeader; |
| |
| /** |
| * Header for tables displaying types and description. |
| */ |
| protected final List<String> usesTableHeader; |
| |
| /** |
| * Header for tables displaying types and description. |
| */ |
| protected final List<String> providesTableHeader; |
| |
| /** |
| * Summary for use tables displaying class and package use. |
| */ |
| protected final String useTableSummary; |
| |
| /** |
| * Column header for class docs displaying Modifier and Type header. |
| */ |
| protected final String modifierTypeHeader; |
| |
| private final DocFile docFile; |
| |
| protected Content script; |
| |
| |
| /** |
| * Constructor. |
| * |
| * @param path The directory path to be created for this file |
| * or null if none to be created. |
| */ |
| public HtmlWriter(Configuration configuration, DocPath path) { |
| docFile = DocFile.createFileForOutput(configuration, path); |
| this.configuration = configuration; |
| |
| // The following should be converted to shared Content objects |
| // and moved to Contents, but that will require additional |
| // changes at the use sites. |
| Resources resources = configuration.getResources(); |
| moduleTableHeader = Arrays.asList( |
| resources.getText("doclet.Module"), |
| resources.getText("doclet.Description")); |
| packageTableHeader = new ArrayList<>(); |
| packageTableHeader.add(resources.getText("doclet.Package")); |
| packageTableHeader.add(resources.getText("doclet.Description")); |
| requiresTableHeader = new ArrayList<>(); |
| requiresTableHeader.add(resources.getText("doclet.Modifier")); |
| requiresTableHeader.add(resources.getText("doclet.Module")); |
| requiresTableHeader.add(resources.getText("doclet.Description")); |
| exportedPackagesTableHeader = new ArrayList<>(); |
| exportedPackagesTableHeader.add(resources.getText("doclet.Package")); |
| if (configuration.docEnv.getModuleMode() == ModuleMode.ALL) { |
| exportedPackagesTableHeader.add(resources.getText("doclet.Module")); |
| } |
| exportedPackagesTableHeader.add(resources.getText("doclet.Description")); |
| indirectPackagesTableHeader = new ArrayList<>(); |
| indirectPackagesTableHeader.add(resources.getText("doclet.From")); |
| indirectPackagesTableHeader.add(resources.getText("doclet.Packages")); |
| usesTableHeader = new ArrayList<>(); |
| usesTableHeader.add(resources.getText("doclet.Type")); |
| usesTableHeader.add(resources.getText("doclet.Description")); |
| providesTableHeader = new ArrayList<>(); |
| providesTableHeader.add(resources.getText("doclet.Type")); |
| providesTableHeader.add(resources.getText("doclet.Description")); |
| useTableSummary = resources.getText("doclet.Use_Table_Summary", |
| resources.getText("doclet.packages")); |
| modifierTypeHeader = resources.getText("doclet.0_and_1", |
| resources.getText("doclet.Modifier"), |
| resources.getText("doclet.Type")); |
| } |
| |
| public void write(Content c) throws DocFileIOException { |
| try (Writer writer = docFile.openWriter()) { |
| c.write(writer, true); |
| } catch (IOException e) { |
| throw new DocFileIOException(docFile, DocFileIOException.Mode.WRITE, e); |
| } |
| } |
| |
| /** |
| * Returns an HtmlTree for the SCRIPT tag. |
| * |
| * @return an HtmlTree for the SCRIPT tag |
| */ |
| protected HtmlTree getWinTitleScript(){ |
| HtmlTree scriptTree = HtmlTree.SCRIPT(); |
| if(winTitle != null && winTitle.length() > 0) { |
| String scriptCode = "<!--\n" + |
| " try {\n" + |
| " if (location.href.indexOf('is-external=true') == -1) {\n" + |
| " parent.document.title=\"" + escapeJavaScriptChars(winTitle) + "\";\n" + |
| " }\n" + |
| " }\n" + |
| " catch(err) {\n" + |
| " }\n" + |
| "//-->\n"; |
| RawHtml scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); |
| scriptTree.addContent(scriptContent); |
| } |
| return scriptTree; |
| } |
| |
| /** |
| * Returns a String with escaped special JavaScript characters. |
| * |
| * @param s String that needs to be escaped |
| * @return a valid escaped JavaScript string |
| */ |
| private static String escapeJavaScriptChars(String s) { |
| StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < s.length(); i++) { |
| char ch = s.charAt(i); |
| switch (ch) { |
| case '\b': |
| sb.append("\\b"); |
| break; |
| case '\t': |
| sb.append("\\t"); |
| break; |
| case '\n': |
| sb.append("\\n"); |
| break; |
| case '\f': |
| sb.append("\\f"); |
| break; |
| case '\r': |
| sb.append("\\r"); |
| break; |
| case '"': |
| sb.append("\\\""); |
| break; |
| case '\'': |
| sb.append("\\\'"); |
| break; |
| case '\\': |
| sb.append("\\\\"); |
| break; |
| default: |
| if (ch < 32 || ch >= 127) { |
| sb.append(String.format("\\u%04X", (int)ch)); |
| } else { |
| sb.append(ch); |
| } |
| break; |
| } |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns a content tree for the SCRIPT tag for the main page(index.html). |
| * |
| * @return a content for the SCRIPT tag |
| */ |
| protected Content getFramesJavaScript() { |
| HtmlTree scriptTree = HtmlTree.SCRIPT(); |
| String scriptCode = "\n" + |
| " tmpTargetPage = \"\" + window.location.search;\n" + |
| " if (tmpTargetPage != \"\" && tmpTargetPage != \"undefined\")\n" + |
| " tmpTargetPage = tmpTargetPage.substring(1);\n" + |
| " if (tmpTargetPage.indexOf(\":\") != -1 || (tmpTargetPage != \"\" && !validURL(tmpTargetPage)))\n" + |
| " tmpTargetPage = \"undefined\";\n" + |
| " targetPage = tmpTargetPage;\n" + |
| " function validURL(url) {\n" + |
| " try {\n" + |
| " url = decodeURIComponent(url);\n" + |
| " }\n" + |
| " catch (error) {\n" + |
| " return false;\n" + |
| " }\n" + |
| " var pos = url.indexOf(\".html\");\n" + |
| " if (pos == -1 || pos != url.length - 5)\n" + |
| " return false;\n" + |
| " var allowNumber = false;\n" + |
| " var allowSep = false;\n" + |
| " var seenDot = false;\n" + |
| " for (var i = 0; i < url.length - 5; i++) {\n" + |
| " var ch = url.charAt(i);\n" + |
| " if ('a' <= ch && ch <= 'z' ||\n" + |
| " 'A' <= ch && ch <= 'Z' ||\n" + |
| " ch == '$' ||\n" + |
| " ch == '_' ||\n" + |
| " ch.charCodeAt(0) > 127) {\n" + |
| " allowNumber = true;\n" + |
| " allowSep = true;\n" + |
| " } else if ('0' <= ch && ch <= '9'\n" + |
| " || ch == '-') {\n" + |
| " if (!allowNumber)\n" + |
| " return false;\n" + |
| " } else if (ch == '/' || ch == '.') {\n" + |
| " if (!allowSep)\n" + |
| " return false;\n" + |
| " allowNumber = false;\n" + |
| " allowSep = false;\n" + |
| " if (ch == '.')\n" + |
| " seenDot = true;\n" + |
| " if (ch == '/' && seenDot)\n" + |
| " return false;\n" + |
| " } else {\n" + |
| " return false;\n" + |
| " }\n" + |
| " }\n" + |
| " return true;\n" + |
| " }\n" + |
| " function loadFrames() {\n" + |
| " if (targetPage != \"\" && targetPage != \"undefined\")\n" + |
| " top.classFrame.location = top.targetPage;\n" + |
| " }\n"; |
| RawHtml scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); |
| scriptTree.addContent(scriptContent); |
| return scriptTree; |
| } |
| |
| /** |
| * Returns an HtmlTree for the BODY tag. |
| * |
| * @param includeScript set true if printing windowtitle script |
| * @param title title for the window |
| * @return an HtmlTree for the BODY tag |
| */ |
| public HtmlTree getBody(boolean includeScript, String title) { |
| HtmlTree body = new HtmlTree(HtmlTag.BODY); |
| // Set window title string which is later printed |
| this.winTitle = title; |
| // Don't print windowtitle script for overview-frame, allclasses-frame |
| // and package-frame |
| if (includeScript) { |
| this.script = getWinTitleScript(); |
| body.addContent(script); |
| Content noScript = HtmlTree.NOSCRIPT( |
| HtmlTree.DIV(configuration.getContent("doclet.No_Script_Message"))); |
| body.addContent(noScript); |
| } |
| return body; |
| } |
| |
| /** |
| * Generated javascript variables for the document. |
| * |
| * @param typeMap map comprising of method and type relationship |
| * @param tabTypes set comprising of all table tab types for this class |
| * @param elementName packages or methods table for which tabs need to be displayed |
| */ |
| public void generateTableTabTypesScript(Map<String,Integer> typeMap, |
| Set<? extends TableTabTypes> tabTypes, String elementName) { |
| String sep = ""; |
| StringBuilder vars = new StringBuilder("var "); |
| vars.append(elementName) |
| .append(" = {"); |
| for (Map.Entry<String,Integer> entry : typeMap.entrySet()) { |
| vars.append(sep); |
| sep = ","; |
| vars.append("\"") |
| .append(entry.getKey()) |
| .append("\":") |
| .append(entry.getValue()); |
| } |
| vars.append("};").append(DocletConstants.NL); |
| sep = ""; |
| vars.append("var tabs = {"); |
| for (TableTabTypes entry : tabTypes) { |
| vars.append(sep); |
| sep = ","; |
| vars.append(entry.tableTabs().value()) |
| .append(":") |
| .append("[") |
| .append("\"") |
| .append(entry.tableTabs().tabId()) |
| .append("\"") |
| .append(sep) |
| .append("\"") |
| .append(configuration.getText(entry.tableTabs().resourceKey())) |
| .append("\"]"); |
| } |
| vars.append("};") |
| .append(DocletConstants.NL); |
| addStyles(HtmlStyle.altColor, vars); |
| addStyles(HtmlStyle.rowColor, vars); |
| addStyles(HtmlStyle.tableTab, vars); |
| addStyles(HtmlStyle.activeTableTab, vars); |
| script.addContent(new RawHtml(vars)); |
| } |
| |
| /** |
| * Adds javascript style variables to the document. |
| * |
| * @param style style to be added as a javascript variable |
| * @param vars variable string to which the style variable will be added |
| */ |
| public void addStyles(HtmlStyle style, StringBuilder vars) { |
| vars.append("var ").append(style).append(" = \"").append(style) |
| .append("\";").append(DocletConstants.NL); |
| } |
| |
| /** |
| * Returns an HtmlTree for the TITLE tag. |
| * |
| * @return an HtmlTree for the TITLE tag |
| */ |
| public HtmlTree getTitle() { |
| HtmlTree title = HtmlTree.TITLE(new StringContent(winTitle)); |
| return title; |
| } |
| |
| /* |
| * Returns a header for Modifier and Type column of a table. |
| */ |
| public String getModifierTypeHeader() { |
| return modifierTypeHeader; |
| } |
| } |