Skip to content

Package: BluetteGalleryAdapter

BluetteGalleryAdapter

nameinstructionbranchcomplexitylinemethod
BluetteGalleryAdapter(SiteNode, GalleryView, ModelFactory)
M: 91 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
createImageLink(String, int)
M: 18 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getInlinedScript()
M: 45 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
lambda$getInlinedScript$0(Key)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getInlinedScript$1(ResourceProperties, Key)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$toAggregate$2(Key, Object)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
prepare(GalleryViewController.GalleryItem, List, Template)
M: 135 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 25 C: 0
0%
M: 1 C: 0
0%
prepareCatalog(List)
M: 25 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
prepareFallbackGallery(GalleryViewController.GalleryItem, List)
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
prepareFallbackLightbox(List)
M: 49 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
prepareGallery(GalleryViewController.GalleryItem, List)
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
render(RenderContext)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 36 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
toAggregate(GalleryViewController.GalleryItem)
M: 32 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
toAggregate(ResourceProperties, Key)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * NorthernWind - lightweight CMS
5: * http://tidalwave.it/projects/northernwind
6: *
7: * Copyright (C) 2011 - 2025 Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/northernwind-src
22: * git clone https://github.com/tidalwave-it/northernwind-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.northernwind.frontend.ui.component.gallery.htmltemplate.bluette;
27:
28: import javax.annotation.Nonnegative;
29: import javax.annotation.Nonnull;
30: import java.util.List;
31: import java.util.Optional;
32: import it.tidalwave.util.Id;
33: import it.tidalwave.util.Key;
34: import it.tidalwave.northernwind.core.model.ModelFactory;
35: import it.tidalwave.northernwind.core.model.ResourcePath;
36: import it.tidalwave.northernwind.core.model.ResourceProperties;
37: import it.tidalwave.northernwind.core.model.Site;
38: import it.tidalwave.northernwind.core.model.SiteNode;
39: import it.tidalwave.northernwind.core.model.Template;
40: import it.tidalwave.northernwind.core.model.Template.Aggregate;
41: import it.tidalwave.northernwind.frontend.ui.RenderContext;
42: import it.tidalwave.northernwind.frontend.ui.component.htmltemplate.TextHolder;
43: import it.tidalwave.northernwind.frontend.ui.component.gallery.GalleryView;
44: import it.tidalwave.northernwind.frontend.ui.component.gallery.GalleryViewController.GalleryItem;
45: import it.tidalwave.northernwind.frontend.ui.component.gallery.spi.GalleryAdapterSupport;
46: import lombok.extern.slf4j.Slf4j;
47: import static it.tidalwave.northernwind.core.model.Template.Aggregates.toAggregates;
48:
49: /***************************************************************************************************************************************************************
50: *
51: * @author Fabrizio Giudici
52: *
53: **************************************************************************************************************************************************************/
54: @Slf4j
55: public class BluetteGalleryAdapter extends GalleryAdapterSupport
56: {
57: private static final Key<String> P_COPYRIGHT = Key.of("copyright", String.class);
58:
59: private static final Key<ResourcePath> P_BLUETTE_TEMPLATE_PATH = Key.of("bluettePath", ResourcePath.class);
60:
61: /** The path to the template for fallback rendering of a single gallery page, when JavaScript is not available. */
62: private static final Key<ResourcePath> P_BLUETTE_FALLBACK_TEMPLATE_PATH = Key.of("bluetteFallbackPath", ResourcePath.class);
63:
64: /** The path to the template for fallback rendering of the light box, when JavaScript is not available. */
65: private static final Key<ResourcePath> P_BLUETTE_LIGHTBOX_FALLBACK_TEMPLATE_PATH = Key.of("bluetteLightboxFallbackPath", ResourcePath.class);
66:
67: /** The path to the template for the script that redirects a page to the dynamic counterpart (with #!). */
68: private static final Key<ResourcePath> P_BLUETTE_REDIRECT_SCRIPT_TEMPLATE_PATH = Key.of("bluetteRedirectScriptPath", ResourcePath.class);
69:
70: /** The path to the template for the image catalog. */
71: private static final Key<ResourcePath> P_BLUETTE_CATALOG_TEMPLATE_PATH = Key.of("bluetteCatalogPath", ResourcePath.class);
72:
73: private static final Key<ResourcePath> P_BLUETTE_VARIABLES_TEMPLATE_PATH = Key.of("bluetteVariablesPath", ResourcePath.class);
74:
75: private static final Key<String> P_CATALOG_URL = Key.of("bluetteCatalogUrl", String.class);
76:
77: @Nonnull
78: private final Site site;
79:
80: @Nonnull
81: private final Template defaultTemplate;
82:
83: @Nonnull
84: private final Template fallbackTemplate;
85:
86: @Nonnull
87: private final Template lightboxFallbackTemplate;
88:
89: @Nonnull
90: private final Template redirectScriptTemplate;
91:
92: @Nonnull
93: private final Template catalogTemplate;
94:
95: @Nonnull
96: private final Template variablesTemplate;
97:
98: @Nonnull
99: private final ResourceProperties bluetteConfiguration;
100:
101: @Nonnull
102: private final ResourcePath baseUrl;
103:
104: @Nonnull
105: private final String copyright;
106:
107: private final int fallbackImageSize = 1280; // FIXME: parametrise size
108:
109: private final int fallbackThumbnailSize = 100; // FIXME: parametrise size
110:
111: private final ResourcePath lightboxSegmentUri = ResourcePath.of("lightbox");
112:
113: @Nonnull
114: private final String homeUrl;
115:
116: private String rendered = "";
117:
118: private boolean catalog;
119:
120: /***********************************************************************************************************************************************************
121: *
122: **********************************************************************************************************************************************************/
123: public BluetteGalleryAdapter (@Nonnull final SiteNode siteNode,
124: @Nonnull final GalleryView view,
125: @Nonnull final ModelFactory modelFactory)
126: {
127: super(siteNode, view, modelFactory);
128: this.site = siteNode.getSite();
129: bluetteConfiguration = siteNode.getPropertyGroup(new Id("bluetteConfiguration"));
130: baseUrl = siteNode.getRelativeUri().prependedWith(site.getContextPath());
131: homeUrl = site.createLink(ResourcePath.of("/blog")); // FIXME
132: copyright = bluetteConfiguration.getProperty(P_COPYRIGHT).orElse("");
133:
134: defaultTemplate = loadTemplate(P_BLUETTE_TEMPLATE_PATH, "Default.st");
135: fallbackTemplate = loadTemplate(P_BLUETTE_FALLBACK_TEMPLATE_PATH, "Fallback.st");
136: lightboxFallbackTemplate = loadTemplate(P_BLUETTE_LIGHTBOX_FALLBACK_TEMPLATE_PATH, "LightBoxFallback.st");
137: redirectScriptTemplate = loadTemplate(P_BLUETTE_REDIRECT_SCRIPT_TEMPLATE_PATH, "RedirectScript.st");
138: catalogTemplate = loadTemplate(P_BLUETTE_CATALOG_TEMPLATE_PATH, "Catalog.st");
139: variablesTemplate = loadTemplate(P_BLUETTE_VARIABLES_TEMPLATE_PATH, "Variables.st");
140: }
141:
142: /***********************************************************************************************************************************************************
143: * {@inheritDoc}
144: **********************************************************************************************************************************************************/
145: @Override @Nonnull
146: public String getInlinedScript()
147: {
148: final var link = site.createLink(siteNode.getRelativeUri().appendedWith("images.xml"));
149: final var properties = bluetteConfiguration.withProperty(P_CATALOG_URL, "'" + link + "'");
150: // FIXME: since key doesn't have dynamic type, we can't properly escape strings.
151: final var variables = properties.getKeys().stream()
152:• .filter(k -> k.getName().startsWith("bluette") || "logging".equals(k.getName()))
153: .flatMap(k -> toAggregate(properties, k).stream())
154: .collect(toAggregates("entries"));
155:
156: return variablesTemplate.render(variables) + "\n" + redirectScriptTemplate.render();
157: }
158:
159: /***********************************************************************************************************************************************************
160: * {@inheritDoc}
161: **********************************************************************************************************************************************************/
162: @Override
163: public void prepareCatalog (@Nonnull final List<? extends GalleryItem> items)
164: {
165: final var entries = items.stream().map(this::toAggregate).collect(toAggregates("entries"));
166: rendered = catalogTemplate.render(entries);
167: catalog = true;
168: }
169:
170: /***********************************************************************************************************************************************************
171: * {@inheritDoc}
172: **********************************************************************************************************************************************************/
173: // TODO: Could we manage #! params here and select the proper item?
174: @Override
175: public void prepareGallery (@Nonnull final GalleryItem item, @Nonnull final List<? extends GalleryItem> items)
176: {
177: prepare(item, items, defaultTemplate);
178: rendered = defaultTemplate.render();
179: }
180:
181: /***********************************************************************************************************************************************************
182: * {@inheritDoc}
183: **********************************************************************************************************************************************************/
184: @Override
185: public void prepareFallbackGallery (@Nonnull final GalleryItem item, @Nonnull final List<? extends GalleryItem> items)
186: {
187: prepare(item, items, fallbackTemplate);
188: rendered = fallbackTemplate.render();
189: }
190:
191: /***********************************************************************************************************************************************************
192: * {@inheritDoc}
193: **********************************************************************************************************************************************************/
194: @Override
195: public void prepareFallbackLightbox (@Nonnull final List<? extends GalleryItem> items)
196: {
197: final var entries = items.stream().map(this::toAggregate).collect(toAggregates("entries"));
198: final var redirectUrl = site.createLink(baseUrl.appendedWith("#!").appendedWith(lightboxSegmentUri)).replaceAll("/$", "");
199: redirectScriptTemplate.addAttribute("redirectUrl", redirectUrl);
200: lightboxFallbackTemplate.addAttribute("copyright", copyright);
201: rendered = lightboxFallbackTemplate.render(entries);
202: }
203:
204: /***********************************************************************************************************************************************************
205: * {@inheritDoc}
206: **********************************************************************************************************************************************************/
207: @Override
208: public void render (@Nonnull final RenderContext context)
209: {
210: final var textHolder = (TextHolder)view;
211:
212:• if (!catalog)
213: {
214: textHolder.addAttribute("content", rendered);
215: }
216: else
217: {
218: textHolder.setTemplate("$content$\n");
219: textHolder.setContent(rendered);
220: textHolder.setMimeType("text/xml");
221: }
222: }
223:
224: /***********************************************************************************************************************************************************
225: *
226: **********************************************************************************************************************************************************/
227: private void prepare (// final @Nonnull RenderContext context,
228: @Nonnull final GalleryItem item,
229: @Nonnull final List<? extends GalleryItem> items,
230: @Nonnull final Template template)
231: {
232: final var count = items.size();
233: final var index = items.indexOf(item);
234: final var prevIndex = (index - 1 + count) % count;
235: final var nextIndex = (index + 1) % count;
236:
237: final var imageId = item.getId().stringValue();
238: final var imageUrl = createImageLink(imageId, fallbackImageSize);
239:
240: final var redirectUrl = site.createLink(baseUrl.appendedWith("#!").appendedWith(imageId)).replaceAll("/$", "");
241: final var previousUrl = site.createLink(baseUrl.appendedWith(items.get(prevIndex).getId().stringValue()));
242: final var nextUrl = site.createLink(baseUrl.appendedWith(items.get(nextIndex).getId().stringValue()));
243: final var lightboxUrl = site.createLink(baseUrl.appendedWith(lightboxSegmentUri));
244:
245: template.addAttribute("caption", item.getDescription())
246: .addAttribute("previous", previousUrl)
247: .addAttribute("next", nextUrl)
248: .addAttribute("lightbox", lightboxUrl)
249: .addAttribute("home", homeUrl)
250: .addAttribute("imageId", imageId)
251: .addAttribute("imageUrl", imageUrl)
252: .addAttribute("copyright", copyright);
253:
254:• if (template != defaultTemplate)
255: {
256: redirectScriptTemplate.addAttribute("redirectUrl", redirectUrl);
257:
258: // context.setDynamicNodeProperty(PD_IMAGE_ID, imageId);
259: // FIXME: these should be dynamic properties
260: // siteNodeProperties.getProperty().ifPresent(id -> view.addAttribute("imageId", id));
261: // siteNodeProperties.getProperty(PD_URL).ifPresent(id -> view.addAttribute("url", id));
262: final var textHolder = (TextHolder)view;
263: textHolder.addAttribute("description", item.getDescription());
264: textHolder.addAttribute("imageId", imageId);
265: textHolder.addAttribute("imageUrl", imageUrl);
266: }
267: }
268:
269: /***********************************************************************************************************************************************************
270: *
271: **********************************************************************************************************************************************************/
272: @Nonnull
273: private Aggregate toAggregate (@Nonnull final GalleryItem item)
274: {
275: final var id = item.getId().stringValue();
276: final var link = site.createLink(baseUrl.appendedWith(id));
277: return Aggregate.of("id", id)
278: .with("link", link)
279: .with("url", createImageLink(id, fallbackThumbnailSize))
280: .with("title", item.getDescription().replaceAll("\n+", " "));
281: }
282:
283: /***********************************************************************************************************************************************************
284: *
285: **********************************************************************************************************************************************************/
286: @Nonnull
287: private static Optional<Aggregate> toAggregate (@Nonnull final ResourceProperties properties,
288: @Nonnull final Key<?> key)
289: {
290: // A space in front of [ ] makes them interpreted as a string and not a list.
291: return properties.getProperty(key).map(v -> Aggregate.of("name", key.stringValue()).with("value", v.toString().replace("[", " [")));
292: }
293:
294: /***********************************************************************************************************************************************************
295: *
296: **********************************************************************************************************************************************************/
297: @Nonnull
298: private String createImageLink (@Nonnull final String id, @Nonnegative final int size)
299: {
300: return site.createLink(ResourcePath.of(String.format("/media/stillimages/%d/%s.jpg", size, id)));
301: }
302: }