Skip to content

Commit 74b79ea

Browse files
committed
Merge branch 'main' into SITES-26758
2 parents 10912f5 + a3ac4a5 commit 74b79ea

File tree

9 files changed

+359
-13
lines changed

9 files changed

+359
-13
lines changed

bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v2/TeaserImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ protected void initImage() {
8181
overriddenImageResourceProperties.put(Teaser.PN_ACTIONS_ENABLED, Boolean.valueOf(actionsEnabled).toString());
8282
overriddenImageResourceProperties.put(PN_ID, String.join(ID_SEPARATOR, this.getId(), IMAGE_ID_PREFIX));
8383

84-
if (StringUtils.isNotEmpty(getTitle()) || getTeaserActions().size() > 0) {
84+
// Only allow image to render links if all other elements are empty
85+
if (!(StringUtils.isAllBlank(getTitle(), getPretitle(), getDescription()) && getTeaserActions().isEmpty())) {
8586
overriddenImageResourceProperties.put(Teaser.PN_IMAGE_LINK_HIDDEN, Boolean.TRUE.toString());
8687
}
8788
super.initImage();

bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v2/TeaserImplTest.java

+29-5
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717

1818
import java.util.Objects;
1919

20-
import com.adobe.cq.ui.wcm.commons.config.NextGenDynamicMediaConfig;
21-
import com.adobe.cq.wcm.core.components.models.Component;
22-
import com.adobe.cq.wcm.core.components.testing.MockNextGenDynamicMediaConfig;
2320
import org.apache.sling.api.resource.Resource;
2421
import org.apache.sling.api.resource.ValueMap;
2522
import org.junit.jupiter.api.BeforeEach;
@@ -28,23 +25,26 @@
2825

2926
import com.adobe.cq.wcm.core.components.Utils;
3027
import com.adobe.cq.wcm.core.components.commons.link.Link;
28+
import com.adobe.cq.wcm.core.components.models.Component;
3129
import com.adobe.cq.wcm.core.components.models.ListItem;
3230
import com.adobe.cq.wcm.core.components.models.Teaser;
31+
import com.adobe.cq.wcm.core.components.testing.MockNextGenDynamicMediaConfig;
32+
import com.day.cq.wcm.foundation.Image;
3333
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
3434

3535
import static com.adobe.cq.wcm.core.components.internal.link.LinkTestUtils.assertValidLink;
3636
import static org.junit.jupiter.api.Assertions.assertEquals;
37-
import static org.junit.jupiter.api.Assertions.assertNotNull;
3837
import static org.junit.jupiter.api.Assertions.assertNull;
3938
import static org.junit.jupiter.api.Assertions.assertTrue;
40-
import static org.mockito.Mockito.mock;
4139

4240
@ExtendWith(AemContextExtension.class)
4341
public class TeaserImplTest extends com.adobe.cq.wcm.core.components.internal.models.v1.TeaserImplTest {
4442

4543
private static final String TEST_BASE = "/teaser/v2";
4644
private static final String TEASER_25 = TEST_ROOT_PAGE + TEST_ROOT_PAGE_GRID + "/teaser-25";
4745
private static final String TEASER_26 = TEST_ROOT_PAGE + TEST_ROOT_PAGE_GRID + "/teaser-26";
46+
private static final String TEASER_27 = TEST_ROOT_PAGE + TEST_ROOT_PAGE_GRID + "/teaser-27";
47+
private static final String TEASER_28 = TEST_ROOT_PAGE + TEST_ROOT_PAGE_GRID + "/teaser-28";
4848

4949
@BeforeEach
5050
protected void setUp() {
@@ -206,4 +206,28 @@ protected void testTeaserWithNgdmImage() {
206206
assertEquals("Teasers Test", teaser.getTitle());
207207
Utils.testJSONExport(teaser, Utils.getTestExporterJSONPath(testBase, "teaser26"));
208208
}
209+
210+
@Test
211+
protected void testTeaserWithImageAndLinkAndNoTitleAndPretitleAndNoDescription() {
212+
Teaser teaser = getTeaserUnderTest(TEASER_27);
213+
assertEquals("Teaser Pre-title", teaser.getPretitle());
214+
assertNull(teaser.getTitle());
215+
assertNull(teaser.getDescription());
216+
ValueMap imageValueMap = teaser.getImageResource().getValueMap();
217+
assertEquals("/content/page1", imageValueMap.get(Image.PN_LINK_URL));
218+
assertTrue(imageValueMap.get(Teaser.PN_IMAGE_LINK_HIDDEN, Boolean.class));
219+
Utils.testJSONExport(teaser, Utils.getTestExporterJSONPath(testBase, "teaser27"));
220+
}
221+
222+
@Test
223+
protected void testTeaserWithImageAndLinkAndNoTitleAndNoPretitleAndNoDescription() {
224+
Teaser teaser = getTeaserUnderTest(TEASER_28);
225+
assertNull(teaser.getPretitle());
226+
assertNull(teaser.getTitle());
227+
assertNull(teaser.getDescription());
228+
ValueMap imageValueMap = teaser.getImageResource().getValueMap();
229+
assertEquals("/content/page1", imageValueMap.get(Image.PN_LINK_URL));
230+
assertNull(imageValueMap.get(Teaser.PN_IMAGE_LINK_HIDDEN, Boolean.class));
231+
Utils.testJSONExport(teaser, Utils.getTestExporterJSONPath(testBase, "teaser28"));
232+
}
209233
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"id" : "teaser-721d56e29c",
3+
"pretitle" : "Teaser Pre-title",
4+
"actionsEnabled" : true,
5+
"imageLinkHidden": false,
6+
"titleLinkHidden": false,
7+
"actions" : [],
8+
"link" : {
9+
"valid": true,
10+
"url" : "/core/content/page1.html"
11+
},
12+
"imagePath" : "/core/content/teasers/_jcr_content/root/responsivegrid/teaser-27.coreimg.png/1490005239000/adobe-systems-logo-and-wordmark.png",
13+
":type" : "core/wcm/components/teaser/v2/teaser",
14+
"dataLayer" : {
15+
"teaser-721d56e29c": {
16+
"@type" : "core/wcm/components/teaser/v2/teaser",
17+
"xdm:linkURL" : "/core/content/page1.html"
18+
}
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"id" : "teaser-2dda15a9bc",
3+
"actionsEnabled" : true,
4+
"imageLinkHidden": false,
5+
"titleLinkHidden": false,
6+
"actions" : [],
7+
"link" : {
8+
"valid": true,
9+
"url" : "/core/content/page1.html"
10+
},
11+
"imagePath" : "/core/content/teasers/_jcr_content/root/responsivegrid/teaser-28.coreimg.png/1490005239000/adobe-systems-logo-and-wordmark.png",
12+
":type" : "core/wcm/components/teaser/v2/teaser",
13+
"dataLayer" : {
14+
"teaser-2dda15a9bc": {
15+
"@type" : "core/wcm/components/teaser/v2/teaser",
16+
"xdm:linkURL" : "/core/content/page1.html"
17+
}
18+
}
19+
}

bundles/core/src/test/resources/teaser/v2/test-content.json

+17
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,23 @@
317317
"sling:resourceType": "core/wcm/components/teaser/v2/teaser",
318318
"titleFromPage": true,
319319
"descriptionFromPage": true
320+
},
321+
"teaser-27" : {
322+
"jcr:primaryType" : "nt:unstructured",
323+
"linkURL" : "/content/page1",
324+
"fileReference" : "/content/dam/core/images/Adobe_Systems_logo_and_wordmark.png",
325+
"sling:resourceType" : "core/wcm/components/teaser/v2/teaser",
326+
"pretitle" : "Teaser Pre-title",
327+
"titleFromPage" : false,
328+
"descriptionFromPage" : false
329+
},
330+
"teaser-28" : {
331+
"jcr:primaryType" : "nt:unstructured",
332+
"linkURL" : "/content/page1",
333+
"fileReference" : "/content/dam/core/images/Adobe_Systems_logo_and_wordmark.png",
334+
"sling:resourceType" : "core/wcm/components/teaser/v2/teaser",
335+
"titleFromPage" : false,
336+
"descriptionFromPage" : false
320337
}
321338
}
322339
}

content/src/content/jcr_root/apps/core/wcm/components/contentfragment/v1/contentfragment/clientlibs/editor/authoring/js/editAction.js

+32-6
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,15 @@
2020
var CLASS_CONTENTFRAGMENT = "cmp-contentfragment";
2121
// name of the attribute on the content fragment storing its path
2222
var ATTRIBUTE_PATH = "data-cmp-contentfragment-path";
23-
// base URL of the editor
23+
// unified shell endpoints for internal stage and for prod
24+
var UNIFIED_SHELL_STAGE_ENDPOINT = "https://experience-stage.adobe.com/";
25+
var UNIFIED_SHELL_PROD_ENDPOINT = "https://experience.adobe.com/";
26+
// identifier of internal stage env
27+
var AEM_STAGE_ENV = "cmstg";
28+
// base URL of the old cf editor
2429
var EDITOR_URL = "/editor.html";
30+
// feature toggle enabling opening the cf in the new editor
31+
var FT_USE_NEW_EDITOR = "FT_SITES-19326";
2532

2633
var ContentFragmentEditor = ns.util.createClass({
2734

@@ -37,14 +44,33 @@
3744
// get the path of the content fragment
3845
var fragmentPath = $(editable.dom).find("." + CLASS_CONTENTFRAGMENT).attr(ATTRIBUTE_PATH);
3946
if (fragmentPath) {
40-
var fragmentEditUrl = EDITOR_URL + fragmentPath;
41-
var fragment = ns.CFM.Fragments.adaptToFragment(editable.dom);
42-
if (fragment && typeof fragment.variation !== "undefined" && fragment.variation !== "master") {
43-
fragmentEditUrl = fragmentEditUrl + "?variation=" + fragment.variation;
47+
var editorUrl = "";
48+
// check if the url for the new editor should be used
49+
if (Granite.Toggles && Granite.Toggles.isEnabled(FT_USE_NEW_EDITOR)) {
50+
editorUrl = this.getNewEditorUrl(fragmentPath);
51+
} else {
52+
editorUrl = EDITOR_URL + fragmentPath;
53+
var fragment = ns.CFM.Fragments.adaptToFragment(editable.dom);
54+
if (fragment && typeof fragment.variation !== "undefined" && fragment.variation !== "master") {
55+
editorUrl = editorUrl + "?variation=" + fragment.variation;
56+
}
57+
editorUrl = Granite.HTTP.externalize(editorUrl);
4458
}
4559
// open the editor in a new window
46-
window.open(Granite.HTTP.externalize(fragmentEditUrl));
60+
window.open(editorUrl);
4761
}
62+
},
63+
64+
getNewEditorUrl: function(fragmentPath) {
65+
var newEditorUrl = "";
66+
var hostNameAEM = window.location.hostname;
67+
if (hostNameAEM.indexOf(AEM_STAGE_ENV) !== -1) {
68+
newEditorUrl = UNIFIED_SHELL_STAGE_ENDPOINT;
69+
} else {
70+
newEditorUrl = UNIFIED_SHELL_PROD_ENDPOINT;
71+
}
72+
newEditorUrl += "?repo=" + hostNameAEM + "#/aem/cf/editor" + fragmentPath;
73+
return newEditorUrl;
4874
}
4975

5076
});

content/src/content/jcr_root/apps/core/wcm/components/teaser/v2/teaser/teaser.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
data-cmp-data-layer="${teaser.data.json}">
2727
<a class="cmp-teaser__link"
2828
data-sly-attribute="${teaser.link.htmlAttributes}"
29-
data-sly-unwrap="${!teaser.link.valid || !teaser.actions.empty}"
29+
data-sly-unwrap="${!teaser.link.valid || !teaser.actions.empty || !(teaser.pretitle || teaser.title || teaser.description)}"
3030
data-cmp-clickable="${teaser.data ? true : false}">
3131
<div class="cmp-teaser__content">
3232
<sly data-sly-call="${pretitleTemplate.pretitle @ teaser=teaser}"></sly>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2025 Adobe
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16+
package com.adobe.cq.wcm.core.components.it.http;
17+
18+
import org.apache.sling.testing.clients.ClientException;
19+
import org.jsoup.Jsoup;
20+
import org.jsoup.select.Elements;
21+
import org.junit.BeforeClass;
22+
import org.junit.ClassRule;
23+
import org.junit.Rule;
24+
import org.junit.Test;
25+
import org.junit.rules.ErrorCollector;
26+
27+
import com.adobe.cq.testing.client.CQClient;
28+
import com.adobe.cq.testing.junit.rules.CQAuthorPublishClassRule;
29+
import com.adobe.cq.testing.junit.rules.CQRule;
30+
31+
import static org.junit.Assert.assertEquals;
32+
import static org.junit.Assert.assertNotNull;
33+
34+
public class TeaserIT {
35+
@ClassRule
36+
public static final CQAuthorPublishClassRule cqBaseClassRule = new CQAuthorPublishClassRule();
37+
38+
@Rule
39+
public CQRule cqBaseRule = new CQRule(cqBaseClassRule.authorRule, cqBaseClassRule.publishRule);
40+
41+
@Rule
42+
public ErrorCollector collector = new ErrorCollector();
43+
44+
static CQClient adminPublish;
45+
46+
@BeforeClass
47+
public static void beforeClass() {
48+
adminPublish = cqBaseClassRule.publishRule.getAdminClient(CQClient.class);
49+
}
50+
51+
@Test
52+
public void testNoNestedLinkElements() throws ClientException {
53+
String content = adminPublish.doGet("/content/core-components/teaser/teaser-links.html", 200).getContent();
54+
Elements html = Jsoup.parse(content).select("html");
55+
assertNotNull(html);
56+
// Expect no nesting of <a> tags
57+
assertEquals("Expected no nested links", 0, html.select("a a").size());
58+
// Expect only teaser with not CTAs and not content to have image link
59+
assertEquals("Mismatched image links", 1, html.select("a > img").size());
60+
// Expect only teaser with no CTAs and content to have global link
61+
assertEquals("Mismatched teaser content links", 1, html.select("a .cmp-teaser__content").size());
62+
// Expect teasers with CTAs to have CTA links
63+
assertEquals("Mismatched teaser content links", 2, html.select("a.cmp-teaser__action-link").size());
64+
}
65+
}

0 commit comments

Comments
 (0)