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

com.day.cq.wcm.foundation.model.responsivegrid.ResponsiveGrid Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2017 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 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.day.cq.wcm.foundation.model.responsivegrid;

import aQute.bnd.annotation.ProviderType;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.day.cq.wcm.api.NameConstants;
import com.day.cq.wcm.api.TemplatedResource;
import com.day.cq.wcm.api.designer.ComponentStyle;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.foundation.model.responsivegrid.export.ResponsiveGridExporter;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.AbstractResource;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.factory.ModelFactory;

import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * Sling model for the Responsive grid component.
 * A Responsive grid component provides access to its columns and generates a set of specific responsive data.
 */
@Model(
        adaptables                  = SlingHttpServletRequest.class,
        adapters                    = { ResponsiveGrid.class, ComponentExporter.class },
        defaultInjectionStrategy    = DefaultInjectionStrategy.OPTIONAL,
        resourceType                = ResponsiveGrid.RESOURCE_TYPE)
@Exporter(
        name                        = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
        selector                    = ExporterConstants.SLING_MODEL_SELECTOR,
        extensions                  = ExporterConstants.SLING_MODEL_EXTENSION)
@JsonSerialize(as = ResponsiveGridExporter.class)
@ProviderType
public class ResponsiveGrid extends AbstractResource implements ResponsiveGridExporter {

    protected static final String RESOURCE_TYPE = "wcm/foundation/components/responsivegrid";

    @Self
    private SlingHttpServletRequest slingRequest;

    @SlingObject
    private volatile Resource resource;

    @ScriptVariable
    private ValueMap properties;

    @ScriptVariable
    private Style currentStyle;

    @Inject
    private ModelFactory modelFactory;

    /**
     * Class names of the responsive grid
     */
    private String classNames;

    /**
     * Map containing all the class names exposed by columns
     */
    private Map columnClassNames = new HashMap();

    /**
     * Child columns of the responsive grid
     */
    private Map childColumns = new LinkedHashMap();

    /**
     * Number of columns set on the design or the default number of columns
     */
    private int columns;

    @PostConstruct
    protected void initModel() {
        Map breakpoints = new HashMap();
        Set missingParagraphBreakpointNames = new HashSet();

        // class prefix
        String classNamesPrefix = currentStyle.get("cssPrefix", ResponsiveConstants.DEFAULT_CSS_PREFIX);

        // grid columns css
        classNames = ResponsiveConstants.DEFAULT_CSS_PREFIX;

        // columns
        Resource responsiveCfg = resource.getChild(NameConstants.NN_RESPONSIVE_CONFIG);

        Resource responsiveParentCfg = null;
        Resource parent = resource.getParent();
        if (parent != null) {
            responsiveParentCfg = parent.getChild(NameConstants.NN_RESPONSIVE_CONFIG);
        }

        boolean hasResponsiveCfgSize = false;

        columns = currentStyle.get("columns", ResponsiveConstants.DEFAULT_COLUMNS);

        // Columns provided by the design
        int width = currentStyle.get("columns", 0);
        int offset = currentStyle.get("offset", 0);

        boolean hasDesignValues = (width > 0) || currentStyle.containsKey("offset");

        int initialDefaultWidth = ResponsiveConstants.DEFAULT_COLUMNS;
        Resource effectiveResource = getEffectiveResource();

        // The initial width may also come from the configuration of the structure resource backing-up the current grid
        Resource effectiveResponsiveConfig =
                effectiveResource.getChild(
                        NameConstants.NN_RESPONSIVE_CONFIG + "/" +
                                ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT);

        if (effectiveResponsiveConfig != null && effectiveResponsiveConfig.getValueMap().containsKey("width")) {
            initialDefaultWidth =
                    effectiveResponsiveConfig.getValueMap().get("width", ResponsiveConstants.DEFAULT_COLUMNS);
        }

        if (responsiveCfg != null) {
            for (Iterator resCfgIt = responsiveCfg.listChildren(); resCfgIt.hasNext();) {
                Resource resCfg = resCfgIt.next();
                String breakpointName = resCfg.getName();
                ValueMap cfg = resCfg.adaptTo(ValueMap.class);
                Breakpoint.ResponsiveBehavior behavior =
                        Breakpoint.ResponsiveBehavior.valueOf(
                                cfg.get("behavior",
                                        Breakpoint.ResponsiveBehavior.none.toString()));

                if (!hasDesignValues) {
                    int resWidth = cfg.get("width", 0);
                    int resOffset = cfg.get("offset", 0);

                    width = (resWidth > 0) ? resWidth : width;
                    offset = (resOffset > 0) ? resOffset : offset;
                }

                if (width > 0) {
                    // Adapt the width and offset based on the one of the parent
                    if (responsiveParentCfg != null) {
                        Resource parentBreakpoint = responsiveParentCfg.getChild(breakpointName);

                        // The width + the offset of the responsive grid cannot be bigger than the one of its parent
                        if (parentBreakpoint != null) {
                            ValueMap parentCfg = parentBreakpoint.adaptTo(ValueMap.class);
                            int parentWidth = parentCfg.get("width", width);

                            if (width + offset > parentWidth) {
                                width = parentWidth;
                                offset = 0;
                            }
                        }
                    }
                }

                breakpoints.put(breakpointName, new Breakpoint(breakpointName, width, offset, behavior));

                if (width > 0) {
                    hasResponsiveCfgSize = true;
                    classNames += " " + ResponsiveConstants.DEFAULT_CSS_PREFIX + "--" + breakpointName + "--" + width;
                }
            }
        }

        if (!hasResponsiveCfgSize) {
            int columns = currentStyle.get("columns", initialDefaultWidth);
            classNames += " " + ResponsiveConstants.DEFAULT_CSS_PREFIX + "--" + columns;
        }

        if (!breakpoints.containsKey(ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT)) {
            int columns = currentStyle.get("columns", initialDefaultWidth);
            breakpoints.put(
                    ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT,
                    new Breakpoint(ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT,
                            columns,
                            offset,
                            Breakpoint.ResponsiveBehavior.none));
            classNames += " " +
                    ResponsiveConstants.DEFAULT_CSS_PREFIX + "--" +
                    ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT + "--" + columns;
        }

        for (Iterator paragraphsIt = getEffectiveResource().listChildren(); paragraphsIt.hasNext();) {
            Resource child = paragraphsIt.next();
            if (!NameConstants.NN_RESPONSIVE_CONFIG.equals(child.getName())) {
                ResponsiveColumn column =
                        new ResponsiveColumn(child, breakpoints, classNamesPrefix, slingRequest, modelFactory);

                childColumns.put(column.getResource().getName(), column);

                // Add missing breakpoints originating from the resources
                Set columnBreakpointNames = new HashSet();

                Map columnBreakpoints = column.getBreakpoints();
                // Storing the class names of each column
                columnClassNames.put(column.getName(), column.getColumnClassNames());

                if (columnBreakpoints != null) {
                    columnBreakpointNames.addAll(columnBreakpoints.keySet());
                }

                columnBreakpointNames.removeAll(breakpoints.keySet());
                missingParagraphBreakpointNames.addAll(columnBreakpointNames);
            }
        }

        // In case a paragraph has a breakpoint that the grid doesn't
        // Add that breakpoint to the parent with the default value
        if (!missingParagraphBreakpointNames.isEmpty()) {
            for (String missingParagraphBreakpointName : missingParagraphBreakpointNames) {
                Breakpoint missingBreakpoint =  breakpoints.get(ResponsiveConstants.BREAKPOINT_VARIANT_NAME_DEFAULT);
                int missingWidth = missingBreakpoint.getWidth();
                int missingOffset = missingBreakpoint.getOffset();
                Breakpoint.ResponsiveBehavior missingBehavior = missingBreakpoint.getResponsiveBehavior();

                if (missingWidth == 0) {
                    missingWidth = currentStyle.get("columns", initialDefaultWidth);
                }

                if (missingWidth > 0) {
                    classNames += " " +
                            ResponsiveConstants.DEFAULT_CSS_PREFIX + "--" +
                            missingParagraphBreakpointName + "--" + missingWidth;
                }

                if (missingOffset > 0) {
                    classNames += " " +
                            ResponsiveConstants.DEFAULT_CSS_PREFIX + "--" +
                            ResponsiveConstants.OFFSET_CSS_VARIANT_NAME + "--" + missingParagraphBreakpointName + "--" + missingOffset;
                }

                breakpoints.put(
                        missingParagraphBreakpointName,
                        new Breakpoint(missingParagraphBreakpointName, missingWidth, missingOffset, missingBehavior));
            }
        }

        // add custom styles of the resource
        classNames += " " + properties.get(ComponentStyle.PN_CSS_CLASS, "");

        classNames = classNames.trim();
    }

