All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.aemds.guide.utils.GuideThemeUtils Maven / Gradle / Ivy

/*
 * **********************************************************************
 *  ADOBE CONFIDENTIAL
 *  __________________
 *
 *  Copyright 2015 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 *  NOTICE:  All information contained herein is, and remains
 *  the property of Adobe Systems Incorporated and its suppliers,
 *  if any.  The intellectual and technical concepts contained
 *  herein are proprietary to Adobe Systems Incorporated and its
 *  suppliers and may be covered by U.S. and Foreign Patents,
 *  patents in process, and are protected by trade secret or copyright law.
 *  Dissemination of this information or reproduction of this material
 *  is strictly forbidden unless prior written permission is obtained
 *  from Adobe Systems Incorporated.
 *  **********************************************************************
 */
package com.adobe.aemds.guide.utils;
import com.adobe.aemds.guide.common.FDVersion;
import com.adobe.aemds.guide.model.TypekitConfiguration;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.aemds.guide.service.internal.TypekitConfigurationService;
import com.adobe.aemds.guide.themes.GuideThemeConstants;
import com.adobe.aemds.guide.themes.model.BreakpointInfo;
import com.adobe.aemds.guide.themes.model.Component;
import com.adobe.aemds.guide.themes.model.DefaultBreakpointInfo;
import com.adobe.aemds.guide.themes.model.Selector;
import com.adobe.aemds.guide.themes.model.Theme;
import com.adobe.aemds.guide.themes.model.ThemeMetadata;
import com.adobe.aemds.guide.utils.GuideUtils;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.webservicesupport.Configuration;
import com.day.cq.wcm.webservicesupport.ConfigurationManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.resourcemerger.api.ResourceMergerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.RepositoryException;
import org.apache.sling.api.resource.PersistenceException;
import javax.jcr.PathNotFoundException;
import javax.jcr.*;
import java.io.ByteArrayInputStream;
import java.util.*;
import com.day.cq.commons.jcr.JcrUtil;
import com.adobe.aemds.guide.themes.model.ThemeClientLib;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.Template;
import com.day.cq.wcm.api.TemplatedResource;
/**
 * @pad.exclude Exclude from Published API.
 */
public class GuideThemeUtils {
    private static Logger logger = LoggerFactory.getLogger(GuideThemeUtils.class);
    /**
     * The API provides the form page path configured in the Theme
     *
     * @param resourceResolver ResourceResolver instance
     * @param themeContentPath Path of the theme
     * @return Form path using in theme editor
     */
    public static String getConfiguredFormPagePath(ResourceResolver resourceResolver, String themeContentPath) {
        if (resourceResolver == null) {
            throw new GuideException("Invalid user session.");
        }
        Resource themeResource = resourceResolver.resolve(themeContentPath);
        ThemeMetadata themeMetadata = themeResource.getChild(GuideThemeConstants.NODE_METADATA).adaptTo(ThemeMetadata.class);
        return themeMetadata.getFormPagePath();
    }

    /**
     * The API provides the form path configured in the Theme
     *
     * @param resourceResolver ResourceResolver instance
     * @param themeContentPath Path of the theme
     * @return Form path using in theme editor
     */
    public static String getConfiguredFormPath(ResourceResolver resourceResolver, String themeContentPath) {
        if (resourceResolver == null) {
            throw new GuideException("Invalid user session.");
        }
        String formAssetPath = null;
        try {
            Session session = resourceResolver.adaptTo(Session.class);
            if (themeContentPath != null && session.nodeExists(themeContentPath)) {
                Node themeContentNode = session.getNode(themeContentPath);
                if (themeContentNode.hasProperty(GuideThemeConstants.RELATIVE_PATH_CONFIGURED_FORM_REF)) {
                    formAssetPath = themeContentNode.getProperty(GuideThemeConstants.RELATIVE_PATH_CONFIGURED_FORM_REF).getString();
                }
            }
        } catch (RepositoryException e) {
            throw new GuideException(e);
        }
        return formAssetPath;
    }

