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