Skip to content

Commit 1919aa1

Browse files
committed
Load partial handlebars templates from Library
1 parent 29082b4 commit 1919aa1

1 file changed

Lines changed: 53 additions & 29 deletions

File tree

src/main/java/net/rptools/maptool/util/HandlebarsUtil.java

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,24 @@
2525
import com.github.jknack.handlebars.helper.ext.AssignHelper;
2626
import com.github.jknack.handlebars.helper.ext.IncludeHelper;
2727
import com.github.jknack.handlebars.helper.ext.NumberHelper;
28+
import com.github.jknack.handlebars.io.AbstractTemplateLoader;
2829
import com.github.jknack.handlebars.io.ClassPathTemplateLoader;
2930
import com.github.jknack.handlebars.io.TemplateLoader;
30-
import com.github.jknack.handlebars.io.URLTemplateLoader;
31+
import com.github.jknack.handlebars.io.TemplateSource;
3132
import java.io.File;
3233
import java.io.IOException;
34+
import java.net.URI;
35+
import java.net.URISyntaxException;
3336
import java.net.URL;
37+
import java.nio.charset.Charset;
3438
import java.nio.charset.StandardCharsets;
3539
import java.nio.file.Path;
3640
import java.util.Arrays;
3741
import java.util.Base64;
42+
import javax.annotation.Nonnull;
3843
import net.rptools.maptool.model.Token;
44+
import net.rptools.maptool.model.library.Library;
45+
import net.rptools.maptool.model.library.LibraryManager;
3946
import org.apache.logging.log4j.LogManager;
4047
import org.apache.logging.log4j.Logger;
4148

@@ -52,50 +59,62 @@ public class HandlebarsUtil<T> {
5259
/** Logging class instance. */
5360
private static final Logger log = LogManager.getLogger(Token.class);
5461

62+
/** Handlebars partial template source that uses Add-On files */
63+
private static record LibraryTemplateSource(@Nonnull Library library, @Nonnull String filename)
64+
implements TemplateSource {
65+
@Override
66+
public long lastModified() {
67+
// No modification time is available.
68+
return -1;
69+
}
70+
71+
@Override
72+
@Nonnull
73+
public String content(@Nonnull final Charset charset) throws IOException {
74+
try {
75+
// The library API requires a URL even if it only uses the path.
76+
var url = new URI("lib", library.getNamespace().join(), filename, null).toURL();
77+
try (var is = library.read(url).join()) {
78+
return new String(is.readAllBytes(), charset);
79+
}
80+
} catch (URISyntaxException e) {
81+
throw new AssertionError("lib URL of namespace and filename should be valid", e);
82+
}
83+
}
84+
}
85+
5586
/** Handlebars partial template loader that uses Add-On Library URIs */
56-
private static class LibraryTemplateLoader extends URLTemplateLoader {
87+
private static class LibraryTemplateLoader extends AbstractTemplateLoader {
5788
/** Path to template being resolved, relative paths are resolved relative to its parent. */
58-
Path current;
89+
@Nonnull final Path current;
5990

60-
private LibraryTemplateLoader(String current, String prefix, String suffix) {
91+
@Nonnull final Library library;
92+
93+
private LibraryTemplateLoader(@Nonnull String current, @Nonnull Library library) {
6194
if (!current.startsWith("/")) {
6295
current = "/" + current;
6396
}
6497
this.current = new File(current).toPath();
65-
setPrefix(prefix);
66-
setSuffix(suffix);
98+
this.library = library;
99+
setPrefix(TemplateLoader.DEFAULT_PREFIX);
100+
setSuffix(TemplateLoader.DEFAULT_SUFFIX);
67101
}
68102

69-
private LibraryTemplateLoader(String current, String prefix) {
70-
this(current, prefix, DEFAULT_SUFFIX);
71-
}
72-
73-
private LibraryTemplateLoader(String current) {
74-
this(current, DEFAULT_PREFIX, DEFAULT_SUFFIX);
75-
}
76-
77-
/** Normalize locations by removing redundant path components */
103+
/** Resolve possibly relative uri to a new location relative to current rooted below prefix */
78104
@Override
79-
protected String normalize(final String location) {
80-
return new File(location).toPath().normalize().toString();
81-
}
82-
83-
/** Resolve possibly relative uri relative to current rooted below prefix */
84-
@Override
85-
public String resolve(final String uri) {
86-
var location = current.resolveSibling(uri).normalize().toString();
105+
@Nonnull
106+
public String resolve(@Nonnull final String path) {
107+
var location = current.resolveSibling(path).normalize().toString();
87108
if (location.startsWith("/")) {
88109
location = location.substring(1);
89110
}
90111
return getPrefix() + location + getSuffix();
91112
}
92113

93114
@Override
94-
protected URL getResource(String location) throws IOException {
95-
if (location.startsWith("/")) {
96-
location = location.substring(1);
97-
}
98-
return new URL("lib://" + location);
115+
@Nonnull
116+
public LibraryTemplateSource sourceAt(@Nonnull final String location) {
117+
return new LibraryTemplateSource(library, resolve(location));
99118
}
100119
}
101120

@@ -155,7 +174,12 @@ private HandlebarsUtil(String stringTemplate, TemplateLoader loader) throws IOEx
155174
* @throws IOException If there is an error compiling the template.
156175
*/
157176
public HandlebarsUtil(String stringTemplate, URL entry) throws IOException {
158-
this(stringTemplate, new LibraryTemplateLoader(entry.getHost() + entry.getPath()));
177+
this(
178+
stringTemplate,
179+
new LibraryTemplateLoader(
180+
entry.getPath(),
181+
// Template is defined by AddOn so library should always be present.
182+
new LibraryManager().getLibrary(entry).join().orElseThrow()));
159183
}
160184

161185
/**

0 commit comments

Comments
 (0)