    /**
     * Get the theme client library for a given theme path
     *
     * @param resourceResolver ResourceResolver instance
     * @param themeContentPath Path of the theme
     * @return theme client library for a given theme path
     */
    public static String getThemeClientlibCategory(ResourceResolver resourceResolver, String themeContentPath) {
        if (resourceResolver == null) {
            throw new GuideException("Invalid user session.");
        }

        String themeClientlibCategory = null;
        try {
            Session session = resourceResolver.adaptTo(Session.class);
            if (themeContentPath != null && session.nodeExists(themeContentPath)) {
                Node themeContentNode = session.getNode(themeContentPath);
                if (themeContentNode.hasProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_CLIENTLIB_CATEGORY)) {
                    themeClientlibCategory = themeContentNode.getProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_CLIENTLIB_CATEGORY).getString();
                }
            }
        } catch (RepositoryException e) {
            throw new GuideException(e);
        }
        return themeClientlibCategory;
    }

    /**
     * Get the base client lib category for the theme
     *
     * @param resourceResolver ResourceResolver instance
     * @param themeContentPath Path of the theme
     * @return base client lib category for the theme
     */
    public static String getBaseClientlibCategory(ResourceResolver resourceResolver, String themeContentPath) {
        if (resourceResolver == null) {
            throw new GuideException("Invalid user session.");
        }

        String baseClientlibCategory = null;
        try {
            Session session = resourceResolver.adaptTo(Session.class);
            if (themeContentPath != null && session.nodeExists(themeContentPath)) {
                Node themeContentNode = session.getNode(themeContentPath);
                if (themeContentNode.hasProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_CLIENTLIB_REF)) {
                    String clientlibLoc = themeContentNode.getProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_CLIENTLIB_REF).getString();
                    Node clientlibNode = session.getNode(clientlibLoc + "/" + themeContentNode.getParent().getName());
                    if (clientlibNode.hasProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_DEPENDENCIES)) {
                        Value[] values = clientlibNode.getProperty(GuideThemeConstants.RELATIVE_PATH_PROPERTY_DEPENDENCIES).getValues();
                        baseClientlibCategory = values[0].getString();
                    }
                }
            }
        } catch (RepositoryException e) {
            throw new GuideException(e);
        }
        return baseClientlibCategory;
    }

    public static void saveThemeCSS(Theme theme,
                                    ResourceResolver resolver,
                                    ResourceMergerService resourceMergerService) throws GuideException {
        try {
            String cSSString = getThemeCSS(theme, resolver, resourceMergerService);
            updateClientLibForTheme(resolver,
                    theme.getThemeNodeName(),
                    cSSString,
                    theme.getMetadata().getClientlibRef());
        } catch (RepositoryException e) {
            logger.error("Unable to save the Theme Css", e);
            throw new GuideException(e);
        }
    }

    public static String getThemeCSS(Theme theme, ResourceResolver resolver, ResourceMergerService resourceMergerService) {
        String themeCss = "";
        List themeFormBreakpointList = new ArrayList();
        ThemeMetadata themeMetadata = theme.getMetadata();
        List breakpoints = themeMetadata.getBreakpoints();
        String themeFormPath = themeMetadata.getFormPagePath();
        Resource breakpointNodeResource = GuideUtils.getFormBreakpointResource(resolver, themeFormPath);
        if (breakpointNodeResource != null) {
            Iterator childResources = breakpointNodeResource.getChildren().iterator();
            while (childResources.hasNext()) {
                Resource childResource = childResources.next();
                BreakpointInfo breakpointInfo = childResource.adaptTo(BreakpointInfo.class);
                themeFormBreakpointList.add(breakpointInfo);
            }
        }

        if(!containsDefaultBreakpoint(breakpoints)) {
            BreakpointInfo defaultBreakpoint = new DefaultBreakpointInfo();
            breakpoints.add(defaultBreakpoint);
        }
        List sortedBreakpoints = sortBreakpoints(breakpoints);
        // This list will be used to form to add breakpoint to theme. This scenario can occur when u have an additional
        // breakpoint in the theme configured and you start styling that breakpoint.
        List currentFormBreakpointList = sortBreakpoints(themeFormBreakpointList);
        Iterator componentIterator = theme.getComponents().iterator();


        while (componentIterator.hasNext()) {
            Component component = componentIterator.next();
            Map selectorMap = GuideStyleMigrationUtils.getSelectorMap(component.getComponentPath(), resolver, resourceMergerService, "cq:themeConfig");
            themeCss += getComponentCssString(component, resolver, sortedBreakpoints, currentFormBreakpointList, selectorMap, themeMetadata);
        }
        themeCss += theme.getRawCss();
        return themeCss;
    }

    private static boolean containsDefaultBreakpoint(List breakpoints) {
        Iterator breakpointIterator = breakpoints.iterator();
        while(breakpointIterator.hasNext()) {
            BreakpointInfo breakpoint = breakpointIterator.next();
            if(breakpoint.getId().equals("default")) {
                return true;
            }
        }
        return false;
    }

    public static String getComponentCssString(Component component,
                                               ResourceResolver resolver,
                                               List sortedBreakpoints,
                                               List additionalBreakpointList,
                                               Map selectorMap,
                                               ThemeMetadata themeMetadata) {
        //themeMetadata and additionalBreakpointList only makes sense in theme only for the logic to add any additional breakpoint.
        // These two can be completely ignored while looking at inline css generation.
        String themeCss = "";
        Iterator selectorIterator = component.getSelectors().iterator();
        while (selectorIterator.hasNext()) {
            Selector selector = selectorIterator.next();
            ValueMap selectorProperties = selector.getSelectorAllProperties();
            Iterator breakpointIterator = sortedBreakpoints.iterator();
            //As visible this is theme specific logic to look at any additional breakpoint in selector json
            // which is not present in theme breakpoint list. For inline empy set is added just to have same code flow.
            // This makes no sense for inline css generation as there we make breakpoints list from form itself.
            Set selectorBreakpointIdSet = (additionalBreakpointList.isEmpty() ? new HashSet() : selector.getBreakpointsIdSet());
            while (breakpointIterator.hasNext()) {
                BreakpointInfo breakpoint = breakpointIterator.next();
                themeCss += getSelectorCssString(breakpoint, selector, selectorProperties, resolver, selectorMap, component.getInlineClass());
                String currentBreakpointId = breakpoint.getId();
                if (selectorBreakpointIdSet.contains(currentBreakpointId)) {
                    selectorBreakpointIdSet.remove(currentBreakpointId);
                }
            }
            // Theme sepecific Logic to add any additional breakpoint if found in selector json.
            Iterator additionalBreakpointListIterator = additionalBreakpointList.iterator();
            while(additionalBreakpointListIterator.hasNext() && !selectorBreakpointIdSet.isEmpty()) {
                BreakpointInfo breakpoint = additionalBreakpointListIterator.next();
                String breakpointId = breakpoint.getId();
                if (selectorBreakpointIdSet.contains(breakpointId)) {
                    addBreakpointToTheme(breakpoint, themeMetadata);
                    sortedBreakpoints.add(breakpoint);
                    GuideThemeUtils.sortBreakpoints(sortedBreakpoints);
                    themeCss += getSelectorCssString(breakpoint, selector, selectorProperties, resolver, selectorMap, component.getInlineClass());
                }
            }
        }
        return themeCss;
    }

    private static void addBreakpointToTheme(BreakpointInfo breakpoint, ThemeMetadata themeMetadata) {
        try {
            Resource breakpointResource = themeMetadata.getResource().getChild("breakpoints");
            Node themeBreakpointNode = breakpointResource.adaptTo(Node.class);
            Node newBreakpointNode = themeBreakpointNode.addNode(breakpoint.getId(), GuideConstants.NT_UNSTRUCTURED);
            newBreakpointNode.setProperty("title", breakpoint.getName());
            newBreakpointNode.setProperty("width", breakpoint.getMax());
        } catch (Exception e) {
            logger.error("Unable to add breakpoint to theme", e);
        }
    }

    private static String getSelectorCssString(BreakpointInfo breakpoint,
                                               Selector selector,
                                               ValueMap selectorProperties,
                                               ResourceResolver resolver,
                                               Map selectorMap,
                                               String inlineClass) {
        String selectorCss = "";
        String breakpointId = breakpoint.getId();
        List stylePropertyNames = selector.getStylePropertyNames(breakpointId);
        if (stylePropertyNames.size() > 0) {
            if (!breakpointId.equals("default")) {
                selectorCss += "@media (max-width : " + breakpoint.getMax() + "px){\n";
            }
            Iterator propertiesIterator = stylePropertyNames.iterator();
            while (propertiesIterator.hasNext()) {
                String propertyName = propertiesIterator.next();
                if (selectorProperties.get(propertyName) != null) {
                    String stateName = propertyName.substring(propertyName.indexOf("#") + 1);
                    HashSet maskedPropertiesSet = selector.getMaskedPropertiesSet(breakpointId, stateName);
                    String[] cssProperties = selector.getCssPropertiesList(breakpointId, stateName).toArray(new String[0]);
                    String selectorPath = selectorMap.get(selector.getId());
                    if (selectorPath != null) {
                        if (!stateName.equals("default")) {
                            selectorPath = selectorMap.get(selector.getId()) + "/states/" + stateName;
                        }
                        if (resolver.getResource(selectorPath) != null && resolver.getResource(selectorPath).getValueMap().containsKey("cssSelector")) {
                            ValueMap valueMap = resolver.getResource(selectorPath).getValueMap();
                            String cssSelector, cssOverride = "", beforeSelector = "", afterSelector = "", addonCss = "";
                            String inlinePrefix = "";
                            cssSelector = generateSelectorString(inlineClass, valueMap.get("cssSelector").toString(), true);
                            selectorCss += cssSelector + "{\n";
                            for (String cssProperty : cssProperties) {
                                String key = cssProperty.substring(0, cssProperty.indexOf(':'));
                                String value = cssProperty.substring(cssProperty.indexOf(':') + 1);
                                if (key.equals(GuideThemeConstants.CSS_OVERRIDE_PROPERTY_NAME)) {
                                    cssOverride = getCssPropertyValue(GuideThemeConstants.CSS_OVERRIDE_PROPERTY_NAME, value, maskedPropertiesSet);
                                } else if (key.equals(GuideThemeConstants.AFTER_PSEUDO_ELEMENT_PROPERTY_NAME)) {
                                    afterSelector = getPseudoCSSString(cssSelector, "::after", getCssPropertyValue(GuideThemeConstants.AFTER_PSEUDO_ELEMENT_PROPERTY_NAME, value, maskedPropertiesSet));
                                } else if (key.equals(GuideThemeConstants.BEFORE_PSEUDO_ELEMENT_PROPERTY_NAME)) {
                                    beforeSelector = getPseudoCSSString(cssSelector, "::before", getCssPropertyValue(GuideThemeConstants.BEFORE_PSEUDO_ELEMENT_PROPERTY_NAME, value, maskedPropertiesSet));
                                } else if (key.equals(GuideThemeConstants.ADDON_CSS_ELEMENT_PROPERTY_NAME)) {
                                    addonCss = getAddonCSSString(inlineClass, value);
                                } else {
                                    String propertyValueCssString = key + ":" + value + ";\n";
                                    selectorCss += getCssPropertyValue(key, propertyValueCssString, maskedPropertiesSet);
                                }
                            }
                            selectorCss += cssOverride + "\n";
                            selectorCss += "}\n";
                            selectorCss += beforeSelector;
                            selectorCss += afterSelector;
                            selectorCss += addonCss;
                        } else {
                            logger.error("CSS selector string not found for resource: " + selectorPath);
                        }
                    } else {
                        logger.error("CSS selector information not found for selector Id: " + selector.getId());
                    }
                }
            }
            if (!breakpointId.equals("default")) {
                selectorCss += "}\n";
            }
        }
        return selectorCss;
    }

    public static void saveInlineCSS(Resource resource, String formPath, ResourceMergerService resourceMergerService) {
        ResourceResolver resolver = resource.getResourceResolver();
        String resourceType = resource.getResourceType();
        List breakpointInfoList = new ArrayList();
        Resource breakpointNodeResource = GuideUtils.getFormBreakpointResource(resolver, formPath);
        if (breakpointNodeResource != null) {
            Iterator childResources = breakpointNodeResource.getChildren().iterator();
            while (childResources.hasNext()) {
                Resource childResource = childResources.next();
                BreakpointInfo breakpointInfo = childResource.adaptTo(BreakpointInfo.class);
                breakpointInfoList.add(breakpointInfo);
            }
        }
        BreakpointInfo defaultBreakpoint = new DefaultBreakpointInfo();
        breakpointInfoList.add(defaultBreakpoint);
        List sortedBreakpoints = GuideThemeUtils.sortBreakpoints(breakpointInfoList);
        Resource styleResource = resource.getChild("style");
        String overridePath = resolver.getResource(resourceType).getPath();
        Map selectorMap = GuideStyleMigrationUtils.getSelectorMap(overridePath, resolver, resourceMergerService, "cq:styleConfig");
        if (styleResource != null) {
            com.adobe.aemds.guide.themes.model.Component component = styleResource.adaptTo(com.adobe.aemds.guide.themes.model.Component.class);
            String cssString = GuideThemeUtils.getComponentCssString(component, resolver, sortedBreakpoints, new ArrayList(), selectorMap, null);
            ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);
            properties.put("cssStyle", cssString);
        }
    }

    private static String getAddonCSSString(String inlineClass, String value) {
        String cssString = "";
        try {
            JSONObject addOnCSSObject = new JSONObject(value);
            JSONObject selectors = addOnCSSObject.getJSONObject("selectors");
            Iterator selectorKeys = selectors.keys();
            while (selectorKeys.hasNext()) {
                String key = selectorKeys.next();
                JSONObject selector = selectors.getJSONObject(key);
                String cssSelectorString = generateSelectorString(inlineClass, selector.getString("cssSelector"), false);
                cssString += cssSelectorString + " {\n";
                JSONObject properties = selector.getJSONObject("properties");
                Iterator propertyKeys = properties.keys();
                while (propertyKeys.hasNext()) {
                    String propertyKey = propertyKeys.next();
                    String propValue = properties.getString(propertyKey);
                    cssString += propertyKey + ":" + propValue + ";\n";
                }
                cssString += "}\n";
            }
        } catch (JSONException e) {
            logger.error("Unable to parse addonCss object", e);
        }
        return cssString;
    }

    //if target is set return it, else return the resource itself
    private static Resource getTargetResource(Resource resource) {
        ValueMap values = resource.getValueMap();
        String target = values.get("target", String.class);
        if (target != null) {
            ResourceResolver resolver = resource.getResourceResolver();
            return resolver.getResource(target);
        }
        return resource;
    }

    private static String getPseudoCSSString(String selectorString, String pseudoElementString, String value) {
        StringBuilder selectorValueBuilder = new StringBuilder();
        String cssString = "";
        StringTokenizer st = new StringTokenizer(selectorString, ",");
        while (st.hasMoreElements()) {
            selectorValueBuilder.append(st.nextElement())
                    .append(pseudoElementString);
            if (st.hasMoreElements()) {
                selectorValueBuilder.append(",");
            }
        }
        cssString += selectorValueBuilder.toString();
        cssString += "{\n";
        cssString += value + "\n";
        cssString += "}\n";
        return cssString;
    }

    /**
     * Internal method to update the client library CSS when the theme is updated
     *
     * @param resolver      resource resolver
     * @param clientLibName client library name
     * @param cssString     CSS definition for the theme
     * @param clientLibPath client library path
     * @throws RepositoryException
     */
    private static void updateClientLibForTheme(ResourceResolver resolver,
                                                String clientLibName,
                                                String cssString,
                                                String clientLibPath) throws RepositoryException {
        Resource cssTxtResource;
        Session session = resolver.adaptTo(Session.class);
        String clientLibCompletePath = clientLibPath + "/" + clientLibName;
        Resource clientLibResource = resolver.getResource(clientLibCompletePath);
        if (clientLibResource != null) {
            // Upload the css file
            Resource contentResource = clientLibResource.getChild("css/theme.css/jcr:content");
            //Binary binary = session.getValueFactory().createBinary(new ByteArrayInputStream(cssString.getBytes()));
            ModifiableValueMap map = contentResource.adaptTo(ModifiableValueMap.class);
            map.put(GuideThemeConstants.PROPERTY_JCR_DATA, cssString);

            // Update the lastModified date so that the updated clientLib is picked.
            cssTxtResource = clientLibResource.getChild("css.txt/jcr:content");
            ModifiableValueMap txtMap = cssTxtResource.adaptTo(ModifiableValueMap.class);
            Calendar currentTime = Calendar.getInstance();
            txtMap.put(JcrConstants.JCR_LASTMODIFIED,currentTime);
        } else {
            logger.error("Unable to find clientLib at location {}", clientLibCompletePath);
        }
    }

    public static List sortBreakpoints(List breakpoints) {
        Collections.sort(breakpoints, new Comparator() {
            @Override
            public int compare(BreakpointInfo breakpoint2, BreakpointInfo breakpoint1) {
                if (breakpoint2.getMax() == -1) {
                    return -1;
                }
                if (breakpoint1.getMax() == -1) {
                    return 1;
                }
                return breakpoint1.getMax().compareTo(breakpoint2.getMax());
            }
        });
        return breakpoints;
    }

    /**
     * Check if Property present in masked List or not.
     * @param   cssString   CssString to be commented.
     * @return  value    final resolved value
     */

    public static String makeCssComment(String cssString) {
        return "/*" + cssString + "*/";
    }

    /**
     * The API copies the asset Resource in inline style from fromResource to toResource.
     *
     * @param fromResource the Resource whose style resource is being copied.
     * @param toResource the Resource where style resource is copied.
     * @param resourceResolver resourceResolver instance.
     */
    public static void copyAssets(Resource fromResource, Resource toResource, ResourceResolver resourceResolver) {
        try {
            String fromResourceAssetPath = fromResource.getPath() + "/" + GuideThemeConstants.STYLE_ASSETS_NODE;
            Resource fromResourceAsset = resourceResolver.getResource(fromResourceAssetPath);
            Session session = resourceResolver.adaptTo(Session.class);
            if (fromResourceAsset != null) {
                String toResourceAssetPath = toResource.getPath() + "/" + GuideThemeConstants.STYLE_ASSETS_NODE;
                Resource toResourceAsset = resourceResolver.getResource(toResourceAssetPath);
                if (toResourceAsset == null) {
                    String toResourcePath = toResource.getPath();
                    Node fromResourceAssetNode = session.getNode(fromResourceAssetPath),
                            toResourceNode = session.getNode(toResourcePath);
                    JcrUtil.copy(fromResourceAssetNode, toResourceNode, null);
                } else {
                    Iterator children = fromResourceAsset.listChildren();
                    Node toResourceAssetNode = session.getNode(toResourceAssetPath);
                    while (children.hasNext()) {
                        Resource imageResource = children.next();
                        String imageResourceName = imageResource.getName(),
                                imageResourcePath = imageResource.getPath(),
                                oldImageResourcePath = toResourceAssetPath + "/" + imageResourceName;
                        if (session.itemExists(oldImageResourcePath)) {
                            session.removeItem(oldImageResourcePath);
                        }
                        Node imageNode = session.getNode(imageResourcePath);
                        JcrUtil.copy(imageNode, toResourceAssetNode, null);
                    }
                }
                session.save();
            }
        } catch (PathNotFoundException e) {
            logger.error("Error in copying StyleAsset", e);
        } catch (RepositoryException e) {
            logger.error("Error in copying StyleAsset", e);
        }
    }

    /**
     * The API copies the style Resource in inline style from fromResource to toResource.
     *
     * @param fromResource the Resource whose style resource is being copied.
     * @param toResource the Resource where style resource is copied.
     * @param resourceResolver resourceResolver instance.
     * @param cssClass cssClass of the copied Resource.
     */

    public static void copyStyles(Resource fromResource, Resource toResource, ResourceResolver resourceResolver, String cssClass) {
        try {
            String fromResourcePath = fromResource.getPath(),
                    fromResourceStylePath = fromResourcePath + "/" + GuideThemeConstants.STYLE_NODE,
                    toResourcePath = toResource.getPath(),
                    toResourceStylePath = toResourcePath + "/" + GuideThemeConstants.STYLE_NODE;
            Session session = resourceResolver.adaptTo(Session.class);
            Resource fromResourceStyle = resourceResolver.getResource(fromResourceStylePath);
            Resource toResourceStyle = resourceResolver.getResource(toResourceStylePath);
            ModifiableValueMap toResourcePropertyMap = toResource.adaptTo(ModifiableValueMap.class);
            ModifiableValueMap fromResourcePropertyMap = fromResource.adaptTo(ModifiableValueMap.class);
            if (fromResourceStyle == null) {
                if (toResourcePropertyMap != null) {
                    if (toResourcePropertyMap.containsKey(GuideThemeConstants.CSS_STYLE_PROPERTY)) {
                        toResourcePropertyMap.remove(GuideThemeConstants.CSS_STYLE_PROPERTY);
                    }
                    if (toResourcePropertyMap.containsKey(GuideThemeConstants.CSS_CLASS_PROPERTY)) {
                        toResourcePropertyMap.remove(GuideThemeConstants.CSS_CLASS_PROPERTY);
                    }
                }
                if (toResourceStyle != null) {
                    resourceResolver.delete(toResourceStyle);
                }
            } else {
                if (!toResourcePropertyMap.containsKey(GuideThemeConstants.CSS_CLASS_PROPERTY)) {
                    toResourcePropertyMap.put(GuideThemeConstants.CSS_CLASS_PROPERTY, cssClass);
                }
                toResourcePropertyMap.put(GuideThemeConstants.CSS_STYLE_PROPERTY, fromResourcePropertyMap.get(GuideThemeConstants.CSS_STYLE_PROPERTY));
                Node fromResourceStyleNode = session.getNode(fromResourceStylePath),
                        toResourceNode = session.getNode(toResourcePath);
                JcrUtil.copy(fromResourceStyleNode, toResourceNode, null);
            }
            session.save();
            resourceResolver.commit();
        } catch (PersistenceException e) {
            logger.error("Error in copying StyleNode", e);
        } catch (PathNotFoundException e) {
            logger.error("Error in copying StyleNode", e);
        } catch (RepositoryException e) {
            logger.error("Error in copying StyleNode", e);
        }
    }

    /**
     * Check if Property present in masked List or not.
     * @param   property  property that needs to be checked masked or not.
     * @param   value css value.
     * @param   maskedPropertiesSet  Set of properties that are masked.
     * @return  value    final resolved value.
     */
    private static String getCssPropertyValue(String property, String value, HashSet maskedPropertiesSet) {
        if(maskedPropertiesSet.contains(property)) {
            if(property.equals(GuideThemeConstants.AFTER_PSEUDO_ELEMENT_PROPERTY_NAME) || property.equals(GuideThemeConstants.AFTER_PSEUDO_ELEMENT_PROPERTY_NAME) || property.equals(GuideThemeConstants.BEFORE_PSEUDO_ELEMENT_PROPERTY_NAME)) {
                value = "";
            } else {
                value = makeCssComment(value);
            }
        }
        return value;
    }
    /**
     * get clientLib category of the given resource.
     * @param   themeResource Theme jcr content resource
     * @return  clientLibCategory   clientLib category of the given theme resource.
     */
    public static String getClientLibCategory (Resource themeResource) {
        String category = null;
        if (themeResource != null) {
            ThemeClientLib clientLib = getThemeClientLib(themeResource);
            if(clientLib != null) {
                category = clientLib.getCategory();
            }
        }
        return category;
    }

    /**
     * get clientLib path of the given resource.
     * @param   themeResource Theme jcr content resource
     * @return  clientLibPath   clientLib path of the given theme resource.
     *
     */
    public static String getClientLibPath (Resource themeResource) {
        String path = null;
        if (themeResource != null) {
            ThemeClientLib clientLib = getThemeClientLib(themeResource);
            if(clientLib != null) {
                path = clientLib.getPath();
            }
        }
        return path;
    }

    private static ThemeClientLib getThemeClientLib(Resource themeResource) {
        ThemeClientLib clientLib = null;
        if (themeResource != null) {
            String themeNodeName = themeResource.getParent().getName();
            ResourceResolver resolver = themeResource.getResourceResolver();
            ValueMap themeMetaData = themeResource.getChild(GuideThemeConstants.NODE_METADATA).adaptTo(ValueMap.class);
            String path = themeMetaData.get(GuideThemeConstants.PROPERTY_CLIENTLIB_REF, String.class) + "/" + themeNodeName;
            Resource clientLibResource = resolver.getResource(path);
            if (clientLibResource != null) {
                clientLib = clientLibResource.adaptTo(ThemeClientLib.class);
            } else {
                logger.info("Theme client library missing at {}. Falling back to the default client library", path);
            }
        }
        return clientLib;
    }

    /**
     * Gets the path of web font config associated with a theme.
     *
     * @param resourceResolver
     * @param themeContentPath Path of jcr:content node of theme resource.
     * @return The path of web font config
     */
    public static String getWebFontConfig(ResourceResolver resourceResolver, String themeContentPath){
        Resource themeResource = resourceResolver.getResource(themeContentPath);
        if (GuideThemeUtils.isResourceTheme(themeResource)) {
            ValueMap themeMetaData = themeResource.getChild(GuideThemeConstants.NODE_METADATA).adaptTo(ValueMap.class);
            return themeMetaData.get(GuideThemeConstants.PROPERTY_WEB_FONT_CONFIG, String.class);
        }
        return null;
    }

    /**
     * Gets the common clientLib to be included with Theme.
     *
     * @param themeContentResource Theme jcr:content resource.
     * @return Name of the common clientLib to be included
     */
    public static String getCommonClientLibName(Resource themeContentResource){
        Resource themeMetadataResource = themeContentResource.getChild(GuideThemeConstants.NODE_METADATA);
        ValueMap metadata = themeMetadataResource.adaptTo(ValueMap.class);
        // if theme created from version of that of default spec (ie) 1.0, then use the legacy client library
        String targetSpec = metadata.get(GuideConstants.FD_TARGET_VERSION, String.class);
        if(targetSpec == null) {
            targetSpec = GuideThemeConstants.THEME_LEGACY_TARGET_SPEC_VERSION;
        }
        if(FDVersion.compare(GuideThemeConstants.THEME_LEGACY_TARGET_SPEC_VERSION, targetSpec) == 0) {
            return "guide.theme2.common.legacy620";
        }
        return "guide.theme2.common";
    }

    /**
     * Gets the clientLib details to be included for an Adaptive Form
     *
     * @param formResource Form resource
     * @param themeOverride Path of Theme to be overridden
     * @param pageFallbackClientlib fallback clientLib
     * @return ThemeClientLibData object containing the client category names
     */
    public static ThemeClientLibData getClientLibNames(Resource formResource, String themeOverride, String pageFallbackClientlib) {
        Resource themeContentResource = null;
        String themeClientLibName = null,
                commonClientLibName = null;
        if (StringUtils.isNotBlank(themeOverride)) {
            ResourceResolver resourceResolver = formResource.getResourceResolver();
            themeContentResource = resourceResolver.getResource(themeOverride);
            if(GuideThemeUtils.isResourceTheme(themeContentResource)) {
                commonClientLibName = GuideThemeUtils.getCommonClientLibName(themeContentResource);
                themeClientLibName = GuideThemeUtils.getClientLibCategory(themeContentResource);
            }
        }
        if(themeClientLibName == null) {
            themeContentResource = GuideUtils.getThemeResource(formResource);
            if (themeContentResource != null) {
                commonClientLibName = GuideThemeUtils.getCommonClientLibName(themeContentResource);
                themeClientLibName = GuideThemeUtils.getClientLibCategory(themeContentResource);
            }
        }
        if(themeClientLibName == null) {
            if (StringUtils.isNotBlank(pageFallbackClientlib)) {
                //As default is same for all the version and we keep on updating it its common should always be latest version of common.
                themeClientLibName = pageFallbackClientlib;
                commonClientLibName = "guide.theme2.common";
                //TODO: Ideally we should not have a fallbackClientlib, and rather fallback theme.
                //This should be documented for 6.3 (not documentation seen yet for 6.2 for this fallbackLibrary.jsp)
                //Keeping the commonClientLib to legacy. For 0 regression need an API to find theme for given client
            }
        }
        ThemeClientLibData clientLibData = new ThemeClientLibData();
        clientLibData.setCommonClientLib(commonClientLibName);
        if(themeClientLibName != null) {
            clientLibData.setThemeClientLib(themeClientLibName);
        }
        //If form's theme as well as fallback clientlib both are null it means is old form
        // and will not have common or theme.
        return clientLibData;
    }
    /**
     * Check whether the resource type is theme
     *
     * @param themeContentResource Theme jcr:content resource.
     * @return whether resource type is theme or not
     */
    public static boolean isResourceTheme(Resource themeContentResource){
        boolean isResourceTheme = false;
        if (themeContentResource != null) {
            isResourceTheme = themeContentResource.isResourceType(GuideThemeConstants.THEME_SLING_RESOURCE_TYPE_VALUE);
        }
        return isResourceTheme;
    }

    /**
     * Check whether the resource type is theme
     *
     * @param className Inline Style component prefiex Class.
     * @param cssSelector css selector for the particular selector.
     * @param makeDescendantSelector If we want prefix class to be along side the css selector or above it.
     * @return whether resource type is theme or not
     */
    public static String generateSelectorString(String className, String cssSelector, Boolean makeDescendantSelector) {
        if (StringUtils.isEmpty(className)) {
            return cssSelector;
        }
        String selectorString = "";
        String[] selectorArray = cssSelector.split(",");
        for (int i = 0; i < selectorArray.length; i++) {
            if (i != 0) {
                selectorString += ",";
            }
            if (makeDescendantSelector) {
                selectorString += "." + className + " " + selectorArray[i];
            } else {
                selectorString += "." + className + selectorArray[i];
            }
        }
        return selectorString;
    }

    public static void addTypekitConfigurations(JSONArray response, Resource theme,
                        TypekitConfigurationService typekitConfigurationService) throws JSONException {
        Collection collection = typekitConfigurationService.getConfigurationCollection(theme);
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            TypekitConfiguration configuration = iterator.next();
            JSONObject responseObject = new JSONObject();
            responseObject.put("text", StringUtils.isNotEmpty(configuration.title()) ?
                    configuration.title() : configuration.name());
            responseObject.put("value", configuration.name());
            response.put(responseObject);
        }
    }

    public static void addTypekitConfigurations(JSONArray response, Resource theme,
                        ResourceResolver resourceResolver,
                        TypekitConfigurationService typekitConfigurationService) throws JSONException {
        addTypekitConfigurations(response, resourceResolver);
        addTypekitConfigurations(response, theme, typekitConfigurationService);
    }

    @Deprecated
    public static void addTypekitConfigurations(JSONArray response, ResourceResolver resourceResolver) throws JSONException {
        ConfigurationManager configManager = resourceResolver.adaptTo(ConfigurationManager.class);
        Iterator it = configManager.getConfigurations(GuideConstants.TYPEKIT_CLOUD_SERVICE_ROOT_PATH);
        while (it.hasNext()) {
            Configuration configuration = it.next();
            JSONObject responseObject = new JSONObject();
            responseObject.put("text", configuration.getTitle());
            responseObject.put("value", configuration.getPath());
            response.put(responseObject);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy