CSSObject.java 18.3 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  org.apache.commons.lang.StringUtils
 *  org.apache.commons.lang3.StringUtils
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.commons.json.JSONException
 *  org.apache.sling.commons.json.JSONObject
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.aemds.guide.themes;

import com.adobe.aemds.guide.themes.Breakpoint;
import com.adobe.aemds.guide.themes.CSSProperty;
import com.adobe.aemds.guide.themes.Selector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
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.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
public class CSSObject {
    private final TreeMap<Integer, Breakpoint> breakpointStyleMap = new TreeMap();
    private final SelectorProvider selectorProvider;
    private Logger logger = LoggerFactory.getLogger(CSSObject.class);
    private final Map<String, Integer> breakpointInfo = new HashMap<String, Integer>();
    private String rawCss;
    private Set<String> referredImages = null;
    private String patternString = "\\burl\\(\\s*['\"]?(/.+?)['\"]?\\s*\\)";
    private Pattern pattern = Pattern.compile(this.patternString, 2);
    private String urlPatternString = "(\\burl\\(\\s*['\"]?)(.*?)(\\s*['\"]?\\))";
    private Pattern urlPattern = Pattern.compile(this.urlPatternString, 2);
    private String absolutePathPatterString = "^[a-z]*?:?//.*|^/.*";
    private Pattern absolutePathPattern = Pattern.compile(this.absolutePathPatterString, 2);

    public CSSObject(SelectorProvider provider) {
        this.selectorProvider = provider;
        this.rawCss = "";
    }

    public CSSObject(SelectorProvider provider, Boolean extractReferredImages) {
        this(provider);
        if (extractReferredImages.booleanValue()) {
            this.referredImages = new HashSet<String>();
        }
    }

    public CSSObject setBreakpointInfo(Map<String, Integer> breakpointInfo) {
        if (breakpointInfo != null) {
            this.breakpointInfo.putAll(breakpointInfo);
        }
        return this;
    }

    public CSSObject setRawCss(String rawCss) {
        if (rawCss != null && !rawCss.isEmpty()) {
            this.rawCss = rawCss;
        }
        return this;
    }

    public CSSObject addComponentStyles(JSONObject componentStyles, Resource styleConfig, String componentPath) {
        try {
            JSONObject selectors = (JSONObject)componentStyles.get("selectors");
            Iterator selectorsIterator = selectors.keys();
            Pattern urlPattern = Pattern.compile("url\\(\\s*[\"']?([^'\")]+)[\"']?\\s*\\)", 2);
            while (selectorsIterator.hasNext()) {
                String selectorName = (String)selectorsIterator.next();
                JSONObject selectorNode = (JSONObject)selectors.get(selectorName);
                JSONObject breakpointsNode = (JSONObject)selectorNode.get("breakpoints");
                Iterator breakpointNamesIterator = breakpointsNode.keys();
                while (breakpointNamesIterator.hasNext()) {
                    String breakpointName = (String)breakpointNamesIterator.next();
                    JSONObject breakpointNode = (JSONObject)breakpointsNode.get(breakpointName);
                    JSONObject statesParentNode = (JSONObject)breakpointNode.get("states");
                    Iterator statesIterator = statesParentNode.keys();
                    Integer breakPointValue = this.breakpointInfo.get(breakpointName);
                    if (breakPointValue == null) {
                        this.logger.error("no breakpoint information for " + breakpointName + " Ignoring ");
                        continue;
                    }
                    Breakpoint currentBreakpointStyles = this.breakpointStyleMap.get(breakPointValue);
                    if (currentBreakpointStyles == null) {
                        currentBreakpointStyles = new Breakpoint(breakpointName, breakPointValue);
                        this.breakpointStyleMap.put(breakPointValue, currentBreakpointStyles);
                    }
                    while (statesIterator.hasNext()) {
                        String stateName = (String)statesIterator.next();
                        JSONObject stateObject = (JSONObject)statesParentNode.get(stateName);
                        JSONObject properties = (JSONObject)stateObject.get("cssProperties");
                        Iterator propertiesIterator = properties.keys();
                        ArrayList<CSSProperty> cssProperties = new ArrayList<CSSProperty>();
                        while (propertiesIterator.hasNext()) {
                            try {
                                String key = (String)propertiesIterator.next();
                                String value = properties.getString(key);
                                if (componentPath != null) {
                                    value = this.convertRelativeToAbsoluteUrl(value, componentPath);
                                }
                                Matcher matcher = urlPattern.matcher(value);
                                if (this.referredImages != null && matcher.find()) {
                                    do {
                                        String assetID = matcher.group(1);
                                        if (!(assetID = assetID.trim()).startsWith("/content/dam/")) continue;
                                        this.referredImages.add(assetID);
                                    } while (matcher.find());
                                }
                                CSSProperty cssProperty = this.getCSSProperty(key, value);
                                cssProperties.add(cssProperty);
                            }
                            catch (Exception e) {
                                this.logger.warn("unable to read css properties.Ignoring ", (Throwable)e);
                            }
                        }
                        String selectorPath = "items/" + selectorName.replaceAll("/", "/items/");
                        Resource selectorResource = this.getSelectorResource(styleConfig, selectorPath);
                        Selector selector = null;
                        if (selectorResource != null) {
                            ValueMap props = selectorResource.getValueMap();
                            JSONObject htmlAttrs = null;
                            if (((Boolean)props.get("useIdSelector", (Object)false)).booleanValue() && selectorNode.has("htmlAttrs")) {
                                htmlAttrs = selectorNode.getJSONObject("htmlAttrs");
                            }
                            Resource stateResource = selectorResource;
                            if (!stateName.equals("default")) {
                                String statePath = "states/" + stateName;
                                stateResource = selectorResource.getChild(statePath);
                            }
                            if (stateResource != null) {
                                selector = this.selectorProvider.getCSSRule(styleConfig, cssProperties, stateResource, htmlAttrs);
                            }
                        }
                        if (selector != null) {
                            currentBreakpointStyles.addSelector(selector);
                            continue;
                        }
                        this.logger.warn("unable to get style for selector " + selectorName + ":" + stateName);
                    }
                }
            }
        }
        catch (JSONException e) {
            this.logger.warn("JSON Exception while adding component style", (Throwable)e);
        }
        return this;
    }

