From 7867c0bec7fa9de77f297089cc3cd46aa431d44f Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Wed, 15 Apr 2026 17:36:02 -0400 Subject: [PATCH 1/4] Add changelog --- .chachalog/bnO8G4QV.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .chachalog/bnO8G4QV.md diff --git a/.chachalog/bnO8G4QV.md b/.chachalog/bnO8G4QV.md new file mode 100644 index 00000000..8965f934 --- /dev/null +++ b/.chachalog/bnO8G4QV.md @@ -0,0 +1,6 @@ +--- +# Allowed version bumps: patch, minor, major +javascript-modules: minor +--- + +Add boolean param `areaAsSubNode` for similar to JSP templates (#660) \ No newline at end of file From de86e7b9c48def867b3bb24bc20a96622ac00b4f Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Thu, 16 Apr 2026 15:57:27 -0400 Subject: [PATCH 2/4] feat: Expose areaAsSubNode param for Area --- .../modules/engine/js/server/RenderHelper.java | 2 +- javascript-modules-library/src/components/Area.tsx | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript-modules-engine-java/src/main/java/org/jahia/modules/javascript/modules/engine/js/server/RenderHelper.java b/javascript-modules-engine-java/src/main/java/org/jahia/modules/javascript/modules/engine/js/server/RenderHelper.java index 08da5727..1f0de639 100644 --- a/javascript-modules-engine-java/src/main/java/org/jahia/modules/javascript/modules/engine/js/server/RenderHelper.java +++ b/javascript-modules-engine-java/src/main/java/org/jahia/modules/javascript/modules/engine/js/server/RenderHelper.java @@ -63,7 +63,7 @@ public class RenderHelper { "allowedNodeTypes", "numberOfItems", "nodeType", "editable", "areaType", "limitedAbsoluteAreaEdit", "parameters"); private static final Set AREA_ALLOWED_ATTRIBUTES = Set.of("name", "view", "allowedNodeTypes", - "numberOfItems", "nodeType", "editable", "parameters"); + "numberOfItems", "nodeType", "editable", "areaAsSubNode", "parameters"); private JCRSessionFactory jcrSessionFactory; private JCRTemplate jcrTemplate; diff --git a/javascript-modules-library/src/components/Area.tsx b/javascript-modules-library/src/components/Area.tsx index 4ae0db3e..e11f631b 100644 --- a/javascript-modules-library/src/components/Area.tsx +++ b/javascript-modules-library/src/components/Area.tsx @@ -13,6 +13,7 @@ export function Area({ numberOfItems, readOnly = false, nodeType = "jnt:contentList", + areaAsSubNode = false, parameters, }: Readonly<{ /** The name of the area. */ @@ -38,6 +39,15 @@ export function Area({ * @default jnt:contentList */ nodeType?: string; + + /** + * When true, allows the area to be stored as a subnode of the current component + * rather than under the main resource. Useful for repeatable components where + * each instance needs its own content area. + * + * @default false + */ + areaAsSubNode?: boolean; /** Map of custom parameters that can be passed to the backend engine for advanced logic. */ parameters?: Record; }>): JSX.Element { @@ -52,6 +62,7 @@ export function Area({ numberOfItems, nodeType, editable: !readOnly, + areaAsSubNode, parameters, }, renderContext, From bca19bfce9e7024474d783b2667ca5dc7522c724 Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Thu, 16 Apr 2026 18:50:30 -0400 Subject: [PATCH 3/4] Add cypress tests --- .../server/views/testAreas/TestAreas.tsx | 10 +++ tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts | 83 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts diff --git a/jahia-test-module/src/react/server/views/testAreas/TestAreas.tsx b/jahia-test-module/src/react/server/views/testAreas/TestAreas.tsx index 926b4e8d..3b32d6eb 100644 --- a/jahia-test-module/src/react/server/views/testAreas/TestAreas.tsx +++ b/jahia-test-module/src/react/server/views/testAreas/TestAreas.tsx @@ -57,6 +57,16 @@ jahiaComponent( }} /> + +

Area with areaAsSubNode=true

+
+ +
+ +

Area with areaAsSubNode=false

