--- /dev/null
+package be.nikiroo.fanfix.library;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import be.nikiroo.utils.IOUtils;
+import be.nikiroo.utils.StringUtils;
+import be.nikiroo.utils.streams.ReplaceInputStream;
+
+public class Template {
+ private Class<?> location;
+ private String name;
+
+ private Map<String, String> values = new HashMap<String, String>();
+ private Map<String, Template> valuesTemplate = new HashMap<String, Template>();
+ private Map<String, List<Template>> valuesTemplateList = new HashMap<String, List<Template>>();
+
+ public Template(Class<?> location, String name) {
+ this.location = location;
+ this.name = name;
+ }
+
+ public synchronized InputStream read() throws IOException {
+
+ String from[] = new String[values.size() + valuesTemplate.size()
+ + valuesTemplateList.size()];
+ String to[] = new String[from.length];
+
+ int i = 0;
+
+ for (String key : values.keySet()) {
+ from[i] = "${" + key + "}";
+ to[i] = values.get(key);
+
+ i++;
+ }
+ for (String key : valuesTemplate.keySet()) {
+ InputStream value = valuesTemplate.get(key).read();
+ try {
+ from[i] = "${" + key + "}";
+ to[i] = IOUtils.readSmallStream(value);
+ } finally {
+ value.close();
+ }
+
+ i++;
+ }
+ for (String key : valuesTemplateList.keySet()) {
+ List<Template> templates = valuesTemplateList.get(key);
+ StringBuilder value = new StringBuilder();
+ for (Template template : templates) {
+ InputStream valueOne = template.read();
+ try {
+ value.append(IOUtils.readSmallStream(valueOne));
+ } finally {
+ valueOne.close();
+ }
+ }
+ from[i] = "${" + key + "}";
+ to[i] = value.toString();
+
+ i++;
+ }
+
+ InputStream in = IOUtils.openResource(location, name);
+
+ //TODO: pending fix in replace stream
+ String data = IOUtils.readSmallStream(in);
+ in.close();
+ for(i = 0 ; i < from.length;i++) {
+ data=data.replace(from[i], to[i]);
+ }
+
+ //in = new ReplaceInputStream(in, from, to);
+ in = new ByteArrayInputStream(StringUtils.getBytes(data));
+ // END TODO
+
+ return in;
+ }
+
+ public synchronized Template set(String key, String value) {
+ values.put(key, value);
+ valuesTemplate.remove(key);
+ valuesTemplateList.remove(key);
+ return this;
+ }
+
+ public synchronized Template set(String key, Template value) {
+ values.remove(key);
+ valuesTemplate.put(key, value);
+ valuesTemplateList.remove(key);
+ return this;
+ }
+
+ public synchronized Template set(String key, List<Template> value) {
+ values.remove(key);
+ valuesTemplate.remove(key);
+ valuesTemplateList.put(key, value);
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "[Template for %s with (%d,%d,%d) value(s) to replace]", name,
+ values.size(), valuesTemplate.size(),
+ valuesTemplateList.size());
+ }
+}
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
private NanoHTTPD server;
protected TraceHandler tracer = new TraceHandler();
+ WebLibraryServerTemplates templates = WebLibraryServerTemplates
+ .getInstance();
+
abstract protected WLoginResult login(String who, String cookie);
abstract protected WLoginResult login(String who, String key,
WLoginResult login) throws IOException {
BasicLibrary lib = Instance.getInstance().getLibrary();
MetaResultList result = new MetaResultList(metas(login));
- StringBuilder builder = new StringBuilder();
-
- builder.append(getTemplateIndexPreBanner(true));
Map<String, String> params = session.getParms();
// TODO: javascript in realtime, using visible=false + hide [submit]
- StringBuilder selects = new StringBuilder();
+ List<Template> selects = new ArrayList<Template>();
boolean sourcesSel = false;
boolean authorsSel = false;
boolean tagsSel = false;
- String selectTemplate = getTemplate("browser.select");
-
if (!browser.isEmpty()) {
- StringBuilder options = new StringBuilder();
+ List<Template> options = new ArrayList<Template>();
if (browser.equals("sources")) {
sourcesSel = true;
// TODO: if 1 group -> no group
Map<String, List<String>> sources = result.getSourcesGrouped();
for (String source : sources.keySet()) {
- options.append(
- getTemplateBrowserOption(source, source, browser2));
+ options.add(
+ templates.browserOption(source, source, browser2));
}
} else if (browser.equals("authors")) {
authorsSel = true;
// TODO: if 1 group -> no group
Map<String, List<String>> authors = result.getAuthorsGrouped();
for (String author : authors.keySet()) {
- options.append(
- getTemplateBrowserOption(author, author, browser2));
+ options.add(
+ templates.browserOption(author, author, browser2));
}
} else if (browser.equals("tags")) {
tagsSel = true;
filterTag = browser2.isEmpty() ? filterTag : browser2;
for (String tag : result.getTags()) {
- options.append(
- getTemplateBrowserOption(tag, tag, browser2));
+ options.add(templates.browserOption(tag, tag, browser2));
}
}
- selects.append(selectTemplate //
- .replace("${name}", "browser2") //
- .replace("${value}", browser2) //
- .replace("${options}", options.toString()) //
- );
+ selects.add(templates.browserSelect("browser2", browser2, options));
}
if (!browser2.isEmpty()) {
- StringBuilder options = new StringBuilder();
+ List<Template> options = new ArrayList<Template>();
if (browser.equals("sources")) {
filterSource = browser3.isEmpty() ? filterSource : browser3;
if (sources != null && !sources.isEmpty()) {
// TODO: single empty value
for (String source : sources) {
- options.append(getTemplateBrowserOption(source, source,
+ options.add(templates.browserOption(source, source,
browser3));
}
}
if (authors != null && !authors.isEmpty()) {
// TODO: single empty value
for (String author : authors) {
- options.append(getTemplateBrowserOption(author, author,
+ options.add(templates.browserOption(author, author,
browser3));
}
}
}
- selects.append(selectTemplate //
- .replace("${name}", "browser3") //
- .replace("${value}", browser3) //
- .replace("${options}", options.toString()) //
- );
+ selects.add(templates.browserSelect("browser3", browser3, options));
}
- 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()) //
- );
-
- builder.append("\t\t<div class='books'>\n");
+ List<Template> booklines = new ArrayList<Template>();
for (MetaData meta : result.getMetas()) {
if (!filter.isEmpty() && !meta.getTitle().toLowerCase()
.contains(filter.toLowerCase())) {
author = "(" + meta.getAuthor() + ")";
}
- String cachedClass = "cached";
- String cached = "◉";
- if (!lib.isCached(meta.getLuid())) {
- cachedClass = "uncached";
- cached = "○";
- }
-
- 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) //
- );
+ booklines.add(templates.bookline( //
+ meta.getLuid(), //
+ WebLibraryUrls.getViewUrl(meta.getLuid(), null, null), //
+ meta.getTitle(), //
+ author, //
+ lib.isCached(meta.getLuid()) //
+ ));
}
- builder.append("\t\t</div>\n");
-
- builder.append(getTemplate("index.post"));
- return NanoHTTPD.newFixedLengthResponse(builder.toString());
+ // Add the browser in front of the booklines
+ booklines.add(0, templates.browser(browser, filter, selects));
+
+ return newInputStreamResponse(NanoHTTPD.MIME_HTML,
+ templates.index(true, booklines).read());
}
private Response getViewer(Map<String, String> cookies, String uri,
return html;
}
- private String getTemplateBrowserOption(String name, String value,
- String selected) throws IOException {
- String selectedAttribute = "";
- if (value.equals(selected)) {
- selectedAttribute = " selected='selected'";
- }
-
- return getTemplate("browser.option" //
- .replace("${value}", value) //
- .replace("${selected}", selectedAttribute) //
- .replace("${name}", name) //
- );
- }
-
private String getTemplate(String template) throws IOException {
// TODO: check if it is "slow" -> map cache
InputStream in = IOUtils.openResource(WebLibraryServerTemplates.class,
package be.nikiroo.fanfix.library.web.templates;
+import java.util.List;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.bundles.UiConfig;
+import be.nikiroo.fanfix.library.Template;
+import be.nikiroo.utils.Version;
+
public class WebLibraryServerTemplates {
+ static private WebLibraryServerTemplates instance = new WebLibraryServerTemplates();
+
+ static public WebLibraryServerTemplates getInstance() {
+ return instance;
+ }
+
+ public Template bookline(String luid, String href, String title,
+ String author, boolean cached) {
+
+ String cachedClass = "cached";
+ String cachedValue = "◉";
+ if (!cached) {
+ cachedClass = "uncached";
+ cachedValue = "○";
+ }
+
+ return new Template(getClass(), "bookline.html") //
+ .set("href", href) //
+ .set("cachedClass", cachedClass) //
+ .set("cached", cachedValue) //
+ .set("luid", luid) //
+ .set("title", title) //
+ .set("author", author) //
+ ;
+ }
+
+ public Template browser(String selectedValue, String filter,
+ List<Template> selects) {
+ return new Template(getClass(), "browser.html") //
+ .set("sourcesSelected",
+ "sources".equals(selectedValue) ? "selected='selected'"
+ : "") //
+ .set("authorsSelected",
+ "authors".equals(selectedValue) ? "selected='selected'"
+ : "") //
+ .set("tagsSelected",
+ "tags".equals(selectedValue) ? "selected='selected'"
+ : "") //
+ .set("filter", filter) //
+ .set("selects", selects) //
+ ;
+ }
+
+ public Template browserOption(String name, String value,
+ String selectedValue) {
+ return new Template(getClass(), "browser.option.html") //
+ .set("value", value) //
+ .set("selected",
+ value.equals(selectedValue) ? "selected='selected'"
+ : "") //
+ .set("name", name) //
+ ;
+ }
+
+ public Template browserSelect(String name, String value,
+ List<Template> options) {
+ return new Template(getClass(), "browser.select.html") //
+ .set("name", name) //
+ .set("value", value) //
+ .set("options", options) //
+ ;
+ }
+
+ public Template index(boolean banner, List<Template> content) {
+ String favicon = "favicon.ico";
+ String icon = Instance.getInstance().getUiConfig()
+ .getString(UiConfig.PROGRAM_ICON);
+ if (icon != null) {
+ favicon = "icon_" + icon.replace("-", "_") + ".png";
+ }
+
+ Template index = new Template(getClass(), "index.html") //
+ .set("title", "Fanfix") //
+ .set("favicon", favicon) //
+ .set("content", content) //
+ ;
+
+ if (banner) {
+ index.set("banner", new Template(getClass(), "index.banner.html") //
+ .set("favicon", favicon) //
+ .set("version", Version.getCurrentVersion().toString()) //
+ );
+ } else {
+ index.set("banner", "");
+ }
+
+ return index;
+ }
+
+ public Template viewer(Template browser, List<Template> booklines) {
+ // TODO
+ return null;
+ }
+
+ public Template viewerImage(String src, String href, String zoomStyle) {
+ return new Template(getClass(), "viewer.image.html") //
+ .set("src", src) //
+ .set("href", href) //
+ .set("zoomStyle", zoomStyle) //
+ ;
+ }
+
+ public Template viewerText(List<Template> desc, List<Template> content) {
+ return new Template(getClass(), "viewer.text.html") //
+ .set("desc", desc) //
+ .set("content", content) //
+ ;
+ }
+
+ public Template viewerLink(String name, String link, String className) {
+ return new Template(getClass(), "viewer.link.html") //
+ .set("link", link) //
+ .set("class", className) //
+ .set("name", name) //
+ ;
+ }
+
+ public Template viewerNavbar(int current, List<Template> links,
+ String hrefFirst, String hrefPrevious, String hrefNext,
+ String hrefLast, boolean disabledFirst, boolean disabledPrevious,
+ boolean disabledNext, boolean disabledLast) {
+ return new Template(getClass(), "viewer.navbar.html") //
+ .set("disabledFirst",
+ disabledFirst ? "disabled='disabled'" : "") //
+ .set("disabledPrevious",
+ disabledPrevious ? "disabled='disabled'" : "") //
+ .set("disabledNext", disabledNext ? "disabled='disabled'" : "") //
+ .set("disabledLast", disabledLast ? "disabled='disabled'" : "") //
+ .set("hrefFirst", hrefFirst) //
+ .set("hrefPrevious", hrefPrevious) //
+ .set("hrefNext", hrefNext) //
+ .set("hrefLast", hrefLast) //
+ .set("current", Integer.toString(current)) //
+ .set("links", links) //
+ ;
+ }
+
+ // numberOfButtons = 4 or 1 or the moment
+ public Template viewerOptionbar(int numberOfButtons,
+ List<Template> buttons) {
+ return new Template(getClass(), "viewer.optionbar.html") //
+ .set("classSize", "s" + numberOfButtons) //
+ .set("buttons", buttons) //
+ ;
+ }
+
+ public Template viewerOptionbarButton(String value, String href,
+ String className, boolean disabled) {
+ return new Template(getClass(), "viewer.optionbar.button.html") //
+ .set("disabled", disabled ? "disabled='disabled'" : "") //
+ .set("class", className) //
+ .set("href", href) //
+ .set("value", value) //
+ ;
+ }
}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<!--
+ Copyright 2020 David ROULET
+
+ This file is part of fanfix.
+
+ fanfix is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ fanfix is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with fanfix. If not, see <https://www.gnu.org/licenses/>.
+ ___________________________________________________________________________
+
+ This website was coded by:
+ A kangaroo.
+ _ _
+ (\\( \
+ `.\-.)
+ _...._ _,-" `-.
+\ ," `-._.- -.,-" . \
+ \`. ," `.
+ \ `-...__ / . .: y
+ `._ ``-...__ / ,"```-._/
+ `-._ ```-" | /_ //
+ `.._ _ ; <_ \ //
+ ``-.___ `. `-._ \ \ //
+ `- < `. (\ _/)/ `.\/ //
+ \ \ ` ^^^^^^^^^
+ ___________________________________________________________________________
+
+ -->
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>${title}</title>
+ <link rel="stylesheet" type="text/css" href="/style.css" />
+ <link rel="icon" type="image/x-icon" href="/${favicon}" />
+</head>
+<body>
+ <div class='main'>
+${banner}${content} </div>
+</body>
--- /dev/null
+${browser}${viewer}
\ No newline at end of file