From d0a654b7a5fcdb15a5f2e1862c7434a511133990 Mon Sep 17 00:00:00 2001 From: Kyle Giovannetti Date: Tue, 19 Mar 2024 14:05:43 -0300 Subject: [PATCH] [List] Allow current page to be excluded Adds option to the V4 List component to exclude the current page from the results. ---- fixes #2699 --- .../internal/models/v1/ListImpl.java | 28 +++++++++++++++++++ .../internal/models/v1/ListImplTest.java | 12 ++++++++ .../src/test/resources/list/test-content.json | 14 ++++++++++ .../test/resources/list/v2/test-content.json | 14 ++++++++++ .../test/resources/list/v3/test-content.json | 14 ++++++++++ .../test/resources/list/v4/test-content.json | 14 ++++++++++ .../wcm/components/list/v4/list/README.md | 3 +- .../list/v4/list/_cq_dialog/.content.xml | 9 ++++++ 8 files changed, 107 insertions(+), 1 deletion(-) diff --git a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImpl.java b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImpl.java index b659420119..d4b9ebc5bb 100644 --- a/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImpl.java +++ b/bundles/core/src/main/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImpl.java @@ -32,6 +32,7 @@ import javax.jcr.RepositoryException; import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl; +import com.day.cq.search.PredicateGroup; import com.day.cq.search.result.SearchResult; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ObjectUtils; @@ -91,6 +92,11 @@ public class ListImpl extends AbstractComponentImpl implements List { */ private static final String PN_CHILD_DEPTH = "childDepth"; + /** + * Property name for flag that indicates if current page should be excluded. + */ + private static final String PN_EXCLUDE_CURRENT_PAGE = "excludeCurrentPage"; + /** * Search query property name. */ @@ -175,6 +181,11 @@ public class ListImpl extends AbstractComponentImpl implements List { */ protected boolean linkItems; + /** + * Flag indicating if the current request page should be excluded. + */ + protected boolean excludeCurrentPage; + /** * The list items. */ @@ -191,6 +202,7 @@ protected void initModel() { PN_SHOW_MODIFICATION_DATE, currentStyle.get(PN_SHOW_MODIFICATION_DATE, SHOW_MODIFICATION_DATE_DEFAULT)); linkItems = properties.get(PN_LINK_ITEMS, currentStyle.get(PN_LINK_ITEMS, LINK_ITEMS_DEFAULT)); dateFormatString = properties.get(PN_DATE_FORMAT, currentStyle.get(PN_DATE_FORMAT, DATE_FORMAT_DEFAULT)); + excludeCurrentPage = properties.get(PN_EXCLUDE_CURRENT_PAGE, Boolean.FALSE); } @Override @@ -279,6 +291,11 @@ protected java.util.List getPages() { break; } + // filter out current page + if (this.excludeCurrentPage) { + itemStream = itemStream.filter(page -> !page.getPath().equals(this.currentPage.getPath())); + } + // order the results OrderBy orderBy = OrderBy.fromString(properties.get(PN_ORDER_BY, StringUtils.EMPTY)); if (orderBy != null) { @@ -376,6 +393,17 @@ private Stream getSearchListItems() { search.setQuery(query); search.setSearchIn(searchRoot.get().getPath()); search.addPredicate(new Predicate("type", "type").set("type", NameConstants.NT_PAGE)); + + if (this.excludeCurrentPage) { + PredicateGroup pg = new PredicateGroup(); + pg.setNegated(true); + pg.add(new Predicate("path") + .set("path", this.currentPage.getPath()) + .set("exact", Boolean.TRUE.toString()) + .set("self", Boolean.TRUE.toString())); + search.addPredicate(pg); + } + int limit = properties.get(PN_SEARCH_LIMIT, SEARCH_LIMIT_DEFAULT); search.setHitsPerPage(limit); return safeGetSearchResult(search) diff --git a/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImplTest.java b/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImplTest.java index ad0cd7d544..45a7ae46b1 100644 --- a/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImplTest.java +++ b/bundles/core/src/test/java/com/adobe/cq/wcm/core/components/internal/models/v1/ListImplTest.java @@ -69,6 +69,9 @@ public class ListImplTest { protected static final String LIST_21 = TEST_PAGE_CONTENT_ROOT + "/staticOrderByTitleListTypeWithBlankTitle"; + protected static final String LIST_22 = TEST_PAGE_CONTENT_ROOT + "/staticListTypeExcludeCurrentPage"; + + protected final AemContext context = CoreComponentTestContext.newAemContext(); protected String testBase; @@ -103,6 +106,15 @@ protected void testStaticListType() { Utils.testJSONExport(list, Utils.getTestExporterJSONPath(testBase, LIST_2)); } + @Test + protected void testStaticListExcludeCurrentPage() { + this.context.currentPage("/content/list/pages/page_2"); + List list = getListUnderTest(LIST_22); + checkListConsistencyByPaths(list, new String[]{ + "/content/list/pages/page_1" + }); + } + @Test protected void testChildrenListType() { List list = getListUnderTest(LIST_3); diff --git a/bundles/core/src/test/resources/list/test-content.json b/bundles/core/src/test/resources/list/test-content.json index 030b12277f..a56cf912ac 100644 --- a/bundles/core/src/test/resources/list/test-content.json +++ b/bundles/core/src/test/resources/list/test-content.json @@ -25,6 +25,20 @@ "/content/list/pages/page_2" ] }, + "staticListTypeExcludeCurrentPage": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "core/wcm/components/list", + "listFrom": "static", + "showThumbnail": "true", + "linkItems": "true", + "showDescription": "true", + "showModificationDate": "true", + "excludeCurrentPage": "true", + "pages": [ + "/content/list/pages/page_1", + "/content/list/pages/page_2" + ] + }, "staticMaxItemsListType": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "core/wcm/components/list", diff --git a/bundles/core/src/test/resources/list/v2/test-content.json b/bundles/core/src/test/resources/list/v2/test-content.json index 8d767228ad..b872a37637 100644 --- a/bundles/core/src/test/resources/list/v2/test-content.json +++ b/bundles/core/src/test/resources/list/v2/test-content.json @@ -25,6 +25,20 @@ "/content/list/pages/page_2" ] }, + "staticListTypeExcludeCurrentPage": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "core/wcm/components/list/v2/list", + "listFrom": "static", + "showThumbnail": "true", + "linkItems": "true", + "showDescription": "true", + "showModificationDate": "true", + "excludeCurrentPage": "true", + "pages": [ + "/content/list/pages/page_1", + "/content/list/pages/page_2" + ] + }, "staticWithVanityPaths": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "core/wcm/components/list/v2/list", diff --git a/bundles/core/src/test/resources/list/v3/test-content.json b/bundles/core/src/test/resources/list/v3/test-content.json index 1d2f0f97da..f427f9f865 100644 --- a/bundles/core/src/test/resources/list/v3/test-content.json +++ b/bundles/core/src/test/resources/list/v3/test-content.json @@ -25,6 +25,20 @@ "/content/list/pages/page_2" ] }, + "staticListTypeExcludeCurrentPage": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "core/wcm/components/list/v3/list", + "listFrom": "static", + "showThumbnail": "true", + "linkItems": "true", + "showDescription": "true", + "showModificationDate": "true", + "excludeCurrentPage": "true", + "pages": [ + "/content/list/pages/page_1", + "/content/list/pages/page_2" + ] + }, "staticMaxItemsListType": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "core/wcm/components/list/v3/list", diff --git a/bundles/core/src/test/resources/list/v4/test-content.json b/bundles/core/src/test/resources/list/v4/test-content.json index dcd0a6b4f1..32f51682b9 100644 --- a/bundles/core/src/test/resources/list/v4/test-content.json +++ b/bundles/core/src/test/resources/list/v4/test-content.json @@ -25,6 +25,20 @@ "/content/list/pages/page_2" ] }, + "staticListTypeExcludeCurrentPage": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "core/wcm/components/list/v4/list", + "listFrom": "static", + "showThumbnail": "true", + "linkItems": "true", + "showDescription": "true", + "showModificationDate": "true", + "excludeCurrentPage": "true", + "pages": [ + "/content/list/pages/page_1", + "/content/list/pages/page_2" + ] + }, "staticMaxItemsListType": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "core/wcm/components/list/v4/list", diff --git a/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/README.md b/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/README.md index 6769e41201..0b3274caab 100644 --- a/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/README.md +++ b/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/README.md @@ -68,7 +68,8 @@ last modification date of the item; possible values: `title`, `modified` 14. `./showDescription` - if set to `true` each item's description will be rendered 15. `./showModificationDate` - if set to `true` each item's last modification date will be rendered 16. `./displayItemAsTeaser` - if set to `true` the rendering of each list item is delegated to the configured teaser component -17. `./id` - defines the component HTML ID attribute. +17. `./excludeCurrentPage` - if set to `true` the current page is excluded from results. +18. `./id` - defines the component HTML ID attribute. ### Deprecated Edit Dialog Properties 1. `./pages` - defines the pages to be rendered, when the `./listFrom` property is set to `static` up to component version `v3`. diff --git a/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/_cq_dialog/.content.xml b/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/_cq_dialog/.content.xml index a84f75b327..d0a4aedaba 100644 --- a/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/_cq_dialog/.content.xml +++ b/content/src/content/jcr_root/apps/core/wcm/components/list/v4/list/_cq_dialog/.content.xml @@ -282,6 +282,15 @@ +