    private Resource getSelectorResource(Resource parentResource, String selectorPath) {
        if (parentResource == null) {
            return null;
        }
        Resource selectorResource = parentResource.getChild(selectorPath);
        if (selectorResource != null) {
            return this.getTargetResource(selectorResource);
        }
        if (selectorPath.contains("/")) {
            int indexOfSlash = selectorPath.indexOf("/");
            String nodeName = selectorPath.substring(0, indexOfSlash);
            String remainingPath = selectorPath.substring(indexOfSlash + 1);
            Resource childResource = parentResource.getChild(nodeName);
            if (childResource != null) {
                Resource targetResource = this.getTargetResource(childResource);
                return this.getSelectorResource(targetResource, remainingPath);
            }
        }
        return null;
    }

    private Resource getTargetResource(Resource resource) {
        ValueMap values = resource.getValueMap();
        String target = (String)values.get("target", String.class);
        if (target != null) {
            ResourceResolver resolver = resource.getResourceResolver();
            return resolver.getResource(target);
        }
        return resource;
    }

    private String getPseudoElementSelector(String selectorString, String pseudoElementString) {
        StringBuilder selectorValueBuilder = new StringBuilder();
        StringTokenizer st = new StringTokenizer(selectorString, ",");
        while (st.hasMoreElements()) {
            selectorValueBuilder.append(st.nextElement()).append(pseudoElementString);
            if (!st.hasMoreElements()) continue;
            selectorValueBuilder.append(",");
        }
        return selectorValueBuilder.toString();
    }

    private CSSProperty getCSSProperty(String key, String value) {
        return new CSSProperty(key, value);
    }

    public Set<String> getReferredImages() {
        return this.referredImages;
    }

    private String applyCssClass(String className, String selector) {
        if (StringUtils.isEmpty((String)className)) {
            return selector;
        }
        String[] selectors = selector.split(",");
        Object[] newSelectorString = new String[selectors.length];
        int i = 0;
        for (String cssSelector : selectors) {
            newSelectorString[i++] = "." + className + cssSelector;
        }
        return org.apache.commons.lang3.StringUtils.join((Object[])newSelectorString, (String)",");
    }

