Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image v3 #13

Merged
merged 10 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bundles/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
<parent>
<groupId>io.wcm</groupId>
<artifactId>io.wcm.wcm.core.components.parent</artifactId>
<version>1.13.3-2.22.6-SNAPSHOT</version>
<version>1.14.0-2.22.6-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

<groupId>io.wcm</groupId>
<artifactId>io.wcm.wcm.core.components</artifactId>
<version>1.13.3-2.22.6-SNAPSHOT</version>
<version>1.14.0-2.22.6-SNAPSHOT</version>
<packaging>jar</packaging>

<name>WCM Core Components</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,29 @@
*/
package io.wcm.wcm.core.components.impl.models.v2;

import static com.day.cq.commons.ImageResource.PN_ALT;
import static com.day.cq.commons.jcr.JcrConstants.JCR_TITLE;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.models.Image;
import com.adobe.cq.wcm.core.components.models.ImageArea;
import com.adobe.cq.wcm.core.components.models.datalayer.ImageData;
import com.adobe.cq.wcm.core.components.models.datalayer.builder.AssetDataBuilder;
import com.adobe.cq.wcm.core.components.models.datalayer.builder.DataLayerBuilder;
import com.day.cq.wcm.api.designer.Style;
import com.fasterxml.jackson.annotation.JsonIgnore;

import io.wcm.handler.link.Link;
import io.wcm.handler.link.LinkHandler;
import io.wcm.handler.media.Asset;
import io.wcm.handler.media.Media;
import io.wcm.handler.media.MediaHandler;
import io.wcm.handler.media.Rendition;
import io.wcm.handler.url.UrlHandler;
import io.wcm.sling.models.annotations.AemObject;
import io.wcm.wcm.core.components.impl.models.helpers.AbstractComponentImpl;
import io.wcm.wcm.core.components.impl.models.helpers.ImageAreaV1Impl;
import io.wcm.wcm.core.components.impl.models.v3.ImageV3Impl;
import io.wcm.wcm.core.components.impl.servlets.ImageWidthProxyServlet;
import io.wcm.wcm.core.components.impl.util.HandlerUnwrapper;
import io.wcm.wcm.core.components.models.mixin.LinkMixin;
import io.wcm.wcm.core.components.models.mixin.MediaMixin;

/**
* wcm.io-based enhancements for {@link Image}:
Expand All @@ -84,222 +60,36 @@
@Exporter(
name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ImageV2Impl extends AbstractComponentImpl implements Image, MediaMixin, LinkMixin {
public class ImageV2Impl extends ImageV3Impl implements LinkMixin {

/**
* Resource type
*/
public static final String RESOURCE_TYPE = "wcm-io/wcm/core/components/image/v2/image";
private static final String WIDTH_PLACEHOLDER = "{.width}";

@AemObject
private Style currentStyle;
@Self
private LinkHandler linkHandler;
@Self
private MediaHandler mediaHandler;
@Self
private UrlHandler urlHandler;

@ValueMapValue(name = PN_ALT, injectionStrategy = InjectionStrategy.OPTIONAL)
private @Nullable String alt;
@ValueMapValue(name = JCR_TITLE, injectionStrategy = InjectionStrategy.OPTIONAL)
private @Nullable String title;

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
private @Nullable String imageCrop;
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
private @Nullable String imageRotate;

private Link link;
private Media media;
private String uuid;
private String fileReference;
private boolean displayPopupTitle;
private boolean enableLazyLoading;
private int lazyThreshold;
private boolean isDecorative;
private List<ImageArea> areas;

private List<Long> widths = Collections.emptyList();
private long noScriptWidth;
private String srcPattern;

