Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {
AddContentButtons,
getChildNodes,
jahiaComponent,
RenderChild,
RenderChildren,
} from "@jahia/javascript-modules-library";
import type { Node } from "javax.jcr";

Expand Down Expand Up @@ -88,7 +90,33 @@ jahiaComponent(
/>
<PrintChildren title="Offset children" testid="offset" children={offsetChildren} />
<AddContentButtons />

<h3>RenderChildren</h3>
<div data-testid="renderAllChildren">
<RenderChildren view="path" />
</div>
<div data-testid="renderFilteredChildren">
<RenderChildren view="path" filter={(node) => node.getName().includes("filtered")} />
</div>
<div data-testid="renderPaginatedChildren">
<RenderChildren view="path" pagination={{ start: 1, count: 2 }} />
</div>

<h3>RenderChild</h3>
<div data-testid="renderChild">
<RenderChild name="child1" view="path" />
</div>
</>
);
},
);

jahiaComponent(
{
nodeType: "javascriptExample:testGetChildNodes",
name: "path",
displayName: "test getChildNodes",
componentType: "view",
},
(_, { currentNode }) => <div>{currentNode.getPath()}</div>,
);
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {
AddContentButtons,
HydrateInBrowser,
Render,
getChildNodes,
RenderChildren,
jahiaComponent,
useUrlBuilder,
} from "@jahia/javascript-modules-library";
Expand All @@ -17,7 +15,7 @@ jahiaComponent(
displayName: "Hello World Component",
componentType: "view",
},
({ name }: { name: string }, { renderContext, currentNode }) => {
({ name }: { name: string }, { renderContext }) => {
const { buildStaticUrl } = useUrlBuilder();
return (
<>
Expand All @@ -44,13 +42,7 @@ jahiaComponent(
</header>
<p>{t("7l9zetMbU4cKpL4NxSOtL")}</p>
<div className={classes.grid}>
{getChildNodes(currentNode, -1, 0, (node) => node.isNodeType("jnt:content")).map(
(node) => (
// @ts-expect-error Fix the types
<Render key={node.getIdentifier()} node={node} />
),
)}
<AddContentButtons />
<RenderChildren />
</div>

<p className={classes.attribution}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,42 @@ describe('getChildNodes function test', () => {

cy.logout()
})

it('Verify RenderChildren', function () {
cy.login()

cy.visit('/cms/render/default/en/sites/javascriptTestSite/home/testGetChildNodes.html')

for (const child of ['child1', 'child2', 'filtered', 'filtered2', 'filtered3']) {
cy.get('div[data-testid="renderAllChildren"]').contains(
`/sites/javascriptTestSite/home/testGetChildNodes/pagecontent/getChildNodesTest/${child}`,
)
}

for (const child of ['filtered', 'filtered2', 'filtered3']) {
cy.get('div[data-testid="renderFilteredChildren"]').contains(
`/sites/javascriptTestSite/home/testGetChildNodes/pagecontent/getChildNodesTest/${child}`,
)
}

for (const child of ['child2', 'filtered']) {
cy.get('div[data-testid="renderPaginatedChildren"]').contains(
`/sites/javascriptTestSite/home/testGetChildNodes/pagecontent/getChildNodesTest/${child}`,
)
}

cy.logout()
})

it('Verify RenderChild', function () {
cy.login()

cy.visit('/cms/render/default/en/sites/javascriptTestSite/home/testGetChildNodes.html')

cy.get('div[data-testid="renderChild"]').contains(
`/sites/javascriptTestSite/home/testGetChildNodes/pagecontent/getChildNodesTest/child1`,
)

cy.logout()
})
})
1 change: 1 addition & 0 deletions javascript-modules-engine/tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@jahia/cypress": "^4.2.0",
"@jahia/jahia-reporter": "^1.0.30",
"@jahia/jcontent-cypress": "^3.0.0-tests.8",
"@types/mocha": "^10.0.10",
Comment thread
GauBen marked this conversation as resolved.
"@types/node": "^18.11.18",
"cypress": "^14.0.0",
"cypress-iframe": "^1.0.1",
Expand Down
8 changes: 8 additions & 0 deletions javascript-modules-engine/tests/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ __metadata:
"@jahia/cypress": "npm:^4.2.0"
"@jahia/jahia-reporter": "npm:^1.0.30"
"@jahia/jcontent-cypress": "npm:^3.0.0-tests.8"
"@types/mocha": "npm:^10.0.10"
"@types/node": "npm:^18.11.18"
cypress: "npm:^14.0.0"
cypress-iframe: "npm:^1.0.1"
Expand Down Expand Up @@ -404,6 +405,13 @@ __metadata:
languageName: node
linkType: hard

"@types/mocha@npm:^10.0.10":
version: 10.0.10
resolution: "@types/mocha@npm:10.0.10"
checksum: 10c0/d2b8c48138cde6923493e42b38e839695eb42edd04629abe480a8f34c0e3f50dd82a55832c2e8d2b6e6f9e4deb492d7d733e600fbbdd5a0ceccbcfc6844ff9d5
languageName: node
linkType: hard

"@types/node-fetch@npm:^2.5.7":
version: 2.6.1
resolution: "@types/node-fetch@npm:2.6.1"
Expand Down
16 changes: 16 additions & 0 deletions javascript-modules-library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ This component renders a Jahia component out of a node or a JS object.
<Render content={{ nodeType: "ns:nodeType" }}>
```

### `RenderChild`

This component renders a child node of the current node. It's a thin wrapper around `Render` and `AddContentButtons`.

```tsx
<RenderChild name="child" />
```

### `RenderChildren`

This component renders all children of the current node. It's a thin wrapper around `Render`, `getChildNodes` and `AddContentButtons`.

```tsx
<RenderChildren />
```

## Components

### `AbsoluteArea`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ export function Area({
* @default false
*/
readOnly?: boolean;
/** Allow area to be stored as a subnode */
/**
* Allow area to be stored as a subnode
*
* @deprecated Use child node(s) and `<RenderChild(ren) />` instead
*/
areaAsSubNode?: boolean;
/**
* Content type to be used to create the area
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { JSX } from "react";
import { Render } from "./Render.js";
import { useServerContext } from "../../hooks/useServerContext.js";
import { AddContentButtons } from "../AddContentButtons.js";

/**
* Renders a child of the current node, designated by its name.
*
* If the child node does not exist, it will display the "Add content" buttons.
*/
export function RenderChild({
name,
view,
}: {
/**
* The name of the child node to render.
*
* In the CND file, it's what's after the `+` in the child node definition: `+ name (type)`.
*/
name: string;
/** View to use when rendering the child. */
view?: string | undefined;
}): JSX.Element {
const { currentNode } = useServerContext();
if (currentNode.hasNode(name)) {
Comment thread
GauBen marked this conversation as resolved.
return <Render node={currentNode.getNode(name)} view={view} />;
}
return <AddContentButtons childName={name} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { JSX } from "react";
import { Render } from "./Render.js";
import { useServerContext } from "../../hooks/useServerContext.js";
import { AddContentButtons } from "../AddContentButtons.js";
import { getChildNodes } from "../../utils/jcr/getChildNodes.js";
import type { JCRNodeWrapper } from "org.jahia.services.content";

/** Renders the children of the current node, and "Add content" buttons afterwards. */
export function RenderChildren({
view,
pagination,
filter = "jnt:content",
}: {
/** View to use when rendering the children. */
view?: string | undefined;
/**
* Pagination parameters:
*
* - `{ count: number; start?: number }` to specify the number of children to display and the
* starting index (defaults to 0).
* - `{ count: number; page: number }` to specify the number of children to display and the page
* number.
*
* If not provided, all children will be displayed.
*/
pagination?: { count: number; start?: number } | { count: number; page: number };
/**
* Filter to apply to the children:
*
* - A string to filter by node type.
* - A function to filter by custom logic.
*
* @default "jnt:content"
*/
filter?: string | ((node: JCRNodeWrapper) => boolean);
Comment thread
GauBen marked this conversation as resolved.
}): JSX.Element {
const { currentNode } = useServerContext();
const offset = pagination
? "page" in pagination
? pagination.page * pagination.count
: (pagination.start ?? 0)
: 0;
const limit = pagination ? pagination.count : -1;

return (
<>
{getChildNodes(
currentNode,
limit,
offset,
typeof filter === "string" ? (node) => node.isNodeType(filter) : filter,
).map((node) => (
<Render key={node.getIdentifier()} node={node} view={view} />
))}
<AddContentButtons />
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { Node } from "javax.jcr";
import type { JCRNodeWrapper } from "org.jahia.services.content";

/**
Expand All @@ -16,9 +15,9 @@ export function getChildNodes(
node: JCRNodeWrapper,
limit: number | undefined = undefined,
offset = 0,
filter: ((node: Node) => boolean) | undefined = undefined,
): Node[] {
const result: Node[] = [];
filter: ((node: JCRNodeWrapper) => boolean) | undefined = undefined,
): JCRNodeWrapper[] {
const result: JCRNodeWrapper[] = [];

if (!node || !limit) {
console.warn("Missing one or more mandatory parameters (node, limit) to getChildNodes");
Expand All @@ -32,15 +31,15 @@ export function getChildNodes(

// Skip nodes until reaching the offset
if (skipped < offset) {
if (!filter || filter(child)) {
if (!filter || filter(child as JCRNodeWrapper)) {
skipped++;
}

continue;
}

if (!filter || filter(child)) {
result.push(child);
if (!filter || filter(child as JCRNodeWrapper)) {
result.push(child as JCRNodeWrapper);
if (limit > 0 && result.length >= limit) {
break;
}
Expand Down
2 changes: 2 additions & 0 deletions javascript-modules-library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
export { RenderInBrowser } from "./core/server/components/render/RenderInBrowser.js";
export { HydrateInBrowser } from "./core/server/components/render/HydrateInBrowser.js";
export { Render } from "./core/server/components/render/Render.js";
export { RenderChild } from "./core/server/components/render/RenderChild.js";
export { RenderChildren } from "./core/server/components/render/RenderChildren.js";

// Components
export { AbsoluteArea } from "./core/server/components/AbsoluteArea.js";
Expand Down
Loading