DefaultNodeContainerViewController.java

  1. /*
  2.  * #%L
  3.  * *********************************************************************************************************************
  4.  *
  5.  * NorthernWind - lightweight CMS
  6.  * http://northernwind.tidalwave.it - git clone https://bitbucket.org/tidalwave/northernwind-src.git
  7.  * %%
  8.  * Copyright (C) 2011 - 2021 Tidalwave s.a.s. (http://tidalwave.it)
  9.  * %%
  10.  * *********************************************************************************************************************
  11.  *
  12.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  13.  * the License. You may obtain a copy of the License at
  14.  *
  15.  *     http://www.apache.org/licenses/LICENSE-2.0
  16.  *
  17.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  18.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  19.  * specific language governing permissions and limitations under the License.
  20.  *
  21.  * *********************************************************************************************************************
  22.  *
  23.  *
  24.  * *********************************************************************************************************************
  25.  * #L%
  26.  */
  27. package it.tidalwave.northernwind.frontend.ui.component.nodecontainer;

  28. import javax.annotation.Nonnull;
  29. import java.util.List;
  30. import java.util.stream.Stream;
  31. import it.tidalwave.util.Key;
  32. import java.util.Optional;
  33. import it.tidalwave.northernwind.core.model.RequestLocaleManager;
  34. import it.tidalwave.northernwind.core.model.ResourcePath;
  35. import it.tidalwave.northernwind.core.model.ResourceProperties;
  36. import it.tidalwave.northernwind.core.model.Site;
  37. import it.tidalwave.northernwind.core.model.SiteNode;
  38. import it.tidalwave.northernwind.frontend.ui.RenderContext;
  39. import lombok.RequiredArgsConstructor;
  40. import lombok.extern.slf4j.Slf4j;
  41. import static java.util.Collections.*;
  42. import static java.util.stream.Collectors.*;
  43. import static it.tidalwave.northernwind.core.model.Content.*;
  44. import static it.tidalwave.northernwind.core.model.SiteNode._SiteNode_;
  45. import static it.tidalwave.northernwind.frontend.ui.component.Properties.*;

  46. /***********************************************************************************************************************
  47.  *
  48.  * @author  Fabrizio Giudici
  49.  *
  50.  **********************************************************************************************************************/
  51. @RequiredArgsConstructor @Slf4j
  52. public class DefaultNodeContainerViewController implements NodeContainerViewController
  53.   {
  54.     // TODO: this class should not set the HTML contents... it should be a responsibility of the view.
  55.     // Instead, it should pass unformatted objects
  56.     private static final String RSS_MIME_TYPE = "application/rss+xml";

  57.     private static final String TEMPLATE_LINK_SCREEN_CSS =
  58.             "<link rel=\"stylesheet\" media=\"screen\" href=\"%s\" type=\"text/css\" />%n";

  59.     private static final String TEMPLATE_LINK_PRINT_CSS =
  60.             "<link rel=\"stylesheet\" media=\"print\" href=\"%s\" type=\"text/css\" />%n";

  61.     // Always use </script> to close, as some browsers break without
  62.     private static final String TEMPLATE_SCRIPT =
  63.             "<script type=\"text/javascript\" src=\"%s\"></script>%n";

  64.     private static final String TEMPLATE_RSS_LINK =
  65.             "<link rel=\"alternate\" type=\"%s\" title=\"%s\" href=\"%s\" />%n";

  66.     @Nonnull
  67.     private final NodeContainerView view;

  68.     @Nonnull
  69.     private final SiteNode siteNode;

  70.     @Nonnull
  71.     private final RequestLocaleManager requestLocaleManager;

  72.     /*******************************************************************************************************************
  73.      *
  74.      * {@inheritDoc}
  75.      *
  76.      ******************************************************************************************************************/
  77.     @Override
  78.     public void renderView (@Nonnull final RenderContext context)
  79.       throws Exception
  80.       {
  81.         final ResourceProperties viewProperties     = getViewProperties();
  82.         final ResourceProperties siteNodeProperties = context.getRequestContext().getNodeProperties();
  83.         viewProperties.getProperty(P_TEMPLATE_PATH).flatMap(p -> siteNode.getSite().getTemplate(getClass(), p))
  84.                                                                                    .ifPresent(view::setTemplate);

  85.         view.addAttribute("language",         requestLocaleManager.getLocales().get(0).getLanguage());
  86.         viewProperties.getProperty(P_DESCRIPTION).ifPresent(d -> view.addAttribute("description", d));
  87.         viewProperties.getProperty(P_TITLE_PREFIX).ifPresent(p -> view.addAttribute("titlePrefix", p));
  88.         Stream.of(siteNodeProperties.getProperty(PD_TITLE), siteNodeProperties.getProperty(P_TITLE)) // TODO: use multi-key
  89.               .filter(Optional::isPresent)
  90.               .map(Optional::get)
  91.               .findFirst().ifPresent(s -> view.addAttribute("title", s));
  92.         view.addAttribute("screenCssSection", computeScreenCssSection());
  93.         view.addAttribute("printCssSection",  computePrintCssSection());
  94.         view.addAttribute("rssFeeds",         computeRssFeedsSection());
  95.         view.addAttribute("scripts",          computeScriptsSection());
  96.         view.addAttribute("inlinedScripts",   computeInlinedScriptsSection());
  97.         siteNodeProperties.getProperty(PD_IMAGE_ID).ifPresent(id -> view.addAttribute("imageId", id));
  98.         siteNodeProperties.getProperty(PD_URL).ifPresent(id -> view.addAttribute("url", id));
  99.       }

  100.     /*******************************************************************************************************************
  101.      *
  102.      * .
  103.      *
  104.      ******************************************************************************************************************/
  105.     @Nonnull
  106.     protected ResourceProperties getViewProperties()
  107.       {
  108.         return siteNode.getPropertyGroup(view.getId());
  109.       }

  110.     /*******************************************************************************************************************
  111.      *
  112.      * .
  113.      *
  114.      ******************************************************************************************************************/
  115.     @Nonnull
  116.     private String computeScreenCssSection()
  117.       {
  118.         return streamOf(P_SCREEN_STYLE_SHEETS)
  119.                 .map(this::createLink)
  120.                 .map(link -> String.format(TEMPLATE_LINK_SCREEN_CSS, link))
  121.                 .collect(joining());
  122.       }

  123.     /*******************************************************************************************************************
  124.      *
  125.      * .
  126.      *
  127.      ******************************************************************************************************************/
  128.     @Nonnull
  129.     private String computePrintCssSection()
  130.       {
  131.         return streamOf(P_PRINT_STYLE_SHEETS)
  132.                 .map(this::createLink)
  133.                 .map(link -> String.format(TEMPLATE_LINK_PRINT_CSS, link))
  134.                 .collect(joining());
  135.       }

  136.     /*******************************************************************************************************************
  137.      *
  138.      * .
  139.      *
  140.      ******************************************************************************************************************/
  141.     @Nonnull
  142.     private String computeRssFeedsSection()
  143.       {
  144.         final Site site = siteNode.getSite();
  145.         return streamOf(P_RSS_FEEDS)
  146.                 .flatMap(relativePath -> site.find(_SiteNode_).withRelativePath(relativePath).stream())
  147.                 .map(node -> String.format(TEMPLATE_RSS_LINK,
  148.                                            RSS_MIME_TYPE,
  149.                                            node.getProperty(P_TITLE).orElse("RSS"),
  150.                                            site.createLink(node.getRelativeUri())))
  151.                 .collect(joining());
  152.       }

  153.     /*******************************************************************************************************************
  154.      *
  155.      * .
  156.      *
  157.      ******************************************************************************************************************/
  158.     @Nonnull
  159.     private String computeScriptsSection()
  160.       {
  161.         return streamOf(P_SCRIPTS)
  162.                 .map(relativeUri -> siteNode.getSite().createLink(ResourcePath.of(relativeUri)))
  163.                 .map(link -> String.format(TEMPLATE_SCRIPT, link))
  164.                 .collect(joining());
  165.       }

  166.     /*******************************************************************************************************************
  167.      *
  168.      * .
  169.      *
  170.      ******************************************************************************************************************/
  171.     @Nonnull
  172.     protected String computeInlinedScriptsSection()
  173.       {
  174.         return streamOf(P_INLINED_SCRIPTS)
  175.                 .flatMap(path -> siteNode.getSite().find(_Content_).withRelativePath(path).stream())
  176.                 .flatMap(script -> script.getProperty(P_TEMPLATE).stream())
  177.                 .collect(joining());
  178.       }

  179.     /*******************************************************************************************************************
  180.      *
  181.      * .
  182.      *
  183.      ******************************************************************************************************************/
  184.     @Nonnull
  185.     private Stream<String> streamOf (@Nonnull final Key<List<String>> key)
  186.       {
  187.         return getViewProperties().getProperty(key).orElse(emptyList()).stream();
  188.       }

  189.     /*******************************************************************************************************************
  190.      *
  191.      * .
  192.      *
  193.      ******************************************************************************************************************/
  194.     @Nonnull
  195.     private String createLink (@Nonnull final String relativeUri)
  196.       {
  197.         return relativeUri.startsWith("http") ? relativeUri : siteNode.getSite().createLink(ResourcePath.of(relativeUri));
  198.       }
  199.   }