Skip to content

Commit b359561

Browse files
Yahor ChaptsouYahor Chaptsou
authored andcommitted
Merge branch 'main' into SITES-41317
2 parents 1930b45 + 3653bcc commit b359561

74 files changed

Lines changed: 5126 additions & 69 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/contentfragment/ContentFragmentImpl.java

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
3737
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
3838
import org.apache.sling.models.factory.ModelFactory;
39+
import org.apache.sling.settings.SlingSettingsService;
3940
import org.jetbrains.annotations.NotNull;
4041
import org.jetbrains.annotations.Nullable;
4142

@@ -45,13 +46,14 @@
4546
import com.adobe.cq.export.json.ContainerExporter;
4647
import com.adobe.cq.export.json.ExporterConstants;
4748
import com.adobe.cq.wcm.core.components.internal.ContentFragmentUtils;
48-
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
4949
import com.adobe.cq.wcm.core.components.internal.models.v1.datalayer.ContentFragmentDataImpl;
5050
import com.adobe.cq.wcm.core.components.models.contentfragment.ContentFragment;
5151
import com.adobe.cq.wcm.core.components.models.contentfragment.DAMContentFragment;
5252
import com.adobe.cq.wcm.core.components.models.datalayer.ComponentData;
5353
import com.adobe.cq.wcm.core.components.models.datalayer.ContentFragmentData;
5454
import com.adobe.cq.wcm.core.components.models.datalayer.builder.DataLayerBuilder;
55+
import com.adobe.cq.wcm.core.components.services.contentfragment.VcfUrlProvider;
56+
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
5557

