Skip to content

Commit

Permalink
reduce duplication
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanseifert committed Sep 4, 2023
1 parent 0bfa813 commit 666b2c7
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 317 deletions.
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) {
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

0 comments on commit 666b2c7

Please sign in to comment.