package nl.gertontenham.magnolia.templating.functions; import info.magnolia.cms.core.AggregationState; import info.magnolia.cms.i18n.I18nContentSupport; import info.magnolia.context.MgnlContext; import info.magnolia.context.WebContext; import info.magnolia.jcr.util.ContentMap; import info.magnolia.jcr.util.NodeTypes; import info.magnolia.jcr.util.PropertyUtil; import info.magnolia.jcr.wrapper.I18nNodeWrapper; import info.magnolia.link.LinkUtil; import info.magnolia.objectfactory.Components; import info.magnolia.rendering.template.type.TemplateTypeHelper; import info.magnolia.repository.RepositoryConstants; import info.magnolia.templating.functions.TemplatingFunctions; import nl.gertontenham.magnolia.templating.FoundationTemplatingModule; import nl.gertontenham.magnolia.templating.beans.SiteConfig; import nl.gertontenham.magnolia.templating.managers.SiteManager; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Provider; import javax.jcr.Node; import javax.jcr.RepositoryException; import java.util.ArrayList; import java.util.Collection; import java.util.Locale; import java.util.Random; /** * An object exposing several methods useful for foundation based templates. * It extends the Magnolia TemplatingFunctions and is exposed in templates as <code>mtffn</code>. * */ public class FoundationTemplatingFunctions extends TemplatingFunctions { private static final Logger log = LoggerFactory.getLogger(FoundationTemplatingFunctions.class); private enum Mode { DEV, BETA; @Override public String toString() { return super.toString().toLowerCase(); } } private FoundationTemplatingModule module; private SiteManager siteManager; private final I18nContentSupport i18n = Components.getComponent(I18nContentSupport.class); private final WebContext webContext = MgnlContext.getWebContext(); private final String queryString = webContext.getRequest().getQueryString(); private final Random randomizer = new Random(); //TODO: aggregationStateProvider is needed in constructor of TemplatingFunctions, but might be changed in future by Magnolia @Inject public FoundationTemplatingFunctions(Provider<AggregationState> aggregationStateProvider, FoundationTemplatingModule module, SiteManager siteManager, TemplateTypeHelper templateTypeFunctions, Provider<I18nContentSupport> i18nContentSupport) { super(aggregationStateProvider, templateTypeFunctions, i18nContentSupport); this.module = module; this.siteManager = siteManager; } /** * Get Site configuration mapped to root node for given node. * * @param content * @return Site configuration, if not found an empty SiteConfig instance will be returned * @throws RepositoryException */ public SiteConfig getSiteConfig(ContentMap content) throws RepositoryException { return getSiteConfig(content.getJCRNode()); } /** * Get Site configuration mapped to root node for given node. * * @param node * @return Site configuration, if not found an empty SiteConfig instance will be returned * @throws RepositoryException */ public SiteConfig getSiteConfig(Node node) throws RepositoryException { return siteManager.getCurrentSiteConfig(getTreeRoot(node)); } /** * Returns the tree's root {@link ContentMap} of the passed @param content {@link ContentMap} * * @param content * @return ContentMap of tree root * @throws RepositoryException */ public ContentMap getTreeRoot(ContentMap content) throws RepositoryException { return asContentMap(getTreeRoot(content.getJCRNode())); } /** * Returns the tree's root {@link Node} of the passed @param content {@link Node} * * @param node * @return Node of tree root * @throws RepositoryException */ public Node getTreeRoot(Node node) throws RepositoryException { Node rootNode = root(page(node), NodeTypes.Page.NAME); return (rootNode == null) ? page(node) : rootNode; } public ContentMap i18nWrap(ContentMap content) { return asContentMap(this.i18nWrap(content.getJCRNode())); } public Node i18nWrap(Node content) { return (content == null) ? null : encode(new I18nNodeWrapper(content)); } /** * Get all active content locales from beans:/server/i18n/content/locales without the default locale * @return Collection of no-default locales */ public Collection<Locale> getLocalesWithoutDefault() { Collection<Locale> orderList = new ArrayList<Locale>(0); for(Locale loc : i18n.getLocales()) { if (!StringUtils.equalsIgnoreCase(loc.getLanguage(), getDefaultLocaleCode())) { orderList.add(loc); } } return orderList; } /** * Get all active content locales from beans:/server/i18n/content/locales * @return Collection of locales starting with default Locale */ public Collection<Locale> getLocales() { Collection<Locale> orderList = new ArrayList<Locale>(0); orderList.add(getDefaultLocale()); orderList.addAll(getLocalesWithoutDefault()); return orderList; } /** * Get current locale with fallback to beans:/server/i18n/content@fallbackLocale * @return Locale */ public Locale getDefaultLocale() { return (i18n.getLocale() != null) ? i18n.getLocale() : i18n.getFallbackLocale(); } /** * Get fallback locale from beans:/server/i18n/content@fallbackLocale * * @return Locale */ public Locale getFallbackLocale() { return i18n.getFallbackLocale(); } /** * Is content localisation enabled * @return true when (/server/i18n/content@enabled has value true) */ public Boolean getLocalisationEnabled() { return i18n.isEnabled(); } /** * Get default locale code * @return language code eg. "nl", "en" ... */ public String getDefaultLocaleCode() { return getDefaultLocale().getLanguage(); } /** * Get localised relative page link * @return page link * @throws javax.jcr.RepositoryException */ public String getLocalisedPageLink(ContentMap content, Locale locale) throws RepositoryException { return getLocalisedPageLink(content.getJCRNode(), locale); } /** * Get localised relative page link * @return page link * @throws RepositoryException */ public String getLocalisedPageLink(Node node, Locale locale) throws RepositoryException { final Locale currentLocale = i18n.getLocale(); final Locale pageLinkLocale = (locale == null) ? currentLocale : locale; // Set locale temporarily for page link rendering i18n.setLocale(pageLinkLocale); String relLink = LinkUtil.createAbsoluteLink(page(node)); // Use basic page link (without language in url) if locale is the same as the fallback locale in Magnolia if (StringUtils.equalsIgnoreCase(getFallbackLocale().getLanguage(), getDefaultLocaleCode())) { relLink = link(node); } // reset temporarily locale back to current locale. i18n.setLocale(currentLocale); return relLink; } /** * Creates absolute link including context path to the provided node and performing all URI2Repository mappings and applying locales. * * @return absolute link for current page */ public String getAbsolutePageLink(Node node) throws RepositoryException { StringBuilder pageUriSB = new StringBuilder(LinkUtil.createExternalLink(page(node))). append(StringUtils.isBlank(queryString) ? "": "?"+queryString); return pageUriSB.toString(); } public boolean isDevMode() { return StringUtils.equalsIgnoreCase(module.getMode(), Mode.DEV.toString()); } public boolean isBetaMode() { return StringUtils.equalsIgnoreCase(module.getMode(), Mode.BETA.toString()); } /** * Get random number falling into the provided range * @param range * @return random int */ public int getRandomNumber(int range) { return randomizer.nextInt(range); } /** * Get magnolia-templating-foundation module version number * @return version */ public String getModuleVersion() { Node node = nodeByPath("/modules/magnolia-templating-foundation", RepositoryConstants.CONFIG); return StringUtils.lowerCase(PropertyUtil.getString(node, "version", "1.0.0")); } }