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