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