    public String generateCSSString(boolean useImportant, String contextPath) {
        StringBuilder cssStringBuilder = new StringBuilder();
        NavigableMap<Integer, Breakpoint> navMap = this.breakpointStyleMap.descendingMap();
        Set<Map.Entry<Integer, Breakpoint>> collection = navMap.entrySet();
        for (Map.Entry<Integer, Breakpoint> entry : collection) {
            Breakpoint breakpoint = entry.getValue();
            if (!breakpoint.getName().equals("default")) {
                cssStringBuilder.append("@media (max-width: ").append(breakpoint.getMax()).append("px) {\n");
            }
            List<Selector> cssSelectorCollection = breakpoint.getSelectors();
            for (Selector cssSelector : cssSelectorCollection) {
                StringBuilder extraCSSStringBuilder = new StringBuilder();
                String selectorString = cssSelector.getSelectorString();
                if (selectorString == null) continue;
                cssStringBuilder.append(selectorString).append("  {\n");
                List<CSSProperty> cssProperties = cssSelector.getCssProperties();
                for (CSSProperty property : cssProperties) {
                    if (property.getKey().equals("cssOverride")) {
                        cssStringBuilder.append(this.prependContextPath(property.getValue(), contextPath));
                        continue;
                    }
                    if (property.getKey().equals("afterPseudoElement")) {
                        extraCSSStringBuilder.append("\n" + this.getPseudoElementSelector(selectorString, "::after"));
                        extraCSSStringBuilder.append("{\n");
                        extraCSSStringBuilder.append(this.prependContextPath(property.getValue(), contextPath));
                        extraCSSStringBuilder.append("}\n");
                        continue;
                    }
                    if (property.getKey().equals("beforePseudoElement")) {
                        extraCSSStringBuilder.append("\n" + this.getPseudoElementSelector(selectorString, "::before"));
                        extraCSSStringBuilder.append("{\n");
                        extraCSSStringBuilder.append(this.prependContextPath(property.getValue(), contextPath));
                        extraCSSStringBuilder.append("}\n");
                        continue;
                    }
                    if (property.getKey().equals("addonCss")) {
                        try {
                            JSONObject addOnCSSObject = new JSONObject(property.getValue());
                            JSONObject selectors = addOnCSSObject.getJSONObject("selectors");
                            Iterator selectorKeys = selectors.keys();
                            while (selectorKeys.hasNext()) {
                                String key = (String)selectorKeys.next();
                                JSONObject selector = selectors.getJSONObject(key);
                                String cssSelectorString = this.applyCssClass(cssSelector.getCssClassPrefixString(), selector.getString("cssSelector"));
                                extraCSSStringBuilder.append(cssSelectorString + " {\n");
                                JSONObject properties = selector.getJSONObject("properties");
                                Iterator propertyKeys = properties.keys();
                                while (propertyKeys.hasNext()) {
                                    String propertyKey = (String)propertyKeys.next();
                                    String propValue = properties.getString(propertyKey);
                                    extraCSSStringBuilder.append(propertyKey + ":" + propValue + ";\n");
                                }
                                extraCSSStringBuilder.append("}\n");
                            }
                            continue;
                        }
                        catch (JSONException e) {
                            this.logger.error("Unable to parse addonCss object", (Throwable)e);
                            continue;
                        }
                    }
                    cssStringBuilder.append("    ").append(property.getKey()).append(":");
                    if (property.getValuePrefix() != null) {
                        cssStringBuilder.append(property.getValuePrefix());
                    }
                    cssStringBuilder.append(this.prependContextPath(property.getValue(), contextPath));
                    if (property.getValueSuffix() != null) {
                        cssStringBuilder.append(property.getValueSuffix());
                    }
                    if (useImportant) {
                        cssStringBuilder.append("!important");
                    }
                    cssStringBuilder.append(";\n");
                }
                cssStringBuilder.append("  }\n");
                cssStringBuilder.append(extraCSSStringBuilder.toString());
            }
            if (breakpoint.getName().equals("default")) continue;
            cssStringBuilder.append("}\n");
        }
        cssStringBuilder.append("\n" + this.rawCss);
        return cssStringBuilder.toString();
    }

    private String prependContextPath(String urlString, String contextPath) {
        Matcher matcher;
        if (StringUtils.isNotBlank((String)contextPath) && StringUtils.isNotBlank((String)urlString) && (matcher = this.pattern.matcher(urlString)).find()) {
            urlString = matcher.replaceAll("url('" + contextPath + "$1" + "')");
        }
        return urlString;
    }

    private String convertRelativeToAbsoluteUrl(String urlString, String componentPath) {
        if (StringUtils.isNotBlank((String)urlString) && StringUtils.isNotBlank((String)componentPath)) {
            StringBuffer updatedUrlString = new StringBuffer();
            Matcher matcher = this.urlPattern.matcher(urlString);
            while (matcher.find()) {
                matcher.appendReplacement(updatedUrlString, matcher.group(1) + this.makePathAbsolute(matcher.group(2), componentPath) + matcher.group(3));
            }
            matcher.appendTail(updatedUrlString);
            return updatedUrlString.toString();
        }
        return urlString;
    }

    private Boolean isAbsolutePath(String path) {
        if (path == null || path.isEmpty()) {
            return true;
        }
        Matcher matcher = this.absolutePathPattern.matcher(path);
        if (matcher.find()) {
            return true;
        }
        return false;
    }

    private String makePathAbsolute(String path, String componentPath) {
        if (this.isAbsolutePath(path).booleanValue()) {
            return path;
        }
        return componentPath + "/" + path;
    }

    /*
     * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
     */
    public static abstract class SelectorProvider {
        public static final String USE_ID_SELECTOR = "useIdSelector";
        private String CSS_SELECTOR_PROP_NAME = "cssSelector";

        protected boolean isIdSelector(Resource selectorResource) {
            ValueMap props = (ValueMap)selectorResource.adaptTo(ValueMap.class);
            return (Boolean)props.get("useIdSelector", (Object)false);
        }

        protected String getSelectorString(Resource stateResource) {
            ValueMap props = (ValueMap)stateResource.adaptTo(ValueMap.class);
            return (String)props.get((Object)this.CSS_SELECTOR_PROP_NAME);
        }

        public abstract Selector getCSSRule(Resource var1, List<CSSProperty> var2, Resource var3, JSONObject var4);
    }

}