@PostConstruct
private void activate() {
ValueMap properties = resource.getValueMap();

// read basic properties
displayPopupTitle = properties.get(PN_DISPLAY_POPUP_TITLE, currentStyle.get(PN_DISPLAY_POPUP_TITLE, true));
enableLazyLoading = !currentStyle.get(PN_DESIGN_LAZY_LOADING_ENABLED, true);
lazyThreshold = currentStyle.get(PN_DESIGN_LAZY_THRESHOLD, 0);
isDecorative = properties.get(PN_IS_DECORATIVE, currentStyle.get(PN_IS_DECORATIVE, false));
boolean altFromAsset = properties.get(PN_ALT_VALUE_FROM_DAM, currentStyle.get(PN_ALT_VALUE_FROM_DAM, true));

// resolve media and properties from DAM asset
media = HandlerUnwrapper.get(mediaHandler, resource)
@Override
protected Media buildMedia(boolean altFromAsset, boolean imageFromPageImage) {
return HandlerUnwrapper.get(mediaHandler, resource)
// disable dynamic media support as it is not compatible with the "src-pattern" concept
.dynamicMediaDisabled(true)
.decorative(isDecorative)
.forceAltValueFromAsset(altFromAsset)
.build();
if (media.isValid() && !media.getRendition().isImage()) {
// no image asset selected (cannot be rendered) - set to invalid
media = mediaHandler.invalid();
}
if (media.isValid()) {
initPropertiesFromDamAsset(properties);
widths = buildRenditionWidths(media.getRendition());
noScriptWidth = getNoScriptWidth();
srcPattern = buildSrcPattern(media.getUrl());
areas = ImageAreaV1Impl.convertMap(media.getMap());
}

// resolve link - decorative images have no link and no alt text by definition
if (isDecorative) {
link = linkHandler.invalid();
}
else {
link = HandlerUnwrapper.get(linkHandler, resource).build();
}
}

/**
* Checks if the resolved media is a DAM asset, and initializes properties from it.
* @param properties Resource properties
*/
private void initPropertiesFromDamAsset(ValueMap properties) {
Asset asset = media.getAsset();
if (asset != null) {
com.day.cq.dam.api.Asset damAsset = asset.adaptTo(com.day.cq.dam.api.Asset.class);
if (damAsset != null) {
boolean titleFromAsset = properties.get(PN_TITLE_VALUE_FROM_DAM, currentStyle.get(PN_TITLE_VALUE_FROM_DAM, true));
boolean uuidDisabled = currentStyle.get(PN_UUID_DISABLED, false);

fileReference = damAsset.getPath();
alt = asset.getAltText();

if (!uuidDisabled) {
uuid = damAsset.getID();
}

if (titleFromAsset) {
String assetTitle = asset.getTitle();
if (StringUtils.isNotEmpty(assetTitle)) {
title = assetTitle;
}
}
}
}
}

@Override
@NotNull
public Link getLinkObject() {
return link;
}

@Override
@NotNull
public Media getMediaObject() {
return media;
}

@Override
public String getSrc() {
if (noScriptWidth > 0) {
return StringUtils.replace(srcPattern, WIDTH_PLACEHOLDER, "." + noScriptWidth);
}
else {
return media.getUrl();
}
}

@Override
public String getAlt() {
return alt;
}

@Override
public String getTitle() {
return title;
}

@Override
public String getUuid() {
return uuid;
}

/**
* @deprecated Deprecated in API
*/
@Override
@Deprecated
public String getLink() {
return link.getUrl();
}

@Override
public boolean displayPopupTitle() {
return displayPopupTitle;
}

@Override
public String getFileReference() {
return fileReference;
}

@Override
public boolean isLazyEnabled() {
return enableLazyLoading;
}

@Override
public int getLazyThreshold() {
return lazyThreshold;
}

@Override
public String getSrcUriTemplate() {
return srcPattern;
}

@Override
public int @NotNull [] getWidths() {
return widths.stream()
.mapToInt(Long::intValue)
.toArray();
}

@Override
public List<ImageArea> getAreas() {
return areas;
}

@Override
public boolean isDecorative() {
return isDecorative;
protected List<ImageArea> buildAreas() {
return ImageAreaV1Impl.convertMap(media.getMap());
}

/**
* @deprecated Deprecated in API
*/
@Override
@Deprecated
public String getJson() {
// not required for image v2
return null;
}


/**
* Validates the configured list of widths, removes those that are bigger than the original rendition,
* and returns them sorted by size.
* @param rendition Primary rendition
* @return Widths
*/
private List<Long> buildRenditionWidths(Rendition rendition) {
long maxWidth = rendition.getWidth();
@Override
protected List<Long> buildRenditionWidths() {
long maxWidth = media.getRendition().getWidth();
String[] configuredWidths = currentStyle.get(PN_DESIGN_ALLOWED_RENDITION_WIDTHS, new String[0]);
return Arrays.stream(configuredWidths)
.map(NumberUtils::toLong)
Expand All @@ -308,23 +98,13 @@ private List<Long> buildRenditionWidths(Rendition rendition) {
.collect(Collectors.toList());
}

/**
* Picks a "medium" widths from the set of available widths.
* @return Picked width
*/
private long getNoScriptWidth() {
if (widths.isEmpty()) {
return 0;
}
return widths.get((int)Math.round(widths.size() / 2d - 0.5d));
}

/**
* Build image url pattern based in ImageWidthServlet for dynamic rendition selection.
* @param mediaUrl Media Url
* @return Url pattern
*/
private String buildSrcPattern(String mediaUrl) {
@Override
protected String buildSrcPattern() {
String mediaUrl = media.getUrl();
String extension = StringUtils.substringAfterLast(mediaUrl, ".");
String fileName = StringUtils.substringAfterLast(mediaUrl, "/");

Expand All @@ -349,23 +129,32 @@ private String buildSrcPattern(String mediaUrl) {
"." + ImageWidthProxyServlet.SELECTOR + WIDTH_PLACEHOLDER + ".");
}

// --- data layer ---
@Override
@NotNull
public Link getLinkObject() {
return link.getLinkObject();
}

@Override
@JsonIgnore
@SuppressWarnings("null")
public @NotNull ImageData getComponentData() {
return DataLayerBuilder.extending(super.getComponentData()).asImageComponent()
.withTitle(this::getTitle)
.withLinkUrl(this::getLink)
.withAssetData(() -> Optional.of(media)
.filter(Media::isValid)
.map(Media::getAsset)
.map(asset -> asset.adaptTo(com.day.cq.dam.api.Asset.class))
.map(DataLayerBuilder::forAsset)
.map(AssetDataBuilder::build)
.orElse(null))
.build();
public String getSrc() {
long noScriptWidth = getNoScriptWidth();
if (noScriptWidth > 0) {
return StringUtils.replace(srcPattern, WIDTH_PLACEHOLDER, "." + noScriptWidth);
}
else {
return media.getUrl();
}
}

/**
* Picks a "medium" widths from the set of available widths.
* @return Picked width
*/
private long getNoScriptWidth() {
if (widths.isEmpty()) {
return 0;
}
return widths.get((int)Math.round(widths.size() / 2d - 0.5d));
}

}
Loading