1 /*
2  * Copyright (c) 1997, 2018, 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 
26 package jdk.javadoc.internal.doclets.formats.html;
27 
28 import jdk.javadoc.internal.doclets.formats.html.markup.Head;
29 import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
30 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
31 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
32 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
33 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
34 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
35 import jdk.javadoc.internal.doclets.formats.html.markup.Script;
36 import jdk.javadoc.internal.doclets.toolkit.Content;
37 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
38 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
39 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
40 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
41 
42 
43 /**
44  * Generate the documentation in the Html "frame" format in the browser. The
45  * generated documentation will have two or three frames depending upon the
46  * number of packages on the command line. In general there will be three frames
47  * in the output, a left-hand top frame will have a list of all packages with
48  * links to target left-hand bottom frame. The left-hand bottom frame will have
49  * the particular package contents or the all-classes list, where as the single
50  * right-hand frame will have overview or package summary or class file. Also
51  * take care of browsers which do not support Html frames.
52  *
53  *  <p><b>This is NOT part of any supported API.
54  *  If you write code that depends on this, you do so at your own risk.
55  *  This code and its internal interfaces are subject to change or
56  *  deletion without notice.</b>
57  *
58  * @author Atul M Dambalkar
59  */
60 public class FrameOutputWriter extends HtmlDocletWriter {
61 
62     /**
63      * Number of packages specified on the command line.
64      */
65     int noOfPackages;
66 
67     /**
68      * Constructor to construct FrameOutputWriter object.
69      *
70      * @param configuration for this run
71      * @param filename File to be generated.
72      */
FrameOutputWriter(HtmlConfiguration configuration, DocPath filename)73     public FrameOutputWriter(HtmlConfiguration configuration, DocPath filename) {
74         super(configuration, filename);
75         noOfPackages = configuration.packages.size();
76     }
77 
78     /**
79      * Construct FrameOutputWriter object and then use it to generate the Html
80      * file which will have the description of all the frames in the
81      * documentation. The name of the generated file is "index.html" which is
82      * the default first file for Html documents.
83      * @param configuration the configuration for this doclet
84      * @throws DocFileIOException if there is a problem generating the frame file
85      */
generate(HtmlConfiguration configuration)86     public static void generate(HtmlConfiguration configuration) throws DocFileIOException {
87         FrameOutputWriter framegen = new FrameOutputWriter(configuration, DocPaths.INDEX);
88         framegen.generateFrameFile();
89     }
90 
91     /**
92      * Generate the constants in the "index.html" file. Print the frame details
93      * as well as warning if browser is not supporting the Html frames.
94      * @throws DocFileIOException if there is a problem generating the frame file
95      */
generateFrameFile()96     protected void generateFrameFile() throws DocFileIOException {
97         Content frame = getFrameDetails();
98         HtmlTree body = new HtmlTree(HtmlTag.BODY);
99         body.addAttr(HtmlAttr.ONLOAD, "loadFrames()");
100         String topFilePath = configuration.topFile.getPath();
101         Script script = new Script(
102                 "\nif (targetPage == \"\" || targetPage == \"undefined\")\n" +
103                 "     window.location.replace(")
104                 .appendStringLiteral(topFilePath, '\'')
105                 .append(");\n");
106         body.addContent(script.asContent());
107         Content noScript = HtmlTree.NOSCRIPT(contents.noScriptMessage);
108         body.addContent(noScript);
109         if (configuration.allowTag(HtmlTag.MAIN)) {
110             HtmlTree main = HtmlTree.MAIN(frame);
111             body.addContent(main);
112         } else {
113             body.addContent(frame);
114         }
115         if (configuration.windowtitle.length() > 0) {
116             printFramesDocument(configuration.windowtitle, body);
117         } else {
118             printFramesDocument(resources.getText("doclet.Generated_Docs_Untitled"), body);
119         }
120     }
121 
122     /**
123      * Print the frames version of the Html file header.
124      * Called only when generating an HTML frames file.
125      *
126      * @param title Title of this HTML document
127      * @param body the body content tree to be added to the HTML document
128      * @throws DocFileIOException if there is an error writing the frames document
129      */
printFramesDocument(String title, HtmlTree body)130     private void printFramesDocument(String title, HtmlTree body) throws DocFileIOException {
131         DocType htmlDocType = DocType.forVersion(configuration.htmlVersion);
132         Content htmlComment = contents.newPage;
133         Head head = new Head(path, configuration.htmlVersion, configuration.docletVersion)
134                 .setTimestamp(!configuration.notimestamp)
135                 .setTitle(title)
136                 .setCharset(configuration.charset)
137                 .setStylesheets(configuration.getMainStylesheet(), configuration.getAdditionalStylesheets())
138                 .addDefaultScript(false)
139                 .addScript(getFramesScript());
140 
141         Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), head.toContent(), body);
142         HtmlDocument htmlDocument = new HtmlDocument(htmlDocType, htmlComment, htmlTree);
143         htmlDocument.write(DocFile.createFileForOutput(configuration, path));
144    }
145 
146     /**
147      * Get the frame sizes and their contents.
148      *
149      * @return a content tree for the frame details
150      */
getFrameDetails()151     protected Content getFrameDetails() {
152         HtmlTree leftContainerDiv = new HtmlTree(HtmlTag.DIV);
153         HtmlTree rightContainerDiv = new HtmlTree(HtmlTag.DIV);
154         leftContainerDiv.setStyle(HtmlStyle.leftContainer);
155         rightContainerDiv.setStyle(HtmlStyle.rightContainer);
156         if (configuration.showModules && configuration.modules.size() > 1) {
157             addAllModulesFrameTag(leftContainerDiv);
158         } else if (noOfPackages > 1) {
159             addAllPackagesFrameTag(leftContainerDiv);
160         }
161         addAllClassesFrameTag(leftContainerDiv);
162         addClassFrameTag(rightContainerDiv);
163         HtmlTree mainContainer = HtmlTree.DIV(HtmlStyle.mainContainer, leftContainerDiv);
164         mainContainer.addContent(rightContainerDiv);
165         return mainContainer;
166     }
167 
168     /**
169      * Add the IFRAME tag for the frame that lists all modules.
170      *
171      * @param contentTree to which the information will be added
172      */
addAllModulesFrameTag(Content contentTree)173     private void addAllModulesFrameTag(Content contentTree) {
174         HtmlTree frame = HtmlTree.IFRAME(DocPaths.MODULE_OVERVIEW_FRAME.getPath(),
175                 "packageListFrame", resources.getText("doclet.All_Modules"));
176         HtmlTree leftTop = HtmlTree.DIV(HtmlStyle.leftTop, frame);
177         contentTree.addContent(leftTop);
178     }
179 
180     /**
181      * Add the IFRAME tag for the frame that lists all packages.
182      *
183      * @param contentTree the content tree to which the information will be added
184      */
addAllPackagesFrameTag(Content contentTree)185     private void addAllPackagesFrameTag(Content contentTree) {
186         HtmlTree frame = HtmlTree.IFRAME(DocPaths.OVERVIEW_FRAME.getPath(),
187                 "packageListFrame", resources.getText("doclet.All_Packages"));
188         HtmlTree leftTop = HtmlTree.DIV(HtmlStyle.leftTop, frame);
189         contentTree.addContent(leftTop);
190     }
191 
192     /**
193      * Add the IFRAME tag for the frame that lists all classes.
194      *
195      * @param contentTree the content tree to which the information will be added
196      */
addAllClassesFrameTag(Content contentTree)197     private void addAllClassesFrameTag(Content contentTree) {
198         HtmlTree frame = HtmlTree.IFRAME(DocPaths.ALLCLASSES_FRAME.getPath(),
199                 "packageFrame", resources.getText("doclet.All_classes_and_interfaces"));
200         HtmlTree leftBottom = HtmlTree.DIV(HtmlStyle.leftBottom, frame);
201         contentTree.addContent(leftBottom);
202     }
203 
204     /**
205      * Add the IFRAME tag for the frame that describes the class in detail.
206      *
207      * @param contentTree the content tree to which the information will be added
208      */
addClassFrameTag(Content contentTree)209     private void addClassFrameTag(Content contentTree) {
210         HtmlTree frame = HtmlTree.IFRAME(configuration.topFile.getPath(), "classFrame",
211                 resources.getText("doclet.Package_class_and_interface_descriptions"));
212         frame.setStyle(HtmlStyle.rightIframe);
213         contentTree.addContent(frame);
214     }
215 
216     /**
217      * Returns a content tree for the SCRIPT tag for the main page(index.html).
218      *
219      * @return a content for the SCRIPT tag
220      */
getFramesScript()221     protected Script getFramesScript() {
222         return new Script("\n" +
223                 "    tmpTargetPage = \"\" + window.location.search;\n" +
224                 "    if (tmpTargetPage != \"\" && tmpTargetPage != \"undefined\")\n" +
225                 "        tmpTargetPage = tmpTargetPage.substring(1);\n" +
226                 "    if (tmpTargetPage.indexOf(\":\") != -1 || (tmpTargetPage != \"\" && !validURL(tmpTargetPage)))\n" +
227                 "        tmpTargetPage = \"undefined\";\n" +
228                 "    targetPage = tmpTargetPage;\n" +
229                 "    function validURL(url) {\n" +
230                 "        try {\n" +
231                 "            url = decodeURIComponent(url);\n" +
232                 "        }\n" +
233                 "        catch (error) {\n" +
234                 "            return false;\n" +
235                 "        }\n" +
236                 "        var pos = url.indexOf(\".html\");\n" +
237                 "        if (pos == -1 || pos != url.length - 5)\n" +
238                 "            return false;\n" +
239                 "        var allowNumber = false;\n" +
240                 "        var allowSep = false;\n" +
241                 "        var seenDot = false;\n" +
242                 "        for (var i = 0; i < url.length - 5; i++) {\n" +
243                 "            var ch = url.charAt(i);\n" +
244                 "            if ('a' <= ch && ch <= 'z' ||\n" +
245                 "                    'A' <= ch && ch <= 'Z' ||\n" +
246                 "                    ch == '$' ||\n" +
247                 "                    ch == '_' ||\n" +
248                 "                    ch.charCodeAt(0) > 127) {\n" +
249                 "                allowNumber = true;\n" +
250                 "                allowSep = true;\n" +
251                 "            } else if ('0' <= ch && ch <= '9'\n" +
252                 "                    || ch == '-') {\n" +
253                 "                if (!allowNumber)\n" +
254                 "                     return false;\n" +
255                 "            } else if (ch == '/' || ch == '.') {\n" +
256                 "                if (!allowSep)\n" +
257                 "                    return false;\n" +
258                 "                allowNumber = false;\n" +
259                 "                allowSep = false;\n" +
260                 "                if (ch == '.')\n" +
261                 "                     seenDot = true;\n" +
262                 "                if (ch == '/' && seenDot)\n" +
263                 "                     return false;\n" +
264                 "            } else {\n" +
265                 "                return false;\n" +
266                 "            }\n" +
267                 "        }\n" +
268                 "        return true;\n" +
269                 "    }\n" +
270                 "    function loadFrames() {\n" +
271                 "        if (targetPage != \"\" && targetPage != \"undefined\")\n" +
272                 "             top.classFrame.location = top.targetPage;\n" +
273                 "    }\n");
274     }
275 }
276