Skip to content
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.
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
---

Added an `areaAsSubNode` option to the Area component similar to <template:area> jsp tag so repeated components can store area content separately (#660)
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