    @Override
    public String getGridClassNames() {
        return classNames;
    }

    @Override
    public Map getColumnClassNames() {
        return columnClassNames;
    }

    @Override
    public int getColumnCount() {
        return columns;
    }

    /**
     * @return The columns of the current responsive grid.
     */
    @Nonnull
    public Collection getColumns() {
        return childColumns.values();
    }

    /**
     * @return The columns of the current responsive grid.
     * @deprecated Use {@link #getColumns()}
     */
    public List getParagraphs() {
        return new ArrayList(getColumns());
    }

    /**
     * @return The CSS class names to be applied to the current grid.
     * @deprecated Use {@link #getGridClassNames()}
     */
    public String getCssClass() {
        return classNames;
    }

    /**
     * @param  The type of the resource
     * @return Returns the resource optionally wrapped into a {@link TemplatedResource}
     *
     * AdobePatentID="P6273-US"
     */
    @Nonnull
    public  T getEffectiveResource() {
        if (resource instanceof TemplatedResource) {
            return (T) resource;
        }

        Resource templatedResource = slingRequest.adaptTo(TemplatedResource.class);

        if (templatedResource == null) {
            return (T) resource;
        } else {
            return (T) templatedResource;
        }
    }

    @Nonnull
    @Override
    public String getPath() {
        return resource.getPath();
    }

    /**
     * @deprecated
     */
    @Nonnull
    @Override
    public String getResourceType() {
        return resource.getResourceType();
    }

    /**
     * @deprecated
     */
    public String getResourceSuperType() {
        return resource.getResourceSuperType();
    }

    /**
     * @deprecated
     */
    @Nonnull
    @Override
    public ResourceMetadata getResourceMetadata() {
        return resource.getResourceMetadata();
    }

    /**
     * @deprecated
     */
    @Nonnull
    @Override
    public ResourceResolver getResourceResolver() {
        return resource.getResourceResolver();
    }

    @Nonnull
    @Override
    public Map getExportedItems() {
        return childColumns;
    }

    @Nonnull
    @Override
    public String[] getExportedItemsOrder() {
        return childColumns.isEmpty() ?
                new String[0] : childColumns.keySet().toArray(new String[childColumns.size()]);
    }

    @Nonnull
    @Override
    public String getExportedType() {
        return resource.getResourceType();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy