update from master
authorNiki Roo <niki@nikiroo.be>
Sun, 17 May 2020 20:02:52 +0000 (22:02 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 17 May 2020 20:02:52 +0000 (22:02 +0200)
30 files changed:
data/MetaData.java
library/BasicLibrary.java
library/LocalLibrary.java
library/WebLibraryServerHtml.java
library/web/index.post.html [deleted file]
library/web/index.pre.html
library/web/package-info.java [new file with mode: 0644]
library/web/style.css
library/web/templates/WebLibraryServerTemplates.java [new file with mode: 0644]
library/web/templates/bookline.html [new file with mode: 0644]
library/web/templates/browser.html [new file with mode: 0644]
library/web/templates/browser.option.html [new file with mode: 0644]
library/web/templates/browser.select.html [new file with mode: 0644]
library/web/templates/index.banner.html [new file with mode: 0644]
library/web/templates/index.post.html [new file with mode: 0644]
library/web/templates/package-info.java [new file with mode: 0644]
library/web/templates/viewer.desc.html [new file with mode: 0644]
library/web/templates/viewer.descline.html [new file with mode: 0644]
library/web/templates/viewer.image.html [new file with mode: 0644]
library/web/templates/viewer.link.html [new file with mode: 0644]
library/web/templates/viewer.navbar.html [new file with mode: 0644]
library/web/templates/viewer.optionbar.button.html [new file with mode: 0644]
library/web/templates/viewer.optionbar.html [new file with mode: 0644]
library/web/templates/viewer.text.html [new file with mode: 0644]
output/BasicOutput.java
output/InfoCover.java
reader/TextOutput.java
supported/BasicSupportPara.java
supported/InfoReader.java
supported/Text.java

index bcebf754b7dc2b6ee71204d9aaf8a1efe2c20dbf..2e34ef98ad27bda10ff34a009fa3d3d314aaf6b2 100644 (file)
@@ -9,6 +9,12 @@ import be.nikiroo.utils.StringUtils;
 
 /**
  * The meta data associated to a {@link Story} object.
+ * <p>
+ * Note that some earlier version of the program did not save the resume as an
+ * external file; for those stories, the resume is not fetched until the story
+ * is.
+ * <p>
+ * The cover is never fetched until the story is.
  * 
  * @author niki
  */
@@ -120,6 +126,10 @@ public class MetaData implements Cloneable, Comparable<MetaData>, Serializable {
         * The story resume (a.k.a. description).
         * <p>
         * This can be NULL if we don't have a resume for this {@link Story}.
+        * <p>
+        * Note that some earlier version of the program did not save the resume as
+        * an external file; for those stories, the resume is not fetched until the
+        * story is.
         * 
         * @return the resume
         */
@@ -129,6 +139,10 @@ public class MetaData implements Cloneable, Comparable<MetaData>, Serializable {
 
        /**
         * The story resume (a.k.a. description).
+        * <p>
+        * Note that some earlier version of the program did not save the resume as
+        * an external file; for those stories, the resume is not fetched until the
+        * story is.
         * 
         * @param resume
         *            the resume to set
@@ -139,6 +153,8 @@ public class MetaData implements Cloneable, Comparable<MetaData>, Serializable {
 
        /**
         * The cover image of the story if any (can be NULL).
+        * <p>
+        * The cover is not fetched until the story is.
         * 
         * @return the cover
         */
@@ -148,6 +164,8 @@ public class MetaData implements Cloneable, Comparable<MetaData>, Serializable {
 
        /**
         * The cover image of the story if any (can be NULL).
+        * <p>
+        * The cover is not fetched until the story is.
         * 
         * @param cover
         *            the cover to set
index 8b72f19b3a92ad1c1d7ada09d915440596330ee2..f77d0edcef5ae64b186942be2a6048fa7eca7745 100644 (file)
@@ -475,6 +475,8 @@ abstract public class BasicLibrary {
 
        /**
         * Retrieve a specific {@link Story}.
+        * <p>
+        * Note that it will update both the cover and the resume in <tt>meta</tt>.
         * 
         * @param luid
         *            the Library UID of the story
@@ -513,6 +515,8 @@ abstract public class BasicLibrary {
 
        /**
         * Retrieve a specific {@link Story}.
+        * <p>
+        * Note that it will update both the cover and the resume in <tt>meta</tt>.
         * 
         * @param luid
         *            the LUID of the story
index f655d4d03bb43b5df69d00fc8b30b2adbad6c113..25f2ec960627ab354295289f73a7c93d6bbbe3ed 100644 (file)
@@ -625,6 +625,18 @@ public class LocalLibrary extends BasicLibrary {
                        files.add(coverFile);
                }
 
+               String summaryExt = ".summary";
+               File summaryFile = new File(path + summaryExt);
+               if (!summaryFile.exists()) {
+                       summaryFile = new File(
+                                       path.substring(0, path.length() - fileExt.length())
+                                                       + summaryExt);
+               }
+
+               if (summaryFile.exists()) {
+                       files.add(summaryFile);
+               }
+
                return files;
        }
 
index 8895fb83a07b0eb6ff7116b3998a7a89a2acfb15..69d8671736d7e2e4cf8c2922ca61358803f6bd2f 100644 (file)
@@ -22,6 +22,7 @@ import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
 import be.nikiroo.fanfix.data.Story;
 import be.nikiroo.fanfix.library.WebLibraryServer.WLoginResult;
 import be.nikiroo.fanfix.library.web.WebLibraryServerIndex;
+import be.nikiroo.fanfix.library.web.templates.WebLibraryServerTemplates;
 import be.nikiroo.fanfix.reader.TextOutput;
 import be.nikiroo.utils.IOUtils;
 import be.nikiroo.utils.NanoHTTPD;
@@ -173,13 +174,13 @@ abstract class WebLibraryServerHtml implements Runnable {
                                }
 
                                Response rep = null;
-                               if (!login.isSuccess()
-                                               && WebLibraryUrls.isSupportedUrl(uri, true)) {
-                                       rep = loginPage(login, uri);
-                               }
+                               try {
+                                       if (!login.isSuccess()
+                                                       && WebLibraryUrls.isSupportedUrl(uri, true)) {
+                                               rep = loginPage(login, uri);
+                                       }
 
-                               if (rep == null) {
-                                       try {
+                                       if (rep == null) {
                                                if (WebLibraryUrls.isSupportedUrl(uri, false)) {
                                                        if (WebLibraryUrls.INDEX_URL.equals(uri)) {
                                                                rep = root(session, cookies, login);
@@ -253,13 +254,12 @@ abstract class WebLibraryServerHtml implements Runnable {
                                                                                NanoHTTPD.MIME_PLAINTEXT, "Not Found");
                                                        }
                                                }
-                                       } catch (Exception e) {
-                                               Instance.getInstance().getTraceHandler().error(
-                                                               new IOException("Cannot process web request",
-                                                                               e));
-                                               rep = newFixedLengthResponse(Status.INTERNAL_ERROR,
-                                                               NanoHTTPD.MIME_PLAINTEXT, "An error occured");
                                        }
+                               } catch (Exception e) {
+                                       Instance.getInstance().getTraceHandler().error(
+                                                       new IOException("Cannot process web request", e));
+                                       rep = newFixedLengthResponse(Status.INTERNAL_ERROR,
+                                                       NanoHTTPD.MIME_PLAINTEXT, "An error occured");
                                }
 
                                return rep;
@@ -309,31 +309,34 @@ abstract class WebLibraryServerHtml implements Runnable {
                this.tracer = tracer;
        }
 
-       private Response loginPage(WLoginResult login, String uri) {
+       private Response loginPage(WLoginResult login, String uri)
+                       throws IOException {
                StringBuilder builder = new StringBuilder();
 
-               appendPreHtml(builder, true);
+               builder.append(getTemplateIndexPreBanner(true));
 
                if (login.isBadLogin()) {
-                       builder.append("<div class='error'>Bad login or password</div>");
+                       builder.append(
+                                       "\t\t<div class='error'>Bad login or password</div>");
                } else if (login.isBadCookie()) {
-                       builder.append("<div class='error'>Your session timed out</div>");
+                       builder.append(
+                                       "\t\t<div class='error'>Your session timed out</div>");
                }
 
                if (WebLibraryUrls.LOGOUT_URL.equals(uri)) {
                        uri = WebLibraryUrls.INDEX_URL;
                }
 
+               builder.append("\t\t<form method='POST' action='" + uri
+                               + "' class='login'>\n");
                builder.append(
-                               "<form method='POST' action='" + uri + "' class='login'>\n");
-               builder.append(
-                               "<p>You must be logged into the system to see the stories.</p>");
-               builder.append("\t<input type='text' name='login' />\n");
-               builder.append("\t<input type='password' name='password' />\n");
-               builder.append("\t<input type='submit' value='Login' />\n");
-               builder.append("</form>\n");
+                               "\t\t\t<p>You must be logged into the system to see the stories.</p>");
+               builder.append("\t\t\t<input type='text' name='login' />\n");
+               builder.append("\t\t\t<input type='password' name='password' />\n");
+               builder.append("\t\t\t<input type='submit' value='Login' />\n");
+               builder.append("\t\t</form>\n");
 
-               appendPostHtml(builder);
+               builder.append(getTemplate("index.post"));
 
                return NanoHTTPD.newFixedLengthResponse(Status.FORBIDDEN,
                                NanoHTTPD.MIME_HTML, builder.toString());
@@ -345,7 +348,7 @@ abstract class WebLibraryServerHtml implements Runnable {
                MetaResultList result = new MetaResultList(metas(login));
                StringBuilder builder = new StringBuilder();
 
-               appendPreHtml(builder, true);
+               builder.append(getTemplateIndexPreBanner(true));
 
                Map<String, String> params = session.getParms();
 
@@ -369,45 +372,56 @@ abstract class WebLibraryServerHtml implements Runnable {
 
                // TODO: javascript in realtime, using visible=false + hide [submit]
 
-               builder.append("<form class='browser'>\n");
-               builder.append("<div class='breadcrumbs'>\n");
+               StringBuilder selects = new StringBuilder();
+               boolean sourcesSel = false;
+               boolean authorsSel = false;
+               boolean tagsSel = false;
 
-               builder.append("\t<select name='browser'>");
-               appendOption(builder, 2, "", "", browser);
-               appendOption(builder, 2, "Sources", "sources", browser);
-               appendOption(builder, 2, "Authors", "authors", browser);
-               appendOption(builder, 2, "Tags", "tags", browser);
-               builder.append("\t</select>\n");
+               String selectTemplate = getTemplate("browser.select");
 
                if (!browser.isEmpty()) {
-                       builder.append("\t<select name='browser2'>");
+                       StringBuilder options = new StringBuilder();
+
                        if (browser.equals("sources")) {
+                               sourcesSel = true;
                                filterSource = browser2.isEmpty() ? filterSource : browser2;
+
                                // TODO: if 1 group -> no group
-                               appendOption(builder, 2, "", "", browser2);
                                Map<String, List<String>> sources = result.getSourcesGrouped();
                                for (String source : sources.keySet()) {
-                                       appendOption(builder, 2, source, source, browser2);
+                                       options.append(
+                                                       getTemplateBrowserOption(source, source, browser2));
                                }
                        } else if (browser.equals("authors")) {
+                               authorsSel = true;
                                filterAuthor = browser2.isEmpty() ? filterAuthor : browser2;
+
                                // TODO: if 1 group -> no group
-                               appendOption(builder, 2, "", "", browser2);
                                Map<String, List<String>> authors = result.getAuthorsGrouped();
                                for (String author : authors.keySet()) {
-                                       appendOption(builder, 2, author, author, browser2);
+                                       options.append(
+                                                       getTemplateBrowserOption(author, author, browser2));
                                }
                        } else if (browser.equals("tags")) {
+                               tagsSel = true;
                                filterTag = browser2.isEmpty() ? filterTag : browser2;
-                               appendOption(builder, 2, "", "", browser2);
+
                                for (String tag : result.getTags()) {
-                                       appendOption(builder, 2, tag, tag, browser2);
+                                       options.append(
+                                                       getTemplateBrowserOption(tag, tag, browser2));
                                }
                        }
-                       builder.append("\t</select>\n");
+
+                       selects.append(selectTemplate //
+                                       .replace("${name}", "browser2") //
+                                       .replace("${value}", browser2) //
+                                       .replace("${options}", options.toString()) //
+                       );
                }
 
                if (!browser2.isEmpty()) {
+                       StringBuilder options = new StringBuilder();
+
                        if (browser.equals("sources")) {
                                filterSource = browser3.isEmpty() ? filterSource : browser3;
                                Map<String, List<String>> sourcesGrouped = result
@@ -415,12 +429,10 @@ abstract class WebLibraryServerHtml implements Runnable {
                                List<String> sources = sourcesGrouped.get(browser2);
                                if (sources != null && !sources.isEmpty()) {
                                        // TODO: single empty value
-                                       builder.append("\t<select name='browser3'>");
-                                       appendOption(builder, 2, "", "", browser3);
                                        for (String source : sources) {
-                                               appendOption(builder, 2, source, source, browser3);
+                                               options.append(getTemplateBrowserOption(source, source,
+                                                               browser3));
                                        }
-                                       builder.append("\t</select>\n");
                                }
                        } else if (browser.equals("authors")) {
                                filterAuthor = browser3.isEmpty() ? filterAuthor : browser3;
@@ -429,33 +441,30 @@ abstract class WebLibraryServerHtml implements Runnable {
                                List<String> authors = authorsGrouped.get(browser2);
                                if (authors != null && !authors.isEmpty()) {
                                        // TODO: single empty value
-                                       builder.append("\t<select name='browser3'>");
-                                       appendOption(builder, 2, "", "", browser3);
                                        for (String author : authors) {
-                                               appendOption(builder, 2, author, author, browser3);
+                                               options.append(getTemplateBrowserOption(author, author,
+                                                               browser3));
                                        }
-                                       builder.append("\t</select>\n");
                                }
                        }
+
+                       selects.append(selectTemplate //
+                                       .replace("${name}", "browser3") //
+                                       .replace("${value}", browser3) //
+                                       .replace("${options}", options.toString()) //
+                       );
                }
 
-               builder.append("\t<input type='submit' value='Select'/>\n");
-               builder.append("</div>\n");
+               String sel = "selected='selected'";
+               builder.append(getTemplate("browser") //
+                               .replace("${sourcesSelected}", sourcesSel ? sel : "") //
+                               .replace("${authorsSelected}", authorsSel ? sel : "") //
+                               .replace("${tagsSelected}", tagsSel ? sel : "") //
+                               .replace("${filter}", filter) //
+                               .replace("${selects}", selects.toString()) //
+               );
 
-               // TODO: javascript in realtime, using visible=false + hide [submit]
-               builder.append("<div class='filter'>\n");
-               builder.append("\t<span class='label'>Filter: </span>\n");
-               builder.append(
-                               "\t<input name='optionName'  type='hidden' value='filter' />\n");
-               builder.append("\t<input name='optionValue' type='text'   value='"
-                               + filter + "' place-holder='...' />\n");
-               builder.append("\t<input name='optionNo'  type='submit' value='x' />");
-               builder.append(
-                               "\t<input name='submit' type='submit' value='Filter' />\n");
-               builder.append("</div>\n");
-               builder.append("</form>\n");
-
-               builder.append("\t<div class='books'>");
+               builder.append("\t\t<div class='books'>\n");
                for (MetaData meta : result.getMetas()) {
                        if (!filter.isEmpty() && !meta.getTitle().toLowerCase()
                                        .contains(filter.toLowerCase())) {
@@ -478,38 +487,33 @@ abstract class WebLibraryServerHtml implements Runnable {
                                continue;
                        }
 
-                       builder.append("<div class='book_line'>");
-                       builder.append("<a href='");
-                       builder.append(
-                                       WebLibraryUrls.getViewUrl(meta.getLuid(), null, null));
-                       builder.append("'");
-                       builder.append(" class='link'>");
-
-                       if (lib.isCached(meta.getLuid())) {
-                               // â—‰ = &#9673;
-                               builder.append(
-                                               "<span class='cache_icon cached'>&#9673;</span>");
-                       } else {
-                               // â—‹ = &#9675;
-                               builder.append(
-                                               "<span class='cache_icon uncached'>&#9675;</span>");
-                       }
-                       builder.append("<span class='luid'>");
-                       builder.append(meta.getLuid());
-                       builder.append("</span>");
-                       builder.append("<span class='title'>");
-                       builder.append(meta.getTitle());
-                       builder.append("</span>");
-                       builder.append("<span class='author'>");
+                       String author = "";
                        if (meta.getAuthor() != null && !meta.getAuthor().isEmpty()) {
-                               builder.append("(").append(meta.getAuthor()).append(")");
+                               author = "(" + meta.getAuthor() + ")";
+                       }
+
+                       String cachedClass = "cached";
+                       String cached = "&#9673;";
+                       if (!lib.isCached(meta.getLuid())) {
+                               cachedClass = "uncached";
+                               cached = "&#9675;";
                        }
-                       builder.append("</span>");
-                       builder.append("</a></div>\n");
+
+                       builder.append(getTemplate("bookline") //
+                                       .replace("${href}",
+                                                       WebLibraryUrls.getViewUrl(meta.getLuid(), null,
+                                                                       null)) //
+                                       .replace("${luid}", meta.getLuid()) //
+                                       .replace("${title}", meta.getTitle()) //
+                                       .replace("${author}", author) //
+                                       .replace("${cachedClass}", cachedClass) //
+                                       .replace("${cached}", cached) //
+                       );
                }
-               builder.append("</div>");
+               builder.append("\t\t</div>\n");
+
+               builder.append(getTemplate("index.post"));
 
-               appendPostHtml(builder);
                return NanoHTTPD.newFixedLengthResponse(builder.toString());
        }
 
@@ -563,9 +567,6 @@ abstract class WebLibraryServerHtml implements Runnable {
                                                NanoHTTPD.MIME_PLAINTEXT, "Story not found");
                        }
 
-                       StringBuilder builder = new StringBuilder();
-                       appendPreHtml(builder, false);
-
                        // For images documents, always go to the images if not chap 0 desc
                        if (story.getMeta().isImageDocument()) {
                                if (chapter > 0 && paragraph <= 0)
@@ -586,7 +587,7 @@ abstract class WebLibraryServerHtml implements Runnable {
 
                        String first, previous, next, last;
 
-                       StringBuilder content = new StringBuilder();
+                       String viewer = "";
 
                        String disabledLeft = "";
                        String disabledRight = "";
@@ -604,35 +605,37 @@ abstract class WebLibraryServerHtml implements Runnable {
                                last = WebLibraryUrls.getViewUrl(luid,
                                                story.getChapters().size(), null);
 
-                               StringBuilder desc = new StringBuilder();
-
+                               String desc = "";
                                if (chapter <= 0) {
-                                       desc.append("<h1 class='title'>");
-                                       desc.append(story.getMeta().getTitle());
-                                       desc.append("</h1>\n");
-                                       desc.append("<div class='desc'>\n");
-                                       desc.append("\t<a href='" + next + "' class='cover'>\n");
-                                       desc.append("\t\t<img src='/story/" + luid + "/cover'/>\n");
-                                       desc.append("\t</a>\n");
-                                       desc.append("\t<table class='details'>\n");
+                                       StringBuilder desclines = new StringBuilder();
                                        Map<String, String> details = BasicLibrary
                                                        .getMetaDesc(story.getMeta());
                                        for (String key : details.keySet()) {
-                                               appendTableRow(desc, 2, key, details.get(key));
+                                               desclines.append(getTemplate("viewer.descline") //
+                                                               .replace("${key}", key) //
+                                                               .replace("${value}", details.get(key)) //
+                                               );
                                        }
-                                       desc.append("\t</table>\n");
-                                       desc.append("</div>\n");
-                                       desc.append("<h1 class='title'>Description</h1>\n");
+
+                                       desc = getTemplate("viewer.desc") //
+                                                       .replace("${title}", story.getMeta().getTitle()) //
+                                                       .replace("${href}", next) //
+                                                       .replace("${cover}",
+                                                                       WebLibraryUrls.getStoryUrlCover(luid)) //
+                                                       .replace("${details}", desclines.toString()) //
+                                       ;
                                }
 
-                               content.append("<div class='viewer text'>\n");
-                               content.append(desc);
-                               String description = new TextOutput(false).convert(chap,
-                                               chapter > 0);
-                               content.append(chap.getParagraphs().size() <= 0
-                                               ? "No content provided."
-                                               : description);
-                               content.append("</div>\n");
+                               viewer = getTemplate("viewer.text") //
+                                               .replace("${desc}", desc) //
+                               ;
+                               if (chap.getParagraphs().size() <= 0) {
+                                       viewer = viewer.replace("${content}",
+                                                       "No content provided.");
+                               } else {
+                                       viewer = viewer.replace("${content}",
+                                                       new TextOutput(false).convert(chap, chapter > 0));
+                               }
 
                                if (chapter <= 0)
                                        disabledLeft = " disabled='disbaled'";
@@ -689,44 +692,39 @@ abstract class WebLibraryServerHtml implements Runnable {
                                                }
                                        }
 
-                                       String javascript = "document.getElementById(\"previous\").click(); return false;";
-                                       content.append(String.format("" //
-                                                       + "<a class='viewer link' oncontextmenu='%s' href='%s'>"
-                                                       + "<img class='viewer img' style='%s' src='%s'/>"
-                                                       + "</a>", //
-                                                       javascript, //
-                                                       next, //
-                                                       zoomStyle, //
-                                                       WebLibraryUrls.getStoryUrl(luid, chapter,
-                                                                       paragraph)));
+                                       viewer = getTemplate("viewer.image") //
+                                                       .replace("${href}", next) //
+                                                       .replace("${zoomStyle}", zoomStyle) //
+                                                       .replace("${src}", WebLibraryUrls.getStoryUrl(luid,
+                                                                       chapter, paragraph)) //
+                                       ;
                                } else {
-                                       content.append(String.format("" //
-                                                       + "<div class='viewer text'>%s</div>", //
-                                                       para.getContent()));
+                                       viewer = getTemplate("viewer.text") //
+                                                       .replace("${desc}", "") //
+                                                       .replace("${content}",
+                                                                       new TextOutput(false).convert(para)) //
+                                       ;
                                }
                        }
 
-                       builder.append(String.format("" //
-                                       + "<div class='bar navbar'>\n" //
-                                       + "\t<a%s class='button first' href='%s'>&lt;&lt;</a>\n"//
-                                       + "\t<a%s id='previous' class='button previous' href='%s'>&lt;</a>\n" //
-                                       + "\t<div class='gotobox itemsbox'>\n" //
-                                       + "\t\t<div class='button goto'>%d</div>\n" //
-                                       + "\t\t<div class='items goto'>\n", //
-                                       disabledLeft, first, //
-                                       disabledLeft, previous, //
-                                       paragraph > 0 ? paragraph : chapter //
-                       ));
-
                        // List of chap/para links
-
-                       appendItemA(builder, 3, WebLibraryUrls.getViewUrl(luid, 0, null),
-                                       "Description", paragraph == 0 && chapter == 0);
+                       StringBuilder links = new StringBuilder();
+                       links.append(getTemplate("viewer.link") //
+                                       .replace("${link}",
+                                                       WebLibraryUrls.getViewUrl(luid, 0, null)) //
+                                       .replace("${class}",
+                                                       paragraph == 0 && chapter == 0 ? "selected" : "") //
+                                       .replace("${name}", "Description") //
+                       );
                        if (paragraph > 0) {
                                for (int i = 1; i <= chap.getParagraphs().size(); i++) {
-                                       appendItemA(builder, 3,
-                                                       WebLibraryUrls.getViewUrl(luid, chapter, i),
-                                                       "Image " + i, paragraph == i);
+                                       links.append(getTemplate("viewer.link") //
+                                                       .replace("${link}",
+                                                                       WebLibraryUrls.getViewUrl(luid, chapter, i)) //
+                                                       .replace("${class}",
+                                                                       paragraph == i ? "selected" : "") //
+                                                       .replace("${name}", "Image " + i) //
+                                       );
                                }
                        } else {
                                int i = 1;
@@ -736,51 +734,79 @@ abstract class WebLibraryServerHtml implements Runnable {
                                                chapName += ": " + c.getName();
                                        }
 
-                                       appendItemA(builder, 3,
-                                                       WebLibraryUrls.getViewUrl(luid, i, null), chapName,
-                                                       chapter == i);
+                                       links.append(getTemplate("viewer.link") //
+                                                       .replace("${link}",
+                                                                       WebLibraryUrls.getViewUrl(luid, i, null)) //
+                                                       .replace("${class}", chapter == i ? "selected" : "") //
+                                                       .replace("${name}", chapName) //
+                                       );
 
                                        i++;
                                }
                        }
 
-                       builder.append(String.format("" //
-                                       + "\t\t</div>\n" //
-                                       + "\t</div>\n" //
-                                       + "\t<a%s class='button next' href='%s'>&gt;</a>\n" //
-                                       + "\t<a%s class='button last' href='%s'>&gt;&gt;</a>\n"//
-                                       + "</div>\n", //
-                                       disabledRight, next, //
-                                       disabledRight, last //
-                       ));
-
-                       builder.append(content);
+                       // Buttons on the optionbar
 
-                       builder.append("<div class='bar optionbar ");
+                       StringBuilder buttons = new StringBuilder();
+                       buttons.append(getTemplate("viewer.optionbar.button") //
+                                       .replace("${disabled}", "") //
+                                       .replace("${class}", "back") //
+                                       .replace("${href}", "/") //
+                                       .replace("${value}", "Back") //
+                       );
                        if (paragraph > 0) {
-                               builder.append("s4");
-                       } else {
-                               builder.append("s1");
+                               buttons.append(getTemplate("viewer.optionbar.button") //
+                                               .replace("${disabled}", disabledZoomReal) //
+                                               .replace("${class}", "zoomreal") //
+                                               .replace("${href}",
+                                                               uri + "?optionName=zoom&optionValue=real") //
+                                               .replace("${value}", "1:1") //
+                               );
+                               buttons.append(getTemplate("viewer.optionbar.button") //
+                                               .replace("${disabled}", disabledZoomWidth) //
+                                               .replace("${class}", "zoomwidth") //
+                                               .replace("${href}",
+                                                               uri + "?optionName=zoom&optionValue=width") //
+                                               .replace("${value}", "Width") //
+                               );
+                               buttons.append(getTemplate("viewer.optionbar.button") //
+                                               .replace("${disabled}", disabledZoomHeight) //
+                                               .replace("${class}", "zoomheight") //
+                                               .replace("${href}",
+                                                               uri + "?optionName=zoom&optionValue=height") //
+                                               .replace("${value}", "Height") //
+                               );
                        }
-                       builder.append("'>\n");
-                       builder.append("        <a class='button back' href='/'>BACK</a>\n");
 
-                       if (paragraph > 0) {
-                               builder.append(String.format("" //
-                                               + "\t<a%s class='button zoomreal'   href='%s'>REAL</a>\n"//
-                                               + "\t<a%s class='button zoomwidth'  href='%s'>WIDTH</a>\n"//
-                                               + "\t<a%s class='button zoomheight' href='%s'>HEIGHT</a>\n"//
-                                               + "</div>\n", //
-                                               disabledZoomReal,
-                                               uri + "?optionName=zoom&optionValue=real", //
-                                               disabledZoomWidth,
-                                               uri + "?optionName=zoom&optionValue=width", //
-                                               disabledZoomHeight,
-                                               uri + "?optionName=zoom&optionValue=height" //
-                               ));
-                       }
+                       // Full content
+
+                       StringBuilder builder = new StringBuilder();
+
+                       builder.append(getTemplateIndexPreBanner(false));
+
+                       builder.append(getTemplate("viewer.navbar") //
+                                       .replace("${disabledFirst}", disabledLeft) //
+                                       .replace("${disabledPrevious}", disabledLeft) //
+                                       .replace("${disabledNext}", disabledRight) //
+                                       .replace("${disabledLast}", disabledRight) //
+                                       .replace("${hrefFirst}", first) //
+                                       .replace("${hrefPrevious}", previous) //
+                                       .replace("${hrefNext}", next) //
+                                       .replace("${hrefLast}", last) //
+                                       .replace("${current}",
+                                                       "" + (paragraph > 0 ? paragraph : chapter)) //
+                                       .replace("${links}", links.toString()) //
+                       );
+
+                       builder.append(viewer);
+
+                       builder.append(getTemplate("viewer.optionbar") //
+                                       .replace("${classSize}", (paragraph > 0 ? "s4" : "s1")) //
+                                       .replace("${buttons}", buttons.toString()) //
+                       );
+
+                       builder.append(getTemplate("index.post"));
 
-                       appendPostHtml(builder);
                        return NanoHTTPD.newFixedLengthResponse(Status.OK,
                                        NanoHTTPD.MIME_HTML, builder.toString());
                } catch (IOException e) {
@@ -799,22 +825,8 @@ abstract class WebLibraryServerHtml implements Runnable {
                return NanoHTTPD.newChunkedResponse(Status.OK, mimeType, in);
        }
 
-       private String getContentOf(String file) {
-               InputStream in = IOUtils.openResource(WebLibraryServerIndex.class,
-                               file);
-               if (in != null) {
-                       try {
-                               return IOUtils.readSmallStream(in);
-                       } catch (IOException e) {
-                               Instance.getInstance().getTraceHandler().error(
-                                               new IOException("Cannot get file: index.pre.html", e));
-                       }
-               }
-
-               return "";
-       }
-
-       private void appendPreHtml(StringBuilder builder, boolean banner) {
+       private String getTemplateIndexPreBanner(boolean banner)
+                       throws IOException {
                String favicon = "favicon.ico";
                String icon = Instance.getInstance().getUiConfig()
                                .getString(UiConfig.PROGRAM_ICON);
@@ -822,70 +834,44 @@ abstract class WebLibraryServerHtml implements Runnable {
                        favicon = "icon_" + icon.replace("-", "_") + ".png";
                }
 
-               builder.append(
-                               getContentOf("index.pre.html").replace("favicon.ico", favicon));
+               String html = getTemplate("index.pre") //
+                               .replace("${title}", "Fanfix") //
+                               .replace("${favicon}", favicon) //
+               ;
 
                if (banner) {
-                       builder.append("<div class='banner'>\n");
-                       builder.append("\t<img class='ico' src='/") //
-                                       .append(favicon) //
-                                       .append("'/>\n");
-                       builder.append("\t<h1>Fanfix</h1>\n");
-                       builder.append("\t<h2>") //
-                                       .append(Version.getCurrentVersion()) //
-                                       .append("</h2>\n");
-                       builder.append("</div>\n");
+                       html += getTemplate("index.banner") //
+                                       .replace("${favicon}", favicon) //
+                                       .replace("${version}",
+                                                       Version.getCurrentVersion().toString()) //
+                       ;
                }
-       }
 
-       private void appendPostHtml(StringBuilder builder) {
-               builder.append(getContentOf("index.post.html"));
+               return html;
        }
 
-       private void appendOption(StringBuilder builder, int depth, String name,
-                       String value, String selected) {
-               for (int i = 0; i < depth; i++) {
-                       builder.append("\t");
-               }
-               builder.append("<option value='").append(value).append("'");
+       private String getTemplateBrowserOption(String name, String value,
+                       String selected) throws IOException {
+               String selectedAttribute = "";
                if (value.equals(selected)) {
-                       builder.append(" selected='selected'");
-               }
-               builder.append(">").append(name).append("</option>\n");
-       }
-
-       private void appendTableRow(StringBuilder builder, int depth,
-                       String... tds) {
-               for (int i = 0; i < depth; i++) {
-                       builder.append("\t");
+                       selectedAttribute = " selected='selected'";
                }
 
-               int col = 1;
-               builder.append("<tr>");
-               for (String td : tds) {
-                       builder.append("<td class='col");
-                       builder.append(col++);
-                       builder.append("'>");
-                       builder.append(td);
-                       builder.append("</td>");
-               }
-               builder.append("</tr>\n");
+               return getTemplate("browser.option" //
+                               .replace("${value}", value) //
+                               .replace("${selected}", selectedAttribute) //
+                               .replace("${name}", name) //
+               );
        }
 
-       private void appendItemA(StringBuilder builder, int depth, String link,
-                       String name, boolean selected) {
-               for (int i = 0; i < depth; i++) {
-                       builder.append("\t");
-               }
-
-               builder.append("<a href='");
-               builder.append(link);
-               builder.append("' class='item goto");
-               if (selected) {
-                       builder.append(" selected");
+       private String getTemplate(String template) throws IOException {
+               // TODO: check if it is "slow" -> map cache
+               InputStream in = IOUtils.openResource(WebLibraryServerTemplates.class,
+                               template + ".html");
+               try {
+                       return IOUtils.readSmallStream(in);
+               } finally {
+                       in.close();
                }
-               builder.append("'>");
-               builder.append(name);
-               builder.append("</a>\n");
        }
 }
diff --git a/library/web/index.post.html b/library/web/index.post.html
deleted file mode 100644 (file)
index d4e0905..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-</div>
-</body>
\ No newline at end of file
index 18c1508b33c037b305024d392540e7644875ef30..1e626aba1c8c4902e4c50d7995c63587c48c506f 100644 (file)
@@ -40,9 +40,9 @@
        -->
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
-       <title>Fanfix</title>
+       <title>${title}</title>
        <link rel="stylesheet" type="text/css" href="/style.css" />
-       <link rel="icon" type="image/x-icon" href="/favicon.ico" />
+       <link rel="icon" type="image/x-icon" href="/${favicon}" />
 </head>
 <body>
-<div class='main'>
+       <div class='main'>
diff --git a/library/web/package-info.java b/library/web/package-info.java
new file mode 100644 (file)
index 0000000..69bff54
--- /dev/null
@@ -0,0 +1 @@
+package be.nikiroo.fanfix.library.web;
\ No newline at end of file
index 4196aeba5a52a69d1a23a7ccc38500a28470729e..b12a24fa6ea0c3018eb925200baa066d475aee75 100644 (file)
@@ -310,13 +310,13 @@ a.viewer.link:hover {
        display: block;
 }
 
-.desc .details .col1 {
+.desc .details .col.key {
        font-weight: bold;
        padding-left: 5px;
        padding-right: 5px; 
 }
 
-.desc .details .col2 {
+.desc .details .col.value {
        color: #AAA391;
 }
 
diff --git a/library/web/templates/WebLibraryServerTemplates.java b/library/web/templates/WebLibraryServerTemplates.java
new file mode 100644 (file)
index 0000000..482a1b8
--- /dev/null
@@ -0,0 +1,4 @@
+package be.nikiroo.fanfix.library.web.templates;
+
+public class WebLibraryServerTemplates {
+}
diff --git a/library/web/templates/bookline.html b/library/web/templates/bookline.html
new file mode 100644 (file)
index 0000000..9b1a6b7
--- /dev/null
@@ -0,0 +1 @@
+                       <div class='book_line'><a href='${href}' class='link'><span class='cache_icon ${cachedClass}'>${cached}</span><span class='luid'>${luid}</span><span class='title'>${title}</span><span class='author'>${author}</span></a></div>
diff --git a/library/web/templates/browser.html b/library/web/templates/browser.html
new file mode 100644 (file)
index 0000000..f3f3047
--- /dev/null
@@ -0,0 +1,18 @@
+               <form class='browser'>
+                       <div class='breadcrumbs'>
+                               <select name='browser'>
+                                       <option value=''></option>
+                                       <option value='sources' ${sourcesSelected}>Sources</option>
+                                       <option value='authors' ${authorsSelected}>Authors</option>
+                                       <option value='tags'    ${tagsSelected}>Tags</option>
+                               </select>
+${selects}                             <input type='submit' value='Select'/>
+                       </div>
+                       <div class='filter'>
+                               <span class='label'>Filter: </span>
+                               <input name='optionName'  type='hidden' value='filter' />
+                               <input name='optionValue' type='text'   value='${filter}' place-holder='...' />
+                               <input name='optionNo'    type='submit' value='x' />
+                               <input name='submit'      type='submit' value='Filter' />
+                       </div>
+               </form>
diff --git a/library/web/templates/browser.option.html b/library/web/templates/browser.option.html
new file mode 100644 (file)
index 0000000..49f7b5b
--- /dev/null
@@ -0,0 +1 @@
+                                       <option value='${value}' ${selected}>${name}</option>
diff --git a/library/web/templates/browser.select.html b/library/web/templates/browser.select.html
new file mode 100644 (file)
index 0000000..447d845
--- /dev/null
@@ -0,0 +1,3 @@
+                               <select name='${name}' value="${value}">
+                                       <option value=''></option>
+${options}                             </select>
diff --git a/library/web/templates/index.banner.html b/library/web/templates/index.banner.html
new file mode 100644 (file)
index 0000000..c2cd1e7
--- /dev/null
@@ -0,0 +1,5 @@
+               <div class='banner'>
+                       <img class='ico' src='/${favicon}'/>
+                       <h1>Fanfix</h1>
+                       <h2>${version}</h2>
+               </div>
diff --git a/library/web/templates/index.post.html b/library/web/templates/index.post.html
new file mode 100644 (file)
index 0000000..52ba19e
--- /dev/null
@@ -0,0 +1,2 @@
+       </div>
+</body>
\ No newline at end of file
diff --git a/library/web/templates/package-info.java b/library/web/templates/package-info.java
new file mode 100644 (file)
index 0000000..5d4f3b2
--- /dev/null
@@ -0,0 +1 @@
+package be.nikiroo.fanfix.library.web.templates;
\ No newline at end of file
diff --git a/library/web/templates/viewer.desc.html b/library/web/templates/viewer.desc.html
new file mode 100644 (file)
index 0000000..21cddc4
--- /dev/null
@@ -0,0 +1,9 @@
+                       <h1 class='title'>${title}</h1>
+                       <div class='desc'>
+                               <a href='${href}' class='cover'>
+                                       <img src='${cover}'/>
+                               </a>
+                               <table class='details'>
+${details}                             </table>
+                       </div>
+                       <h1 class='title'>Description</h1>
diff --git a/library/web/templates/viewer.descline.html b/library/web/templates/viewer.descline.html
new file mode 100644 (file)
index 0000000..9d61987
--- /dev/null
@@ -0,0 +1 @@
+                                       <tr><td class='col key'>${key}</td><td class='col value'>${value}</td></tr>
diff --git a/library/web/templates/viewer.image.html b/library/web/templates/viewer.image.html
new file mode 100644 (file)
index 0000000..2416516
--- /dev/null
@@ -0,0 +1,6 @@
+               <a 
+                 class='viewer link' 
+                 oncontextmenu='document.getElementById("previous").click(); return false;' 
+                 href='${href}'>
+                       <img class='viewer img' style='${zoomStyle}' src='${src}'/>
+               </a>
diff --git a/library/web/templates/viewer.link.html b/library/web/templates/viewer.link.html
new file mode 100644 (file)
index 0000000..5812c80
--- /dev/null
@@ -0,0 +1 @@
+                                       <a href='${link}' class='item goto ${class}'>${name}</a>
diff --git a/library/web/templates/viewer.navbar.html b/library/web/templates/viewer.navbar.html
new file mode 100644 (file)
index 0000000..59f35be
--- /dev/null
@@ -0,0 +1,11 @@
+               <div class='bar navbar'>
+                       <a ${disabledFirst} class='button first' href='${hrefFirst}'>&lt;&lt;</a>
+                       <a ${disabledPrevious} id='previous' class='button previous' href='${hrefPrevious}'>&lt;</a>
+                       <div class='gotobox itemsbox'>
+                               <div class='button goto'>${current}</div>
+                               <div class='items goto'>
+${links}                               </div>
+                       </div>
+                       <a ${disabledNext} class='button next' href='${hrefNext}'>&gt;</a>
+                       <a ${disabledLast} class='button last' href='${hrefLast}'>&gt;&gt;</a>
+               </div>
diff --git a/library/web/templates/viewer.optionbar.button.html b/library/web/templates/viewer.optionbar.button.html
new file mode 100644 (file)
index 0000000..b85f9a9
--- /dev/null
@@ -0,0 +1 @@
+                       <a ${disabled} class='button ${class}' href='${href}'>${value}</a>
diff --git a/library/web/templates/viewer.optionbar.html b/library/web/templates/viewer.optionbar.html
new file mode 100644 (file)
index 0000000..1d1eaec
--- /dev/null
@@ -0,0 +1,2 @@
+               <div class='bar optionbar ${classSize}'>
+${buttons}             </div>
diff --git a/library/web/templates/viewer.text.html b/library/web/templates/viewer.text.html
new file mode 100644 (file)
index 0000000..4562ea4
--- /dev/null
@@ -0,0 +1,4 @@
+               <div class='viewer text'>
+${desc}                        <!-- The text is in HTML 3.2, so it can also work in Java Swing: -->
+                       ${content}
+               </div>
index 41634faaddbceabc89b4ad1be016c88bbaedc0de..62a008c001b8b3697671079ab34b839fef74bf31 100644 (file)
@@ -299,27 +299,21 @@ public abstract class BasicOutput {
                return "";
        }
 
-       @SuppressWarnings("unused")
        protected void writeStoryHeader(Story story) throws IOException {
        }
 
-       @SuppressWarnings("unused")
        protected void writeChapterHeader(Chapter chap) throws IOException {
        }
 
-       @SuppressWarnings("unused")
        protected void writeParagraphHeader(Paragraph para) throws IOException {
        }
 
-       @SuppressWarnings("unused")
        protected void writeStoryFooter(Story story) throws IOException {
        }
 
-       @SuppressWarnings("unused")
        protected void writeChapterFooter(Chapter chap) throws IOException {
        }
 
-       @SuppressWarnings("unused")
        protected void writeParagraphFooter(Paragraph para) throws IOException {
        }
 
index d8ca49a6876bcb1a759845d117b26cdd302bdfe6..fe530a852b1547ee498c0b66afa8e9fa0fe7a05f 100644 (file)
@@ -5,22 +5,45 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.util.Arrays;
 
 import be.nikiroo.fanfix.Instance;
 import be.nikiroo.fanfix.bundles.Config;
+import be.nikiroo.fanfix.data.Chapter;
 import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
 
+/**
+ * Helper class to write info, cover and summary (resume) files.
+ * 
+ * @author niki
+ */
 public class InfoCover {
+       /**
+        * Write both the <tt>.info<tt> and the <tt>.summary</tt> files by taking
+        * the information from the {@link MetaData}.
+        * 
+        * @param targetDir
+        *            the directory where to write the 2 files
+        * @param targetName
+        *            the target name (no extension) to use (so you will get
+        *            <tt>targetName.info</tt> and <tt>targetName.summary</tt>)
+        * @param meta
+        *            the {@link MetaData} to get the data out of
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
        public static void writeInfo(File targetDir, String targetName,
                        MetaData meta) throws IOException {
                File info = new File(targetDir, targetName + ".info");
 
-               BufferedWriter infoWriter = null;
-               try {
-                       infoWriter = new BufferedWriter(new OutputStreamWriter(
-                                       new FileOutputStream(info), "UTF-8"));
+               if (meta != null) {
+                       BufferedWriter infoWriter = null;
+                       try {
+                               infoWriter = new BufferedWriter(new OutputStreamWriter(
+                                               new FileOutputStream(info), "UTF-8"));
 
-                       if (meta != null) {
                                String tags = "";
                                if (meta.getTags() != null) {
                                        for (String tag : meta.getTags()) {
@@ -47,7 +70,8 @@ public class InfoCover {
                                writeMeta(infoWriter, "TYPE", meta.getType());
                                if (meta.getCover() != null) {
                                        String format = Instance.getInstance().getConfig()
-                                                       .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
+                                                       .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
+                                                       .toLowerCase();
                                        writeMeta(infoWriter, "COVER", targetName + "." + format);
                                } else {
                                        writeMeta(infoWriter, "COVER", "");
@@ -59,14 +83,69 @@ public class InfoCover {
                                writeMeta(infoWriter, "CREATION_DATE", meta.getCreationDate());
                                writeMeta(infoWriter, "FAKE_COVER",
                                                Boolean.toString(meta.isFakeCover()));
+                       } finally {
+                               if (infoWriter != null) {
+                                       infoWriter.close();
+                               }
                        }
-               } finally {
-                       if (infoWriter != null) {
-                               infoWriter.close();
+
+                       if (meta.getResume() != null) {
+                               Story fakeStory = new Story();
+                               fakeStory.setMeta(meta);
+                               fakeStory.setChapters(Arrays.asList(meta.getResume()));
+
+                               Text summaryText = new Text() {
+                                       @Override
+                                       protected boolean isWriteCover() {
+                                               return false;
+                                       }
+
+                                       @Override
+                                       protected boolean isWriteInfo() {
+                                               return false; // infinite loop if not!
+                                       }
+
+                                       @Override
+                                       public String getDefaultExtension(boolean readerTarget) {
+                                               return ".summary";
+                                       }
+
+                                       @Override
+                                       protected void writeStoryHeader(Story story)
+                                                       throws IOException {
+                                       }
+
+                                       @Override
+                                       protected void writeStoryFooter(Story story)
+                                                       throws IOException {
+                                       }
+
+                                       @Override
+                                       protected void writeChapterHeader(Chapter chap)
+                                                       throws IOException {
+                                       }
+
+                                       @Override
+                                       protected void writeChapterFooter(Chapter chap)
+                                                       throws IOException {
+                                       }
+                               };
+
+                               summaryText.process(fakeStory, targetDir, targetName);
                        }
                }
        }
 
+       /**
+        * Write the cover file.
+        * 
+        * @param targetDir
+        *            the target directory
+        * @param targetName
+        *            the target name for the cover (the extension will be added)
+        * @param meta
+        *            the meta to get the information out of
+        */
        public static void writeCover(File targetDir, String targetName,
                        MetaData meta) {
                if (meta != null && meta.getCover() != null) {
index 60b3a7f7c1db5d5ae40b3ebe4e5cde9754817869..732fced729b5a16d7c57e082e09ece9373ee9998 100644 (file)
@@ -145,4 +145,18 @@ public class TextOutput {
                }
                return builder.toString();
        }
+
+       /**
+        * Convert the paragraph into HTML3 code.
+        * 
+        * @param para
+        *            the {@link Paragraph} to convert
+        * 
+        * @return HTML3 code tested with Java Swing
+        */
+       public String convert(Paragraph para) {
+               Chapter fakeChapter = new Chapter(0, "");
+               fakeChapter.setParagraphs(Arrays.asList(para));
+               return convert(fakeChapter, false);
+       }
 }
index 1dbedc9cc326b0bdcb18e11753c8d78ccc611e22..e550d82ee0257ffb84bd8a9aee0eddf044d3c55e 100644 (file)
@@ -35,6 +35,17 @@ public class BasicSupportPara {
        BasicSupportHelper bsHelper;
        BasicSupportImages bsImages;
        
+       /**
+        * Create a new {@link BasicSupportPara}.
+        * <p>
+        * Note that you need an instance of both {@link BasicSupportHelper} and
+        * {@link BasicSupportImages} for it to work.
+        * 
+        * @param bsHelper
+        *            the required {@link BasicSupportHelper}
+        * @param bsImages
+        *            the required {@link BasicSupportImages}
+        */
        public BasicSupportPara(BasicSupportHelper bsHelper, BasicSupportImages bsImages) {
                this.bsHelper = bsHelper;
                this.bsImages = bsImages;
@@ -45,7 +56,7 @@ public class BasicSupportPara {
         * the content as it should be.
         * 
         * @param support
-        *            the linked {@link BasicSupport}
+        *            the linked {@link BasicSupport} (can be NULL)
         * @param source
         *            the source of the story (for image lookup in the same path if
         *            the source is a file, can be NULL)
index d5eeeb1d9190a022db4bf360cb243710decc493e..22afc92f8d3521bfc16ba05e38461ac2f4ef77a9 100644 (file)
@@ -11,27 +11,30 @@ import java.util.Scanner;
 
 import be.nikiroo.fanfix.Instance;
 import be.nikiroo.fanfix.bundles.Config;
+import be.nikiroo.fanfix.data.Chapter;
 import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.utils.IOUtils;
 import be.nikiroo.utils.Image;
 import be.nikiroo.utils.streams.MarkableFileInputStream;
 
-// not complete: no "description" tag
 public class InfoReader {
        static protected BasicSupportHelper bsHelper = new BasicSupportHelper();
-       // static protected BasicSupportImages bsImages = new BasicSupportImages();
-       // static protected BasicSupportPara bsPara = new BasicSupportPara(new
-       // BasicSupportHelper(), new BasicSupportImages());
+       static protected BasicSupportImages bsImages = new BasicSupportImages();
+       static protected BasicSupportPara bsPara = new BasicSupportPara(
+                       new BasicSupportHelper(), new BasicSupportImages());
 
        public static MetaData readMeta(File infoFile, boolean withCover)
                        throws IOException {
                if (infoFile == null) {
                        throw new IOException("File is null");
                }
+               
+               MetaData meta = null;
 
                if (infoFile.exists()) {
                        InputStream in = new MarkableFileInputStream(infoFile);
                        try {
-                               MetaData meta = createMeta(infoFile.toURI().toURL(), in,
+                               meta = createMeta(infoFile.toURI().toURL(), in,
                                                withCover);
 
                                // Some old .info files were using UUID for URL...
@@ -46,8 +49,6 @@ public class InfoReader {
                                // formats have a copy of the original text file)
                                if (!hasIt(meta.getTitle(), meta.getAuthor(), meta.getDate(),
                                                meta.getUrl())) {
-
-                                       // TODO: not nice, would be better to do it properly...
                                        String base = infoFile.getPath();
                                        if (base.endsWith(".info")) {
                                                base = base.substring(0,
@@ -62,15 +63,34 @@ public class InfoReader {
                                        }
 
                                        completeMeta(textFile, meta);
-                                       //
                                }
 
-                               return meta;
+                               
                        } finally {
                                in.close();
                        }
                }
 
+               if (meta != null) {
+                       try {
+                               File summaryFile = new File(infoFile.getAbsolutePath()
+                                               .replaceFirst("\\.info$", ".summary"));
+                               InputStream in = new MarkableFileInputStream(summaryFile);
+                               try {
+                                       String content = IOUtils.readSmallStream(in);
+                                       Chapter desc = bsPara.makeChapter(null, null, 0,
+                                                       "Description", content, false, null);
+                                       meta.setResume(desc);
+                               } finally {
+                                       in.close();
+                               }
+                       } catch (IOException e) {
+                               // ignore absent or bad summary
+                       }
+                       
+                       return meta;
+               }
+
                throw new FileNotFoundException(
                                "File given as argument does not exists: "
                                                + infoFile.getAbsolutePath());
@@ -90,6 +110,7 @@ public class InfoReader {
         */
        static public void completeMeta(File textFile,
                        MetaData meta)  throws IOException {
+               // TODO: not nice, would be better to do it properly...
                if (textFile != null && textFile.exists()) {
                        final URL source = textFile.toURI().toURL();
                        final MetaData[] superMetaA = new MetaData[1];
index 232eab6ec4f7736b6b470011f51d09548fe733e8..71e30c3252220c76f6ae5724e9632d33e67878cf 100644 (file)
@@ -15,9 +15,7 @@ import org.jsoup.nodes.Document;
 
 import be.nikiroo.fanfix.Instance;
 import be.nikiroo.fanfix.bundles.Config;
-import be.nikiroo.fanfix.data.Chapter;
 import be.nikiroo.fanfix.data.MetaData;
-import be.nikiroo.fanfix.data.Paragraph;
 import be.nikiroo.utils.Image;
 import be.nikiroo.utils.ImageUtils;
 import be.nikiroo.utils.Progress;
@@ -172,20 +170,7 @@ class Text extends BasicSupport {
 
        @Override
        protected String getDesc() throws IOException {
-               String content = getChapterContent(null, 0, null).trim();
-               if (!content.isEmpty()) {
-                       Chapter desc = bsPara.makeChapter(this, null, 0, "Description",
-                                       content, isHtml(), null);
-                       StringBuilder builder = new StringBuilder();
-                       for (Paragraph para : desc) {
-                               if (builder.length() > 0) {
-                                       builder.append("\n");
-                               }
-                               builder.append(para.getContent());
-                       }
-               }
-
-               return content;
+               return getChapterContent(null, 0, null).trim();
        }
 
        protected Image getCover(File sourceFile) {