Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .chachalog/bnO8G4QV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
# Allowed version bumps: patch, minor, major
javascript-modules: minor
---

Add boolean param `areaAsSubNode` for <Area> similar to JSP templates (#660)
Comment thread
gflores-jahia marked this conversation as resolved.
Outdated
10 changes: 10 additions & 0 deletions jahia-test-module/src/react/server/views/testAreas/TestAreas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ jahiaComponent(
}}
/>
</div>

<h2>Area with areaAsSubNode=true</h2>
<div data-testid="areaAsSubNodeTrue">
<Area name="subNodeArea" areaAsSubNode={true} />
</div>

<h2>Area with areaAsSubNode=false</h2>
<div data-testid="areaAsSubNodeFalse">
<Area name="noSubNodeArea" areaAsSubNode={false} />
</div>
</>
),
);
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class RenderHelper {
"allowedNodeTypes", "numberOfItems", "nodeType", "editable", "areaType", "limitedAbsoluteAreaEdit",
"parameters");
private static final Set<String> AREA_ALLOWED_ATTRIBUTES = Set.of("name", "view", "allowedNodeTypes",
"numberOfItems", "nodeType", "editable", "parameters");
"numberOfItems", "nodeType", "editable", "areaAsSubNode", "parameters");

private JCRSessionFactory jcrSessionFactory;
private JCRTemplate jcrTemplate;
Expand Down
11 changes: 11 additions & 0 deletions javascript-modules-library/src/components/Area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function Area({
numberOfItems,
readOnly = false,
nodeType = "jnt:contentList",
areaAsSubNode = false,
parameters,
Comment thread
gflores-jahia marked this conversation as resolved.
}: Readonly<{
/** The name of the area. */
Expand All @@ -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<string, unknown>;
}>): JSX.Element {
Expand All @@ -52,6 +62,7 @@ export function Area({
numberOfItems,
nodeType,
editable: !readOnly,
areaAsSubNode,
parameters,
},
renderContext,
Expand Down
83 changes: 83 additions & 0 deletions tests/cypress/e2e/ui/areaAsSubNodeTest.cy.ts
Original file line number Diff line number Diff line change
@@ -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`
Comment thread
gflores-jahia marked this conversation as resolved.
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);
})
});

});
Loading