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

SITES-4621 Keep access to unused in between content #2261

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -15,43 +15,34 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.wcm.core.components.internal.models.v1.contentfragment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
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.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ModelFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.adobe.cq.dam.cfm.content.FragmentRenderService;
import com.adobe.cq.dam.cfm.converter.ContentTypeConverter;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ContainerExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.internal.ContentFragmentUtils;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
import com.adobe.cq.wcm.core.components.internal.models.v1.datalayer.ContentFragmentDataImpl;
import com.adobe.cq.wcm.core.components.models.contentfragment.ContentFragment;
import com.adobe.cq.wcm.core.components.models.contentfragment.DAMContentFragment;
import com.adobe.cq.wcm.core.components.models.datalayer.ComponentData;
import com.adobe.cq.wcm.core.components.models.datalayer.ContentFragmentData;
import com.adobe.cq.wcm.core.components.models.datalayer.builder.DataLayerBuilder;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please revert back the order of imports?

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.*;
import org.apache.sling.models.factory.ModelFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.*;
import java.util.stream.Collectors;

@Model(
adaptables = SlingHttpServletRequest.class,
Expand All @@ -71,6 +62,7 @@ public class ContentFragmentImpl extends AbstractComponentImpl implements Conten
* The resource type of the component associated with this Sling model.
*/
public static final String RESOURCE_TYPE = "core/wcm/components/contentfragment/v1/contentfragment";
public static final String PAR = "par";

@Self(injectionStrategy = InjectionStrategy.REQUIRED)
private SlingHttpServletRequest slingHttpServletRequest;
Expand Down Expand Up @@ -108,6 +100,9 @@ public class ContentFragmentImpl extends AbstractComponentImpl implements Conten

private DAMContentFragment damContentFragment = new EmptyContentFragment();

private String[] paragraphs;
private Integer[] remainingInBetweenContent;

@PostConstruct
private void initModel() {
if (StringUtils.isNotEmpty(fragmentPath)) {
Expand All @@ -116,6 +111,8 @@ private void initModel() {
damContentFragment = new DAMContentFragmentImpl(fragmentResource, contentTypeConverter, variationName, elementNames);
}
}
paragraphs = computeParagraphs();
remainingInBetweenContent = computeRemainingInBetweenContent();
}

@Nullable
Expand Down Expand Up @@ -199,18 +196,28 @@ public String[] getExportedItemsOrder() {
@Nullable
@Override
public String[] getParagraphs() {
return paragraphs != null ? paragraphs.clone() : null;
}

@Override
public @Nullable Integer[] getRemainingInBetweenContent() {
return remainingInBetweenContent != null ? remainingInBetweenContent.clone() : null;
}


private @Nullable String[] computeParagraphs() {
if (!"singleText".equals(displayMode)) {
return null;
}

if (damContentFragment.getElements() == null || damContentFragment.getElements().isEmpty()) {
if (damContentFragment == null || damContentFragment.getElements() == null || damContentFragment.getElements().isEmpty()) {
return null;
}

DAMContentElement damContentElement = damContentFragment.getElements().get(0);

// restrict this method to text elements
if (!damContentElement.isMultiLine()) {
if (damContentElement != null && !damContentElement.isMultiLine()) {
return null;
}

Expand All @@ -224,6 +231,24 @@ public String[] getParagraphs() {
return content.split("(?=(<p>|<h1>|<h2>|<h3>|<h4>|<h5>|<h6>))");
}

public @Nullable Integer[] computeRemainingInBetweenContent() {
ArrayList<Integer> list = new ArrayList<>();
if (paragraphs != null) {
int lastVisibleParIndex = paragraphs.length;
Iterator<Resource> childIterator = resource.listChildren();
while (childIterator.hasNext()) {
String label = childIterator.next().getName();
if (label.startsWith(PAR)) {
int parIndex = Integer.parseInt(label.substring(3));
if (parIndex >= lastVisibleParIndex) {
list.add(parIndex);
}
}
}
}
return list.stream().sorted().collect(Collectors.toList()).toArray(new Integer[0]);
}

@Override
@NotNull
protected ComponentData getComponentData() {
Expand Down
Expand Up @@ -118,4 +118,15 @@ default String getExportedType() {
default String[] getParagraphs() {
return null;
}

/**
* Returns the remaining unused par# for in-between-content.
*
* @return an array containing par# labels
* @since com.adobe.cq.wcm.core.components.models.contentfragment 1.6.0
*/
@Nullable
default Integer[] getRemainingInBetweenContent() {
return null;
}
}
Expand Up @@ -13,7 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@Version("1.5.1")
@Version("1.6.0")
package com.adobe.cq.wcm.core.components.models.contentfragment;

import org.osgi.annotation.versioning.Version;
Expand Up @@ -59,6 +59,7 @@ public abstract class AbstractContentFragmentTest<T> {
static final String CF_STRUCTURED_NESTED_MODEL = "structured-nested-model";
static final String CF_STRUCTURED_SINGLE_ELEMENT = "structured-single-element";
static final String CF_STRUCTURED_SINGLE_ELEMENT_MAIN = "structured-single-element-main";
static final String CF_STRUCTURED_SINGLE_ELEMENT_MAIN_REMAINING_IN_BETWEEN_CONTENT = "structured-single-element-main-remaining-in-between";
static final String CF_STRUCTURED_MULTIPLE_ELEMENTS = "structured-multiple-elements";

/* contents of the text-only and structured content fragments referenced by the above components */
Expand Down
Expand Up @@ -187,6 +187,14 @@ void structuredSingleElementMain() {
Utils.testJSONExport(fragment, Utils.getTestExporterJSONPath(TEST_BASE, CF_STRUCTURED_SINGLE_ELEMENT_MAIN));
}

@Test
void structuredSingleElementMainRemainingInBetweenContent() {
when(fragmentRenderService.render(any(Resource.class))).thenReturn(MAIN_CONTENT);
ContentFragment fragment = getModelInstanceUnderTest(CF_STRUCTURED_SINGLE_ELEMENT_MAIN_REMAINING_IN_BETWEEN_CONTENT);
assertContentFragment(fragment, TITLE, DESCRIPTION, STRUCTURED_TYPE, STRUCTURED_NAME, ASSOCIATED_CONTENT, MAIN);
Utils.testJSONExport(fragment, Utils.getTestExporterJSONPath(TEST_BASE, CF_STRUCTURED_SINGLE_ELEMENT_MAIN_REMAINING_IN_BETWEEN_CONTENT));
}

@Test
void getExportedType() {
ContentFragment fragment = getModelInstanceUnderTest(CF_TEXT_ONLY);
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-b6b8c19a20",
"remainingInBetweenContent":[],
"title": "Test Content Fragment",
"description": "This is a test content fragment.",
"model": "global/models/test",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-84f882bb92",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"title": "Test Content Fragment",
"model": "global/nested/models/test",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-a68b9c84f9",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"paragraphs": [
"<p>Main content</p>"
Expand Down
@@ -0,0 +1,24 @@
{
"id": "contentfragment-d3375413df",
"description": "This is a test content fragment.",
"remainingInBetweenContent":[3, 6, 8],
"paragraphs": [
"<p>Main content</p>"
],
"title": "Test Content Fragment",
"model": "global/models/test",
":items": {},
":itemsOrder": [],
"elementsOrder": [
"main"
],
":type": "core/wcm/components/contentfragment/v1/contentfragment",
"elements": {
"main": {
"value": "<p>Main content</p>",
"title": "Main",
"multiValue": false,
":type": "text/html"
}
}
}
@@ -1,5 +1,6 @@
{
"id": "contentfragment-693827d63c",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"paragraphs": [
"<p>Main content</p>"
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-0ddb9b4c75",
"remainingInBetweenContent":[],
"title": "Test Content Fragment",
"description": "This is a test content fragment.",
"model": "global/models/test",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-a8af0bfdae",
"remainingInBetweenContent":[],
"title": "Test Content Fragment",
"description": "This is a test content fragment.",
"model": "global/models/test",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-a9d49ab72f",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"title": "Test Content Fragment",
"model": "global/models/test",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-2204dfcbac",
"remainingInBetweenContent":[],
"title": "Test Content Fragment",
"description": "This is a test content fragment.",
"model": "/content/dam/contentfragments/text-only/jcr:content/model",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-d88c46402d",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"title": "Test Content Fragment",
"model": "/content/dam/contentfragments/text-only/jcr:content/model",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-aca8901d9b",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"title": "Test Content Fragment",
"model": "/content/dam/contentfragments/text-only/jcr:content/model",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-2b056e758c",
"remainingInBetweenContent":[],
"description": "This is a test content fragment.",
"title": "Test Content Fragment",
"model": "/content/dam/contentfragments/text-only/jcr:content/model",
Expand Down
@@ -1,5 +1,6 @@
{
"id": "contentfragment-bb4058160c",
"remainingInBetweenContent":[],
"title": "Test Content Fragment",
"description": "This is a test content fragment.",
"model": "/content/dam/contentfragments/text-only/jcr:content/model",
Expand Down
16 changes: 16 additions & 0 deletions bundles/core/src/test/resources/contentfragment/test-content.json
Expand Up @@ -110,6 +110,22 @@
"elementNames" : ["main"],
"displayMode" : "singleText"
},
"structured-single-element-main-remaining-in-between" : {
"jcr:primaryType" : "nt:unstructured",
"sling:resourceType": "core/wcm/components/contentfragment/v1/contentfragment",
"fragmentPath" : "/content/dam/contentfragments/structured",
"elementNames" : ["main"],
"displayMode" : "singleText",
"par6": {
"jcr:primaryType" : "nt:unstructured"
},
"par8": {
"jcr:primaryType" : "nt:unstructured"
},
"par3": {
"jcr:primaryType" : "nt:unstructured"
}
},
"structured-multiple-elements" : {
"jcr:primaryType" : "nt:unstructured",
"sling:resourceType": "core/wcm/components/contentfragment/v1/contentfragment",
Expand Down
2 changes: 1 addition & 1 deletion bundles/core/src/test/resources/findbugs-exclude.xml
Expand Up @@ -29,7 +29,7 @@
</Match>
<Match>
<Class name="com.adobe.cq.wcm.core.components.internal.models.v1.contentfragment.ContentFragmentImpl" />
<Method name="getParagraphs" />
<Method name="computeParagraphs" />
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" />
</Match>
</FindBugsFilter>
Expand Up @@ -43,6 +43,9 @@ <h3 class="cmp-contentfragment__title">${fragment.title}</h3>
${item @ context="html"}
<div data-sly-resource="${'par{0}' @ format=itemList.count, resourceType=fragment.gridResourceType}"></div>
</div>
<div data-sly-list="${fragment.remainingInBetweenContent}">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this addition should be behind an option so that we don't end up appending these where they would not be desired. IMO, it's best to have a content policy option to enable showing them.

<div data-sly-resource="${'par{0}' @ format=item, resourceType=fragment.gridResourceType}"></div>
</div>
</div>
</template>

Expand Down