Merge commit '929409950e82914aa3cee323cfa7c5007585d2ea'
[nikiroo-utils.git] / src / be / nikiroo / fanfix / output / Html.java
1 package be.nikiroo.fanfix.output;
2
3 import java.io.BufferedWriter;
4 import java.io.File;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStreamWriter;
9
10 import be.nikiroo.fanfix.Instance;
11 import be.nikiroo.fanfix.bundles.Config;
12 import be.nikiroo.fanfix.data.Chapter;
13 import be.nikiroo.fanfix.data.MetaData;
14 import be.nikiroo.fanfix.data.Paragraph;
15 import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
16 import be.nikiroo.fanfix.data.Story;
17 import be.nikiroo.utils.IOUtils;
18 import be.nikiroo.utils.StringUtils;
19
20 class Html extends BasicOutput {
21 private File dir;
22 protected BufferedWriter writer;
23 private boolean inDialogue = false;
24 private boolean inNormal = false;
25
26 @Override
27 public File process(Story story, File targetDir, String targetName)
28 throws IOException {
29 String targetNameOrig = targetName;
30
31 File target = new File(targetDir, targetName);
32 target.mkdir();
33 dir = target;
34
35 target = new File(targetDir, targetName + getDefaultExtension(true));
36
37 writer = new BufferedWriter(new OutputStreamWriter(
38 new FileOutputStream(target), "UTF-8"));
39 try {
40 super.process(story, targetDir, targetNameOrig);
41 } finally {
42 writer.close();
43 writer = null;
44 }
45
46 // write a copy of the originals inside
47 InfoCover.writeInfo(dir, targetName, story.getMeta());
48 InfoCover.writeCover(dir, targetName, story.getMeta());
49 BasicOutput.getOutput(OutputType.TEXT, isWriteInfo(), isWriteCover())
50 .process(story, dir, targetNameOrig);
51
52 if (story.getMeta().getCover() != null) {
53 Instance.getCache().saveAsImage(story.getMeta().getCover(),
54 new File(dir, "cover"), true);
55 }
56
57 return target;
58 }
59
60 @Override
61 public String getDefaultExtension(boolean readerTarget) {
62 if (readerTarget) {
63 return File.separator + "index.html";
64 }
65
66 return "";
67 }
68
69 @Override
70 protected void writeStoryHeader(Story story) throws IOException {
71 String title = "";
72 String tags = "";
73 String author = "";
74 Chapter resume = null;
75 if (story.getMeta() != null) {
76 MetaData meta = story.getMeta();
77 title = meta.getTitle();
78 resume = meta.getResume();
79 if (meta.getTags() != null) {
80 for (String tag : meta.getTags()) {
81 if (!tags.isEmpty()) {
82 tags += ", ";
83 }
84 tags += tag;
85 }
86
87 if (!tags.isEmpty()) {
88 tags = "(" + tags + ")";
89 }
90 }
91 author = meta.getAuthor();
92 }
93
94 String format = Instance.getConfig()
95 .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
96
97 InputStream inStyle = getClass().getResourceAsStream("html.style.css");
98 if (inStyle == null) {
99 throw new IOException("Cannot find style.css resource");
100 }
101 try {
102 IOUtils.write(inStyle, new File(dir, "style.css"));
103 } finally {
104 inStyle.close();
105 }
106
107 writer.write("<!DOCTYPE html>");
108 writer.write("\n<html>");
109 writer.write("\n<head>");
110 writer.write("\n <meta http-equiv='content-type' content='text/html; charset=utf-8'>");
111 writer.write("\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>");
112 writer.write("\n <link rel='stylesheet' type='text/css' href='style.css'>");
113 writer.write("\n <title>" + StringUtils.xmlEscape(title) + "</title>");
114 writer.write("\n</head>");
115 writer.write("\n<body>\n");
116
117 writer.write("\n <div class=\"titlepage\">");
118 writer.write("\n <h1>" + StringUtils.xmlEscape(title) + "</h1>");
119 writer.write("\n <div class=\"type\">" + StringUtils.xmlEscape(tags)
120 + "</div>");
121 writer.write("\n <div class=\"cover\">");
122 writer.write("\n <img src=\"cover." + format + "\"></img>");
123 writer.write("\n </div>");
124 writer.write("\n <div class=\"author\">"
125 + StringUtils.xmlEscape(author) + "</div>");
126 writer.write("\n </div>");
127
128 writer.write("\n <hr/><br/>");
129
130 if (resume != null) {
131 for (Paragraph para : resume) {
132 writeParagraph(para);
133 }
134 if (inDialogue) {
135 writer.write(" </div>\n");
136 inDialogue = false;
137 }
138 if (inNormal) {
139 writer.write(" </div>\n");
140 inNormal = false;
141 }
142 }
143
144 writer.write("\n <br/>");
145 }
146
147 @Override
148 protected void writeStoryFooter(Story story) throws IOException {
149 writer.write("</body>\n");
150 }
151
152 @Override
153 protected void writeChapterHeader(Chapter chap) throws IOException {
154 String nameOrNumber;
155 if (chap.getName() != null && !chap.getName().isEmpty()) {
156 nameOrNumber = chap.getName();
157 } else {
158 nameOrNumber = Integer.toString(chap.getNumber());
159 }
160
161 writer.write("\n <h2>");
162 writer.write("\n <span class='chap'>Chapter <span class='chapnumber'>"
163 + chap.getNumber() + "</span>:</span> ");
164 writer.write("\n <span class='chaptitle'>"
165 + StringUtils.xmlEscape(nameOrNumber) + "</span>");
166 writer.write("\n </h2>");
167 writer.write("\n ");
168 writer.write("\n <div class='chapter_content'>\n");
169
170 inDialogue = false;
171 inNormal = false;
172 }
173
174 @Override
175 protected void writeChapterFooter(Chapter chap) throws IOException {
176 if (inDialogue) {
177 writer.write(" </div>\n");
178 inDialogue = false;
179 }
180 if (inNormal) {
181 writer.write(" </div>\n");
182 inNormal = false;
183 }
184
185 writer.write("\n </div>");
186 }
187
188 @Override
189 protected void writeParagraphHeader(Paragraph para) throws IOException {
190 if (para.getType() == ParagraphType.QUOTE && !inDialogue) {
191 writer.write(" <div class='dialogues'>\n");
192 inDialogue = true;
193 } else if (para.getType() != ParagraphType.QUOTE && inDialogue) {
194 writer.write(" </div>\n");
195 inDialogue = false;
196 }
197
198 if (para.getType() == ParagraphType.NORMAL && !inNormal) {
199 writer.write(" <div class='normals'>\n");
200 inNormal = true;
201 } else if (para.getType() != ParagraphType.NORMAL && inNormal) {
202 writer.write(" </div>\n");
203 inNormal = false;
204 }
205
206 switch (para.getType()) {
207 case BLANK:
208 writer.write(" <div class='blank'></div>");
209 break;
210 case BREAK:
211 writer.write(" <hr class='break'/>");
212 break;
213 case NORMAL:
214 writer.write(" <span class='normal'>");
215 break;
216 case QUOTE:
217 writer.write(" <div class='dialogue'>&mdash; ");
218 break;
219 case IMAGE:
220 // TODO
221 writer.write("<a href='"
222 + StringUtils.xmlEscapeQuote(para.getContent()) + "'>"
223 + StringUtils.xmlEscape(para.getContent()) + "</a>");
224 break;
225 }
226 }
227
228 @Override
229 protected void writeParagraphFooter(Paragraph para) throws IOException {
230 switch (para.getType()) {
231 case NORMAL:
232 writer.write("</span>\n");
233 break;
234 case QUOTE:
235 writer.write("</div>\n");
236 break;
237 default:
238 writer.write("\n");
239 break;
240 }
241 }
242
243 @Override
244 protected void writeTextLine(ParagraphType type, String line)
245 throws IOException {
246 switch (type) {
247 case QUOTE:
248 case NORMAL:
249 writer.write(decorateText(StringUtils.xmlEscape(line)));
250 break;
251 default:
252 break;
253 }
254 }
255
256 @Override
257 protected String enbold(String word) {
258 return "<strong>" + word + "</strong>";
259 }
260
261 @Override
262 protected String italize(String word) {
263 return "<emph>" + word + "</emph>";
264 }
265 }