5658
@Model(
5759
adaptables = SlingHttpServletRequest.class,
@@ -72,6 +74,10 @@ public class ContentFragmentImpl extends AbstractComponentImpl implements Conten
7274
*/
7375
public static final String RESOURCE_TYPE = "core/wcm/components/contentfragment/v1/contentfragment";
7476

77+
private static final String MASTER_VARIATION = "master";
78+
private static final String PUBLISH_RUN_MODE = "publish";
79+
private static final String VCF_DISPLAY_MODE = "vcf";
80+
7581
@Self(injectionStrategy = InjectionStrategy.REQUIRED)
7682
private SlingHttpServletRequest slingHttpServletRequest;
7783

@@ -84,6 +90,13 @@ public class ContentFragmentImpl extends AbstractComponentImpl implements Conten
8490
@OSGiService
8591
private ModelFactory modelFactory;
8692

93+
@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
94+
private SlingSettingsService slingSettingsService;
95+
96+
@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
97+
@Nullable
98+
private VcfUrlProvider vcfUrlProvider;
99+
87100
@SlingObject
88101
private ResourceResolver resourceResolver;
89102

@@ -106,14 +119,27 @@ public class ContentFragmentImpl extends AbstractComponentImpl implements Conten
106119
@Nullable
107120
private String displayMode;
108121

122+
@ValueMapValue(name = ContentFragment.PN_VCF_TEMPLATE, injectionStrategy = InjectionStrategy.OPTIONAL)
123+
@Nullable
124+
private String vcfTemplate;
125+
109126
private DAMContentFragment damContentFragment = new EmptyContentFragment();
110127

128+
private String fragmentId;
129+
111130
@PostConstruct
112131
private void initModel() {
113132
if (StringUtils.isNotEmpty(fragmentPath)) {
114133
Resource fragmentResource = resourceResolver.getResource(fragmentPath);
115134
if (fragmentResource != null) {
116135
damContentFragment = new DAMContentFragmentImpl(fragmentResource, contentTypeConverter, variationName, elementNames);
136+
fragmentId = fragmentResource.getValueMap().get("jcr:uuid", String.class);
137+
if (fragmentId == null) {
138+
Resource jcrContent = fragmentResource.getChild("jcr:content");
139+
if (jcrContent != null) {
140+
fragmentId = jcrContent.getValueMap().get("jcr:uuid", String.class);
141+
}
142+
}
117143
}
118144
}
119145
}
@@ -224,6 +250,72 @@ public String[] getParagraphs() {
224250
return content.split("(?=(<p>|<h1>|<h2>|<h3>|<h4>|<h5>|<h6>))");
225251
}
226252

253+
@Nullable
254+
@Override
255+
public String getFragmentId() {
256+
return fragmentId;
257+
}
258+
259+
@Nullable
260+
@Override
261+
public String getVcfRenderUrl() {
262+
VcfUrlProvider urls = vcfUrlProvider;
263+
if (!isVcfMode() || StringUtils.isEmpty(fragmentId) || urls == null) {
264+
return null;
265+
}
266+
return isPublishRunMode() ? buildPublishUrl(urls) : buildAuthorPreviewUrl(urls);
267+
}
268+
269+
@Override
270+
public boolean isVcfAuthRequired() {
271+
VcfUrlProvider urls = vcfUrlProvider;
272+
return isVcfMode() && !isPublishRunMode() && urls != null;
273+
}
274+
275+
@Nullable
276+
@Override
277+
public String getVcfTemplatesApiBase() {
278+
VcfUrlProvider urls = vcfUrlProvider;
279+
return urls == null ? null : urls.getVcfTemplatesApiBase();
280+
}
281+
282+
private boolean isVcfMode() {
283+
return VCF_DISPLAY_MODE.equals(displayMode);
284+
}
285+
286+
private String buildPublishUrl(VcfUrlProvider urls) {
287+
String format = urls.getVcfPublishUrlFormat();
288+
if (format == null || StringUtils.isEmpty(vcfTemplate)) {
289+
return null;
290+
}
291+
String variation = hasNonMasterVariation() ? variationName : "main";
292+
return String.format(format, vcfTemplate, fragmentId, variation);
293+
}
294+
295+
private String buildAuthorPreviewUrl(VcfUrlProvider urls) {
296+
String authorFormat = urls.getVcfAuthorUrlFormat();
297+
if (authorFormat == null) {
298+
return null;
299+
}
300+
String url = String.format(authorFormat, fragmentId);
301+
List<String> params = new ArrayList<>();
302+
if (StringUtils.isNotEmpty(vcfTemplate)) {
303+
params.add("templateId=" + vcfTemplate);
304+
}
305+
if (hasNonMasterVariation()) {
306+
params.add("variation=" + variationName);
307+
}
308+
return params.isEmpty() ? url : url + "?" + String.join("&", params);
309+
}
310+
311+
private boolean hasNonMasterVariation() {
312+
return StringUtils.isNotEmpty(variationName) && !MASTER_VARIATION.equals(variationName);
313+
}
314+
315+
private boolean isPublishRunMode() {
316+
return slingSettingsService != null && slingSettingsService.getRunModes().contains(PUBLISH_RUN_MODE);
317+
}
318+
227319
@Override
228320
@NotNull
229321
protected ComponentData getComponentData() {

bundles/core/src/main/java/com/adobe/cq/wcm/core/components/models/contentfragment/ContentFragment.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.adobe.cq.export.json.ComponentExporter;
2525
import com.adobe.cq.export.json.ContainerExporter;
2626
import com.adobe.cq.wcm.core.components.models.Component;
27+
import com.adobe.cq.wcm.core.components.services.contentfragment.VcfUrlProvider;
2728
import com.fasterxml.jackson.annotation.JsonIgnore;
2829

2930
/**
@@ -63,6 +64,13 @@ public interface ContentFragment extends DAMContentFragment, ContainerExporter,
6364
*/
6465
String PN_DISPLAY_MODE = "displayMode";
6566

67+
/**
68+
* Name of the optional resource property that stores the Visual Content Fragment template id.
69+
*
70+
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
71+
*/
72+
String PN_VCF_TEMPLATE = "vcfTemplate";
73+
6674
/**
6775
* Returns resource type that is used for the internal responsive grid.
6876
*
@@ -118,4 +126,54 @@ default String getExportedType() {
118126
default String[] getParagraphs() {
119127
return null;
120128
}
129+
130+
/**
131+
* Returns the JCR UUID of the referenced content fragment, or {@code null}
132+
* if the fragment does not exist or has no UUID.
133+
*
134+
* @return the fragment UUID, or {@code null}
135+
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
136+
*/
137+
@Nullable
138+
@JsonIgnore
139+
default String getFragmentId() {
140+
return null;
141+
}
142+
143+
/**
144+
* Returns the VCF render URL, or {@code null} when display mode is not VCF, the fragment has no id, or
145+
* {@link VcfUrlProvider} is missing or incomplete. Author uses the preview API; publish uses the HTML delivery URL.
146+
*
147+
* @return the VCF render URL, or {@code null}
148+
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
149+
*/
150+
@Nullable
151+
@JsonIgnore
152+
default String getVcfRenderUrl() {
153+
return null;
154+
}
155+
156+
/**
157+
* {@code true} on author in VCF mode when a {@link VcfUrlProvider} is present; {@code false} on publish.
158+
*
159+
* @return {@code true} if VCF auth is required
160+
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
161+
*/
162+
@JsonIgnore
163+
default boolean isVcfAuthRequired() {
164+
return false;
165+
}
166+
167+
/**
168+
* Base URL for the VCF templates API; the dialog appends {@code /{modelId}/templates?limit=...}.
169+
* {@code null} if {@link VcfUrlProvider} is absent or provides no base.
170+
*
171+
* @return templates API base, or {@code null}
172+
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
173+
*/
174+
@Nullable
175+
@JsonIgnore
176+
default String getVcfTemplatesApiBase() {
177+
return null;
178+
}
121179
}

bundles/core/src/main/java/com/adobe/cq/wcm/core/components/models/contentfragment/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
~ See the License for the specific language governing permissions and
1414
~ limitations under the License.
1515
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16-
@Version("1.5.1")
16+
@Version("1.6.0")
1717
package com.adobe.cq.wcm.core.components.models.contentfragment;
1818

1919
import org.osgi.annotation.versioning.Version;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2026 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.services.contentfragment;
17+
18+
import org.jetbrains.annotations.Nullable;
19+
import org.osgi.annotation.versioning.ConsumerType;
20+
21+
/**
22+
* Optional OSGi service: VCF preview URL patterns and templates API base. Implemented by DAM Content Fragment;
23+
* consumed by Core when the Content Fragment component uses {@code displayMode} {@code vcf}.
24+
*
25+
* @since com.adobe.cq.wcm.core.components.services.contentfragment 1.0.0
26+
*/
27+
@ConsumerType
28+
public interface VcfUrlProvider {
29+
30+
/** @return API root (optional for Core), or {@code null} */
31+
@Nullable
32+
String getVcfApiBase();
33+
34+
/** @return author preview format, one {@code %s} for fragment id, or {@code null} */
35+
@Nullable
36+
String getVcfAuthorUrlFormat();
37+
38+
/** @return publish HTML format, three {@code %s}: template id, fragment id, variation, or {@code null} */
39+
@Nullable
40+
String getVcfPublishUrlFormat();
41+
42+
/** @return templates API base (dialog appends {@code /{modelId}/templates?...}), or {@code null} */
43+
@Nullable
44+
String getVcfTemplatesApiBase();
45+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2026 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+
@Version("1.0.0")
17+
package com.adobe.cq.wcm.core.components.services.contentfragment;
18+
19+
import org.osgi.annotation.versioning.Version;

0 commit comments

Comments
 (0)