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