+
+ +
), ); diff --git a/tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts b/tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts new file mode 100644 index 00000000..1c6ddbe4 --- /dev/null +++ b/tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts @@ -0,0 +1,83 @@ +import { addNode, getNodeByPath } from "@jahia/cypress"; +import { addSimplePage } from "../../utils/helpers"; +import { GENERIC_SITE_KEY } from '../../support/constants'; + +/** + * This test verifies that the areaAsSubNode parameter works correctly, + * ensuring that areas are stored as subnodes of the component rather than + * at the page level + */ +describe("AreaAsSubNode test", () => { + const pageName = "testAreaAsSubNode"; + const pagePath = `/sites/${GENERIC_SITE_KEY}/home/${pageName}`; + const componentPath = `${pagePath}/pagecontent`; + + before("Create test page and multiple components", () => { + addSimplePage(`/sites/${GENERIC_SITE_KEY}/home`, pageName, pageName, "en", "simple", [ + { + name: "pagecontent", + primaryNodeType: "jnt:contentList", + }, + ]).then(() => { + ['testArea', 'testArea2'].forEach((componentName) => { + addNode({ + parentPathOrId: componentPath, + name: componentName, + primaryNodeType: "javascriptExample:testAreas" + }); + }) + }); + }); + + beforeEach('Login and visit test page', () => { + cy.login(); + cy.visit(`/jahia/jcontent/${GENERIC_SITE_KEY}/en/pages/home/${pageName}`); + }); + + afterEach('Logout', () => cy.logout()); + + it(`${pageName}: Area with areaAsSubNode=true should render`, () => { + cy.iframe("#page-builder-frame-1").within(() => { + cy.get('div[data-testid="areaAsSubNodeTrue"]') + .find('div[type="area"]') + .should("be.visible"); + }); + }); + + it(`${pageName}: Area with areaAsSubNode=false should render`, () => { + cy.iframe("#page-builder-frame-1").within(() => { + cy.get('div[data-testid="areaAsSubNodeFalse"]') + .find('div[type="area"]') + .should("be.visible"); + }); + }); + + it(`${pageName}: Area without areaAsSubNode param should create area as subnode of the page`, () => { + const areaName = 'basicArea'; + getNodeByPath(`${pagePath}/${areaName}`).then((area) => { + const msg = `${areaName} should be created as a subnode of the page` + expect(area?.data?.jcr?.nodeByPath?.name, msg).to.equal(areaName); + }) + }); + + it(`${pageName}: areaAsSubNode=false should create area as subnode of the page`, () => { + const areaName = 'noSubNodeArea'; + getNodeByPath(`${pagePath}/${areaName}`).then((area) => { + const msg = `${areaName} should be created as a subnode of the page` + expect(area?.data?.jcr?.nodeByPath?.name, msg).to.equal(areaName); + }) + }); + + it(`${pageName}: areaAsSubNode=true should create distinct areas as subnode of component`, () => { + const areaName = 'subNodeArea'; + getNodeByPath(`${componentPath}/testArea/${areaName}`).then((area) => { + const msg = `${areaName} should be created as a subnode of the test area component` + expect(area?.data?.jcr?.nodeByPath?.name, msg).to.equal(areaName); + }) + getNodeByPath(`${componentPath}/testArea2/${areaName}`).then((area) => { + const msg = `${areaName} should be created as a subnode of the test area component` + expect(area?.data?.jcr?.nodeByPath?.name, msg).to.equal(areaName); + }) + }); + +}); From 6803477f6ef9ef13a183f9cc74b08ff1471dfca6 Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Tue, 21 Apr 2026 16:38:23 -0400 Subject: [PATCH 4/4] ci: Modify changelog --- .chachalog/bnO8G4QV.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chachalog/bnO8G4QV.md b/.chachalog/bnO8G4QV.md index 8965f934..fcc31c07 100644 --- a/.chachalog/bnO8G4QV.md +++ b/.chachalog/bnO8G4QV.md @@ -3,4 +3,4 @@ javascript-modules: minor --- -Add boolean param `areaAsSubNode` for similar to JSP templates (#660) \ No newline at end of file + Added an `areaAsSubNode` option to the Area component similar to jsp tag so repeated components can store area content separately (#660) \ No newline at end of file