@sitecore-jss/sitecore-jss-react 22.1.0-canary.9 → 22.2.0-canary.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Date.js +12 -4
- package/dist/cjs/components/DefaultEmptyFieldEditingComponents.js +22 -0
- package/dist/cjs/components/EditFrame.js +2 -2
- package/dist/cjs/components/EditingScripts.js +27 -0
- package/dist/cjs/components/ErrorBoundary.js +22 -7
- package/dist/cjs/components/FieldMetadata.js +33 -0
- package/dist/cjs/components/File.js +2 -1
- package/dist/cjs/components/HiddenRendering.js +7 -4
- package/dist/cjs/components/Image.js +15 -14
- package/dist/cjs/components/Link.js +13 -6
- package/dist/cjs/components/Placeholder.js +9 -6
- package/dist/cjs/components/PlaceholderCommon.js +52 -20
- package/dist/cjs/components/PlaceholderMetadata.js +67 -0
- package/dist/cjs/components/RichText.js +14 -3
- package/dist/cjs/components/Text.js +12 -4
- package/dist/cjs/enhancers/withEmptyFieldEditingComponent.js +56 -0
- package/dist/cjs/enhancers/withFieldMetadata.js +60 -0
- package/dist/cjs/enhancers/withPlaceholder.js +4 -3
- package/dist/cjs/index.js +17 -6
- package/dist/esm/components/Date.js +12 -3
- package/dist/esm/components/DefaultEmptyFieldEditingComponents.js +14 -0
- package/dist/esm/components/EditFrame.js +1 -1
- package/dist/esm/components/EditingScripts.js +20 -0
- package/dist/esm/components/ErrorBoundary.js +22 -7
- package/dist/esm/components/FieldMetadata.js +26 -0
- package/dist/esm/components/File.js +2 -1
- package/dist/esm/components/HiddenRendering.js +6 -3
- package/dist/esm/components/Image.js +15 -13
- package/dist/esm/components/Link.js +13 -6
- package/dist/esm/components/Placeholder.js +7 -4
- package/dist/esm/components/PlaceholderCommon.js +53 -21
- package/dist/esm/components/PlaceholderMetadata.js +60 -0
- package/dist/esm/components/RichText.js +14 -3
- package/dist/esm/components/Text.js +12 -3
- package/dist/esm/enhancers/withEmptyFieldEditingComponent.js +29 -0
- package/dist/esm/enhancers/withFieldMetadata.js +33 -0
- package/dist/esm/enhancers/withPlaceholder.js +4 -3
- package/dist/esm/index.js +6 -2
- package/package.json +5 -5
- package/types/components/Date.d.ts +4 -8
- package/types/components/DefaultEmptyFieldEditingComponents.d.ts +4 -0
- package/types/components/EditFrame.d.ts +1 -1
- package/types/components/EditingScripts.d.ts +5 -0
- package/types/components/ErrorBoundary.d.ts +4 -3
- package/types/components/FieldMetadata.d.ts +23 -0
- package/types/components/HiddenRendering.d.ts +0 -1
- package/types/components/Image.d.ts +4 -8
- package/types/components/Link.d.ts +7 -10
- package/types/components/Placeholder.d.ts +1 -4
- package/types/components/PlaceholderCommon.d.ts +10 -4
- package/types/components/PlaceholderMetadata.d.ts +30 -0
- package/types/components/RichText.d.ts +8 -8
- package/types/components/Text.d.ts +6 -10
- package/types/components/sharedTypes.d.ts +26 -1
- package/types/enhancers/withEmptyFieldEditingComponent.d.ts +28 -0
- package/types/enhancers/withFieldMetadata.d.ts +17 -0
- package/types/enhancers/withPlaceholder.d.ts +2 -4
- package/types/enhancers/withSitecoreContext.d.ts +4 -6
- package/types/index.d.ts +9 -4
|
@@ -17,9 +17,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.DateField = void 0;
|
|
18
18
|
const react_1 = __importDefault(require("react"));
|
|
19
19
|
const prop_types_1 = __importDefault(require("prop-types"));
|
|
20
|
-
const
|
|
20
|
+
const withFieldMetadata_1 = require("../enhancers/withFieldMetadata");
|
|
21
|
+
const withEmptyFieldEditingComponent_1 = require("../enhancers/withEmptyFieldEditingComponent");
|
|
22
|
+
const DefaultEmptyFieldEditingComponents_1 = require("./DefaultEmptyFieldEditingComponents");
|
|
23
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
24
|
+
exports.DateField = (0, withFieldMetadata_1.withFieldMetadata)((0, withEmptyFieldEditingComponent_1.withEmptyFieldEditingComponent)((_a) => {
|
|
21
25
|
var { field, tag, editable = true, render } = _a, otherProps = __rest(_a, ["field", "tag", "editable", "render"]);
|
|
22
|
-
if (!field || (!field.editable &&
|
|
26
|
+
if (!field || (!field.editable && (0, layout_1.isFieldValueEmpty)(field))) {
|
|
23
27
|
return null;
|
|
24
28
|
}
|
|
25
29
|
let children;
|
|
@@ -41,15 +45,19 @@ const DateField = (_a) => {
|
|
|
41
45
|
else {
|
|
42
46
|
return react_1.default.createElement(react_1.default.Fragment, null, children);
|
|
43
47
|
}
|
|
44
|
-
};
|
|
45
|
-
exports.DateField = DateField;
|
|
48
|
+
}, { defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponents_1.DefaultEmptyFieldEditingComponentText }));
|
|
46
49
|
exports.DateField.propTypes = {
|
|
47
50
|
field: prop_types_1.default.shape({
|
|
48
51
|
value: prop_types_1.default.string,
|
|
49
52
|
editable: prop_types_1.default.string,
|
|
53
|
+
metadata: prop_types_1.default.objectOf(prop_types_1.default.any),
|
|
50
54
|
}).isRequired,
|
|
51
55
|
tag: prop_types_1.default.string,
|
|
52
56
|
editable: prop_types_1.default.bool,
|
|
53
57
|
render: prop_types_1.default.func,
|
|
58
|
+
emptyFieldEditingComponent: prop_types_1.default.oneOfType([
|
|
59
|
+
prop_types_1.default.object,
|
|
60
|
+
prop_types_1.default.func,
|
|
61
|
+
]),
|
|
54
62
|
};
|
|
55
63
|
exports.DateField.displayName = 'Date';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DefaultEmptyFieldEditingComponentImage = exports.DefaultEmptyFieldEditingComponentText = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const DefaultEmptyFieldEditingComponentText = () => {
|
|
9
|
+
return react_1.default.createElement("span", null, "[No text in field]");
|
|
10
|
+
};
|
|
11
|
+
exports.DefaultEmptyFieldEditingComponentText = DefaultEmptyFieldEditingComponentText;
|
|
12
|
+
const DefaultEmptyFieldEditingComponentImage = () => {
|
|
13
|
+
const inlineStyles = {
|
|
14
|
+
minWidth: '48px',
|
|
15
|
+
minHeight: '48px',
|
|
16
|
+
maxWidth: '400px',
|
|
17
|
+
maxHeight: '400px',
|
|
18
|
+
cursor: 'pointer',
|
|
19
|
+
};
|
|
20
|
+
return (react_1.default.createElement("img", { alt: "", src: 'data:image/svg+xml,%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 240 240" style="enable-background:new 0 0 240 240;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bfill:none;%7D .st1%7Bfill:%23969696;%7D .st2%7Bfill:%23FFFFFF;%7D .st3%7Bfill:%23FFFFFF;stroke:%23FFFFFF;stroke-width:0.75;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg%3E%3Crect class="st0" width="240" height="240"/%3E%3Cg%3E%3Cg%3E%3Crect x="20" y="20" class="st1" width="200" height="200"/%3E%3C/g%3E%3Cg%3E%3Ccircle class="st2" cx="174" cy="67" r="14"/%3E%3Cpath class="st2" d="M174,54c7.17,0,13,5.83,13,13s-5.83,13-13,13s-13-5.83-13-13S166.83,54,174,54 M174,52 c-8.28,0-15,6.72-15,15s6.72,15,15,15s15-6.72,15-15S182.28,52,174,52L174,52z"/%3E%3C/g%3E%3Cpolyline class="st3" points="29.5,179.25 81.32,122.25 95.41,137.75 137.23,91.75 209.5,179.75 "/%3E%3C/g%3E%3C/g%3E%3C/svg%3E', className: "scEmptyImage", style: inlineStyles }));
|
|
21
|
+
};
|
|
22
|
+
exports.DefaultEmptyFieldEditingComponentImage = DefaultEmptyFieldEditingComponentImage;
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.EditFrame = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const withSitecoreContext_1 = require("../enhancers/withSitecoreContext");
|
|
9
|
-
const
|
|
9
|
+
const editing_1 = require("@sitecore-jss/sitecore-jss/editing");
|
|
10
10
|
const EditFrame = ({ children, dataSource, buttons, title, tooltip, cssClass, parameters, }) => {
|
|
11
11
|
var _a;
|
|
12
12
|
const { sitecoreContext } = (0, withSitecoreContext_1.useSitecoreContext)();
|
|
@@ -30,7 +30,7 @@ const EditFrame = ({ children, dataSource, buttons, title, tooltip, cssClass, pa
|
|
|
30
30
|
chromeData.contextItemUri = frameProps.sc_item;
|
|
31
31
|
}
|
|
32
32
|
chromeData.commands = buttons === null || buttons === void 0 ? void 0 : buttons.map((value) => {
|
|
33
|
-
return (0,
|
|
33
|
+
return (0, editing_1.mapButtonToCommand)(value, dataSource === null || dataSource === void 0 ? void 0 : dataSource.itemId, parameters);
|
|
34
34
|
});
|
|
35
35
|
return (react_1.default.createElement("div", Object.assign({ className: "scLooseFrameZone" }, frameProps),
|
|
36
36
|
react_1.default.createElement("span", { className: "scChromeData" }, JSON.stringify(chromeData)),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EditingScripts = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
9
|
+
const withSitecoreContext_1 = require("../enhancers/withSitecoreContext");
|
|
10
|
+
/**
|
|
11
|
+
* Renders client scripts and data for editing/preview mode in Pages.
|
|
12
|
+
* This script is only rendered when EditMode is Metadata, otherwise it renders nothing.
|
|
13
|
+
*/
|
|
14
|
+
const EditingScripts = () => {
|
|
15
|
+
const { sitecoreContext: { pageState, editMode, clientData, clientScripts }, } = (0, withSitecoreContext_1.useSitecoreContext)();
|
|
16
|
+
// Don't render anything if not in editing/preview mode
|
|
17
|
+
if (pageState === layout_1.LayoutServicePageState.Normal)
|
|
18
|
+
return react_1.default.createElement(react_1.default.Fragment, null);
|
|
19
|
+
if (editMode === layout_1.EditMode.Metadata) {
|
|
20
|
+
return (react_1.default.createElement(react_1.default.Fragment, null, clientScripts === null || clientScripts === void 0 ? void 0 :
|
|
21
|
+
clientScripts.map((src, index) => (react_1.default.createElement("script", { src: src, key: index }))),
|
|
22
|
+
clientData &&
|
|
23
|
+
Object.keys(clientData).map((id) => (react_1.default.createElement("script", { key: id, id: id, type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(clientData[id]) } })))));
|
|
24
|
+
}
|
|
25
|
+
return react_1.default.createElement(react_1.default.Fragment, null);
|
|
26
|
+
};
|
|
27
|
+
exports.EditingScripts = EditingScripts;
|
|
@@ -24,11 +24,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
const react_1 = __importStar(require("react"));
|
|
27
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
27
28
|
const withSitecoreContext_1 = require("../enhancers/withSitecoreContext");
|
|
28
29
|
class ErrorBoundary extends react_1.default.Component {
|
|
29
30
|
constructor(props) {
|
|
30
31
|
super(props);
|
|
31
|
-
this.defaultErrorMessage = 'There was a problem loading this section.';
|
|
32
|
+
this.defaultErrorMessage = 'There was a problem loading this section.';
|
|
32
33
|
this.defaultLoadingMessage = 'Loading component...';
|
|
33
34
|
this.state = { error: null };
|
|
34
35
|
}
|
|
@@ -36,27 +37,37 @@ class ErrorBoundary extends react_1.default.Component {
|
|
|
36
37
|
return { error: error };
|
|
37
38
|
}
|
|
38
39
|
componentDidCatch(error, errorInfo) {
|
|
40
|
+
var _a, _b;
|
|
41
|
+
if (this.showErrorDetails()) {
|
|
42
|
+
console.error(`An error occurred in component ${(_a = this.props.rendering) === null || _a === void 0 ? void 0 : _a.componentName} (${(_b = this.props.rendering) === null || _b === void 0 ? void 0 : _b.uid}): `);
|
|
43
|
+
}
|
|
39
44
|
console.error({ error, errorInfo });
|
|
40
45
|
}
|
|
41
46
|
isInDevMode() {
|
|
42
47
|
return process.env.NODE_ENV === 'development';
|
|
43
48
|
}
|
|
44
|
-
|
|
49
|
+
showErrorDetails() {
|
|
45
50
|
var _a, _b;
|
|
51
|
+
return (this.isInDevMode() ||
|
|
52
|
+
((_a = this.props.sitecoreContext) === null || _a === void 0 ? void 0 : _a.pageState) === layout_1.LayoutServicePageState.Edit ||
|
|
53
|
+
((_b = this.props.sitecoreContext) === null || _b === void 0 ? void 0 : _b.pageState) === layout_1.LayoutServicePageState.Preview);
|
|
54
|
+
}
|
|
55
|
+
render() {
|
|
56
|
+
var _a;
|
|
46
57
|
if (this.state.error) {
|
|
47
|
-
if (this.props.
|
|
48
|
-
return react_1.default.createElement(this.props.
|
|
58
|
+
if (this.props.errorComponent) {
|
|
59
|
+
return react_1.default.createElement(this.props.errorComponent, { error: this.state.error });
|
|
49
60
|
}
|
|
50
61
|
else {
|
|
51
|
-
if (this.
|
|
62
|
+
if (this.showErrorDetails()) {
|
|
52
63
|
return (react_1.default.createElement("div", null,
|
|
53
64
|
react_1.default.createElement("div", { className: "sc-jss-placeholder-error" },
|
|
54
65
|
"A rendering error occurred in component",
|
|
55
66
|
' ',
|
|
56
|
-
react_1.default.createElement("em", null, (
|
|
67
|
+
react_1.default.createElement("em", null, (_a = this.props.rendering) === null || _a === void 0 ? void 0 : _a.componentName),
|
|
57
68
|
react_1.default.createElement("br", null),
|
|
58
69
|
"Error: ",
|
|
59
|
-
react_1.default.createElement("em", null, this.state.error.message))));
|
|
70
|
+
react_1.default.createElement("em", null, this.state.error.message || JSON.stringify(this.state.error)))));
|
|
60
71
|
}
|
|
61
72
|
else {
|
|
62
73
|
return (react_1.default.createElement("div", null,
|
|
@@ -64,6 +75,10 @@ class ErrorBoundary extends react_1.default.Component {
|
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
}
|
|
78
|
+
// do not apply suspense on already dynamic components
|
|
79
|
+
if (this.props.isDynamic) {
|
|
80
|
+
return this.props.children;
|
|
81
|
+
}
|
|
67
82
|
return (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement("h4", null, this.props.componentLoadingMessage || this.defaultLoadingMessage) }, this.props.children));
|
|
68
83
|
}
|
|
69
84
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FieldMetadata = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const prop_types_1 = __importDefault(require("prop-types"));
|
|
9
|
+
/**
|
|
10
|
+
* The component which renders field metadata markup
|
|
11
|
+
* @param {FieldMetadataProps} props the props of the component
|
|
12
|
+
* @returns metadata markup wrapped around children
|
|
13
|
+
*/
|
|
14
|
+
const FieldMetadata = (props) => {
|
|
15
|
+
const data = JSON.stringify(props.metadata);
|
|
16
|
+
const attributes = {
|
|
17
|
+
type: 'text/sitecore',
|
|
18
|
+
chrometype: 'field',
|
|
19
|
+
className: 'scpm',
|
|
20
|
+
};
|
|
21
|
+
const codeOpenAttributes = Object.assign(Object.assign({}, attributes), { kind: 'open' });
|
|
22
|
+
const codeCloseAttributes = Object.assign(Object.assign({}, attributes), { kind: 'close' });
|
|
23
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
24
|
+
react_1.default.createElement("code", Object.assign({}, codeOpenAttributes), data),
|
|
25
|
+
props.children,
|
|
26
|
+
react_1.default.createElement("code", Object.assign({}, codeCloseAttributes))));
|
|
27
|
+
};
|
|
28
|
+
exports.FieldMetadata = FieldMetadata;
|
|
29
|
+
exports.FieldMetadata.displayName = 'FieldMetadata';
|
|
30
|
+
exports.FieldMetadata.propTypes = {
|
|
31
|
+
metadata: prop_types_1.default.object.isRequired,
|
|
32
|
+
children: prop_types_1.default.node.isRequired,
|
|
33
|
+
};
|
|
@@ -15,6 +15,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.File = void 0;
|
|
18
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
18
19
|
const prop_types_1 = __importDefault(require("prop-types"));
|
|
19
20
|
const react_1 = __importDefault(require("react"));
|
|
20
21
|
const File = (_a) => {
|
|
@@ -23,7 +24,7 @@ const File = (_a) => {
|
|
|
23
24
|
*/
|
|
24
25
|
var { field, children } = _a, otherProps = __rest(_a, ["field", "children"]);
|
|
25
26
|
const dynamicField = field;
|
|
26
|
-
if (!field || (
|
|
27
|
+
if (!field || (0, layout_1.isFieldValueEmpty)(dynamicField)) {
|
|
27
28
|
return null;
|
|
28
29
|
}
|
|
29
30
|
// handle link directly on field for forgetful devs
|
|
@@ -3,13 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.HiddenRendering = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const styles = {
|
|
9
|
-
height: '100px',
|
|
10
9
|
backgroundImage: 'linear-gradient(45deg, #ffffff 25%, #dcdcdc 25%, #dcdcdc 50%, #ffffff 50%, #ffffff 75%, #dcdcdc 75%, #dcdcdc 100%)',
|
|
11
10
|
backgroundSize: '3px 3px',
|
|
11
|
+
display: 'flex',
|
|
12
|
+
justifyContent: 'center',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
padding: '30px',
|
|
15
|
+
color: '#aaa',
|
|
12
16
|
};
|
|
13
|
-
const HiddenRendering = () => react_1.default.createElement("div", { style: styles });
|
|
17
|
+
const HiddenRendering = () => react_1.default.createElement("div", { style: styles }, "The component is hidden");
|
|
14
18
|
exports.HiddenRendering = HiddenRendering;
|
|
15
|
-
exports.HIDDEN_RENDERING_NAME = 'Hidden Rendering';
|
|
@@ -20,6 +20,10 @@ const prop_types_1 = __importDefault(require("prop-types"));
|
|
|
20
20
|
const react_1 = __importDefault(require("react"));
|
|
21
21
|
const utils_1 = require("../utils");
|
|
22
22
|
const utils_2 = require("../utils");
|
|
23
|
+
const withFieldMetadata_1 = require("../enhancers/withFieldMetadata");
|
|
24
|
+
const withEmptyFieldEditingComponent_1 = require("../enhancers/withEmptyFieldEditingComponent");
|
|
25
|
+
const DefaultEmptyFieldEditingComponents_1 = require("./DefaultEmptyFieldEditingComponents");
|
|
26
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
23
27
|
const getEditableWrapper = (editableMarkup, ...otherProps) => (
|
|
24
28
|
// create an inline wrapper and use dangerouslySetInnerHTML.
|
|
25
29
|
// if we try to parse the EE value, the parser will strip invalid or disallowed attributes from html elements - and EE uses several
|
|
@@ -66,11 +70,10 @@ const getEEMarkup = (imageField, imageParams, mediaUrlPrefix, otherProps) => {
|
|
|
66
70
|
return getEditableWrapper(editableMarkup);
|
|
67
71
|
};
|
|
68
72
|
exports.getEEMarkup = getEEMarkup;
|
|
69
|
-
|
|
73
|
+
exports.Image = (0, withFieldMetadata_1.withFieldMetadata)((0, withEmptyFieldEditingComponent_1.withEmptyFieldEditingComponent)((_a) => {
|
|
70
74
|
var { editable = true, imageParams, field, mediaUrlPrefix } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix"]);
|
|
71
75
|
const dynamicMedia = field;
|
|
72
|
-
if (!field ||
|
|
73
|
-
(!dynamicMedia.editable && !dynamicMedia.value && !dynamicMedia.src)) {
|
|
76
|
+
if (!field || (!dynamicMedia.editable && (0, layout_1.isFieldValueEmpty)(dynamicMedia))) {
|
|
74
77
|
return null;
|
|
75
78
|
}
|
|
76
79
|
const imageField = dynamicMedia;
|
|
@@ -84,23 +87,17 @@ const Image = (_a) => {
|
|
|
84
87
|
if (!img) {
|
|
85
88
|
return null;
|
|
86
89
|
}
|
|
90
|
+
// prevent metadata from being passed to the img tag
|
|
91
|
+
if (img.metadata) {
|
|
92
|
+
delete img.metadata;
|
|
93
|
+
}
|
|
87
94
|
const attrs = getImageAttrs(Object.assign(Object.assign({}, img), otherProps), imageParams, mediaUrlPrefix);
|
|
88
95
|
if (attrs) {
|
|
89
96
|
return react_1.default.createElement("img", Object.assign({}, attrs));
|
|
90
97
|
}
|
|
91
98
|
return null; // we can't handle the truth
|
|
92
|
-
};
|
|
93
|
-
exports.Image = Image;
|
|
99
|
+
}, { defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponents_1.DefaultEmptyFieldEditingComponentImage }));
|
|
94
100
|
exports.Image.propTypes = {
|
|
95
|
-
media: prop_types_1.default.oneOfType([
|
|
96
|
-
prop_types_1.default.shape({
|
|
97
|
-
src: prop_types_1.default.string,
|
|
98
|
-
}),
|
|
99
|
-
prop_types_1.default.shape({
|
|
100
|
-
value: prop_types_1.default.object,
|
|
101
|
-
editable: prop_types_1.default.string,
|
|
102
|
-
}),
|
|
103
|
-
]),
|
|
104
101
|
field: prop_types_1.default.oneOfType([
|
|
105
102
|
prop_types_1.default.shape({
|
|
106
103
|
src: prop_types_1.default.string,
|
|
@@ -113,5 +110,9 @@ exports.Image.propTypes = {
|
|
|
113
110
|
editable: prop_types_1.default.bool,
|
|
114
111
|
mediaUrlPrefix: prop_types_1.default.instanceOf(RegExp),
|
|
115
112
|
imageParams: prop_types_1.default.objectOf(prop_types_1.default.oneOfType([prop_types_1.default.number.isRequired, prop_types_1.default.string.isRequired]).isRequired),
|
|
113
|
+
emptyFieldEditingComponent: prop_types_1.default.oneOfType([
|
|
114
|
+
prop_types_1.default.object,
|
|
115
|
+
prop_types_1.default.func,
|
|
116
|
+
]),
|
|
116
117
|
};
|
|
117
118
|
exports.Image.displayName = 'Image';
|
|
@@ -40,14 +40,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
40
40
|
exports.LinkPropTypes = exports.Link = void 0;
|
|
41
41
|
const react_1 = __importStar(require("react"));
|
|
42
42
|
const prop_types_1 = __importDefault(require("prop-types"));
|
|
43
|
-
|
|
43
|
+
const withFieldMetadata_1 = require("../enhancers/withFieldMetadata");
|
|
44
|
+
const withEmptyFieldEditingComponent_1 = require("../enhancers/withEmptyFieldEditingComponent");
|
|
45
|
+
const DefaultEmptyFieldEditingComponents_1 = require("./DefaultEmptyFieldEditingComponents");
|
|
46
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
47
|
+
exports.Link = (0, withFieldMetadata_1.withFieldMetadata)((0, withEmptyFieldEditingComponent_1.withEmptyFieldEditingComponent)(
|
|
48
|
+
// eslint-disable-next-line react/display-name
|
|
49
|
+
(0, react_1.forwardRef)((_a, ref) => {
|
|
44
50
|
var { field, editable = true, showLinkTextWithChildrenPresent } = _a, otherProps = __rest(_a, ["field", "editable", "showLinkTextWithChildrenPresent"]);
|
|
45
51
|
const children = otherProps.children;
|
|
46
52
|
const dynamicField = field;
|
|
47
|
-
if (!field ||
|
|
48
|
-
(!dynamicField.editableFirstPart &&
|
|
49
|
-
!dynamicField.value &&
|
|
50
|
-
!dynamicField.href)) {
|
|
53
|
+
if (!field || (!dynamicField.editableFirstPart && (0, layout_1.isFieldValueEmpty)(dynamicField))) {
|
|
51
54
|
return null;
|
|
52
55
|
}
|
|
53
56
|
const resultTags = [];
|
|
@@ -93,7 +96,7 @@ exports.Link = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
93
96
|
const linkText = showLinkTextWithChildrenPresent || !children ? link.text || link.href : null;
|
|
94
97
|
resultTags.push(react_1.default.createElement('a', Object.assign(Object.assign(Object.assign({}, anchorAttrs), otherProps), { key: 'link', ref }), linkText, children));
|
|
95
98
|
return react_1.default.createElement(react_1.default.Fragment, null, resultTags);
|
|
96
|
-
});
|
|
99
|
+
}), { defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponents_1.DefaultEmptyFieldEditingComponentText, isForwardRef: true }), true);
|
|
97
100
|
exports.LinkPropTypes = {
|
|
98
101
|
field: prop_types_1.default.oneOfType([
|
|
99
102
|
prop_types_1.default.shape({
|
|
@@ -107,6 +110,10 @@ exports.LinkPropTypes = {
|
|
|
107
110
|
]).isRequired,
|
|
108
111
|
editable: prop_types_1.default.bool,
|
|
109
112
|
showLinkTextWithChildrenPresent: prop_types_1.default.bool,
|
|
113
|
+
emptyFieldEditingComponent: prop_types_1.default.oneOfType([
|
|
114
|
+
prop_types_1.default.object,
|
|
115
|
+
prop_types_1.default.func,
|
|
116
|
+
]),
|
|
110
117
|
};
|
|
111
118
|
exports.Link.propTypes = exports.LinkPropTypes;
|
|
112
119
|
exports.Link.displayName = 'Link';
|
|
@@ -7,7 +7,8 @@ exports.Placeholder = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const PlaceholderCommon_1 = require("./PlaceholderCommon");
|
|
9
9
|
const withComponentFactory_1 = require("../enhancers/withComponentFactory");
|
|
10
|
-
const
|
|
10
|
+
const editing_1 = require("@sitecore-jss/sitecore-jss/editing");
|
|
11
|
+
const withSitecoreContext_1 = require("../enhancers/withSitecoreContext");
|
|
11
12
|
/**
|
|
12
13
|
* @param {HtmlElementRendering | ComponentRendering} rendering
|
|
13
14
|
*/
|
|
@@ -22,8 +23,8 @@ class PlaceholderComponent extends PlaceholderCommon_1.PlaceholderCommon {
|
|
|
22
23
|
}
|
|
23
24
|
componentDidMount() {
|
|
24
25
|
super.componentDidMount();
|
|
25
|
-
if (this.isEmpty &&
|
|
26
|
-
|
|
26
|
+
if (this.isEmpty && editing_1.HorizonEditor.isActive()) {
|
|
27
|
+
editing_1.HorizonEditor.resetChromes();
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
@@ -37,6 +38,7 @@ class PlaceholderComponent extends PlaceholderCommon_1.PlaceholderCommon {
|
|
|
37
38
|
return react_1.default.createElement("div", { className: "sc-jss-empty-placeholder" }, node);
|
|
38
39
|
}
|
|
39
40
|
render() {
|
|
41
|
+
var _a;
|
|
40
42
|
const childProps = Object.assign({}, this.props);
|
|
41
43
|
delete childProps.componentFactory;
|
|
42
44
|
if (this.state.error) {
|
|
@@ -49,9 +51,9 @@ class PlaceholderComponent extends PlaceholderCommon_1.PlaceholderCommon {
|
|
|
49
51
|
"."));
|
|
50
52
|
}
|
|
51
53
|
const renderingData = childProps.rendering;
|
|
52
|
-
const placeholderData = PlaceholderCommon_1.PlaceholderCommon.getPlaceholderDataFromRenderingData(renderingData, this.props.name);
|
|
53
|
-
const components = this.getComponentsForRenderingData(placeholderData);
|
|
54
|
+
const placeholderData = PlaceholderCommon_1.PlaceholderCommon.getPlaceholderDataFromRenderingData(renderingData, this.props.name, (_a = this.props.sitecoreContext) === null || _a === void 0 ? void 0 : _a.editMode);
|
|
54
55
|
this.isEmpty = placeholderData.every((rendering) => isRawRendering(rendering));
|
|
56
|
+
const components = this.getComponentsForRenderingData(placeholderData);
|
|
55
57
|
if (this.props.renderEmpty && this.isEmpty) {
|
|
56
58
|
const rendered = this.props.renderEmpty(components);
|
|
57
59
|
return components.length ? this.renderEmptyPlaceholder(rendered) : rendered;
|
|
@@ -77,4 +79,5 @@ class PlaceholderComponent extends PlaceholderCommon_1.PlaceholderCommon {
|
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
PlaceholderComponent.propTypes = PlaceholderCommon_1.PlaceholderCommon.propTypes;
|
|
80
|
-
|
|
82
|
+
const PlaceholderWithComponentFactory = (0, withComponentFactory_1.withComponentFactory)(PlaceholderComponent);
|
|
83
|
+
exports.Placeholder = (0, withSitecoreContext_1.withSitecoreContext)()(PlaceholderWithComponentFactory);
|
|
@@ -18,12 +18,15 @@ exports.PlaceholderCommon = void 0;
|
|
|
18
18
|
const react_1 = __importDefault(require("react"));
|
|
19
19
|
const prop_types_1 = __importDefault(require("prop-types"));
|
|
20
20
|
const MissingComponent_1 = require("./MissingComponent");
|
|
21
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
22
|
+
const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
|
|
21
23
|
const utils_1 = require("../utils");
|
|
22
24
|
const HiddenRendering_1 = require("./HiddenRendering");
|
|
23
25
|
const FEaaSComponent_1 = require("./FEaaSComponent");
|
|
24
26
|
const FEaaSWrapper_1 = require("./FEaaSWrapper");
|
|
25
27
|
const BYOCComponent_1 = require("./BYOCComponent");
|
|
26
28
|
const BYOCWrapper_1 = require("./BYOCWrapper");
|
|
29
|
+
const PlaceholderMetadata_1 = require("./PlaceholderMetadata");
|
|
27
30
|
const ErrorBoundary_1 = __importDefault(require("./ErrorBoundary"));
|
|
28
31
|
class PlaceholderCommon extends react_1.default.Component {
|
|
29
32
|
constructor(props) {
|
|
@@ -34,29 +37,38 @@ class PlaceholderCommon extends react_1.default.Component {
|
|
|
34
37
|
this.updateKeyAttributes = this.updateKeyAttributes.bind(this);
|
|
35
38
|
this.createRawElement = this.createRawElement.bind(this);
|
|
36
39
|
}
|
|
37
|
-
static getPlaceholderDataFromRenderingData(rendering, name) {
|
|
40
|
+
static getPlaceholderDataFromRenderingData(rendering, name, editMode) {
|
|
38
41
|
let result;
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
let phName = name.slice();
|
|
43
|
+
/**
|
|
44
|
+
* Process (SXA) dynamic placeholders
|
|
45
|
+
* Find and replace the matching dynamic placeholder e.g 'nameOfContainer-{*}' with the requested e.g. 'nameOfContainer-1'.
|
|
46
|
+
* For Metadata EditMode, we need to keep the raw placeholder name in place.
|
|
47
|
+
*/
|
|
41
48
|
if (rendering === null || rendering === void 0 ? void 0 : rendering.placeholders) {
|
|
42
49
|
Object.keys(rendering.placeholders).forEach((placeholder) => {
|
|
43
|
-
const patternPlaceholder =
|
|
44
|
-
?
|
|
50
|
+
const patternPlaceholder = (0, layout_1.isDynamicPlaceholder)(placeholder)
|
|
51
|
+
? (0, layout_1.getDynamicPlaceholderPattern)(placeholder)
|
|
45
52
|
: null;
|
|
46
|
-
if (patternPlaceholder && patternPlaceholder.test(
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
if (patternPlaceholder && patternPlaceholder.test(phName)) {
|
|
54
|
+
if (editMode === layout_1.EditMode.Metadata) {
|
|
55
|
+
phName = placeholder;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
rendering.placeholders[phName] = rendering.placeholders[placeholder];
|
|
59
|
+
delete rendering.placeholders[placeholder];
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
62
|
});
|
|
51
63
|
}
|
|
52
64
|
if (rendering && rendering.placeholders && Object.keys(rendering.placeholders).length > 0) {
|
|
53
|
-
result = rendering.placeholders[
|
|
65
|
+
result = rendering.placeholders[phName];
|
|
54
66
|
}
|
|
55
67
|
else {
|
|
56
68
|
result = null;
|
|
57
69
|
}
|
|
58
70
|
if (!result) {
|
|
59
|
-
console.warn(`Placeholder '${
|
|
71
|
+
console.warn(`Placeholder '${phName}' was not found in the current rendering data`, JSON.stringify(rendering, null, 2));
|
|
60
72
|
return [];
|
|
61
73
|
}
|
|
62
74
|
return result;
|
|
@@ -78,13 +90,16 @@ class PlaceholderCommon extends react_1.default.Component {
|
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
getComponentsForRenderingData(placeholderData) {
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
var _a;
|
|
94
|
+
const _b = this.props, { name, fields: placeholderFields, params: placeholderParams, missingComponentComponent, hiddenRenderingComponent } = _b, placeholderProps = __rest(_b, ["name", "fields", "params", "missingComponentComponent", "hiddenRenderingComponent"]);
|
|
95
|
+
const transformedComponents = placeholderData
|
|
83
96
|
.map((rendering, index) => {
|
|
97
|
+
var _a, _b;
|
|
84
98
|
const key = rendering.uid
|
|
85
99
|
? rendering.uid
|
|
86
100
|
: `component-${index}`;
|
|
87
101
|
const commonProps = { key };
|
|
102
|
+
let isEmpty = false;
|
|
88
103
|
// if the element is not a 'component rendering', render it 'raw'
|
|
89
104
|
if (!rendering.componentName &&
|
|
90
105
|
rendering.name) {
|
|
@@ -92,11 +107,13 @@ class PlaceholderCommon extends react_1.default.Component {
|
|
|
92
107
|
}
|
|
93
108
|
const componentRendering = rendering;
|
|
94
109
|
let component;
|
|
95
|
-
if (componentRendering.componentName ===
|
|
110
|
+
if (componentRendering.componentName === sitecore_jss_1.constants.HIDDEN_RENDERING_NAME) {
|
|
96
111
|
component = hiddenRenderingComponent !== null && hiddenRenderingComponent !== void 0 ? hiddenRenderingComponent : HiddenRendering_1.HiddenRendering;
|
|
112
|
+
isEmpty = true;
|
|
97
113
|
}
|
|
98
114
|
else if (!componentRendering.componentName) {
|
|
99
115
|
component = () => react_1.default.createElement(react_1.default.Fragment, null);
|
|
116
|
+
isEmpty = true;
|
|
100
117
|
}
|
|
101
118
|
else {
|
|
102
119
|
component = this.getComponentForRendering(componentRendering);
|
|
@@ -119,20 +136,34 @@ class PlaceholderCommon extends react_1.default.Component {
|
|
|
119
136
|
if (!component) {
|
|
120
137
|
console.error(`Placeholder ${name} contains unknown component ${componentRendering.componentName}. Ensure that a React component exists for it, and that it is registered in your componentFactory.js.`);
|
|
121
138
|
component = missingComponentComponent !== null && missingComponentComponent !== void 0 ? missingComponentComponent : MissingComponent_1.MissingComponent;
|
|
139
|
+
isEmpty = true;
|
|
122
140
|
}
|
|
123
141
|
const finalProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, commonProps), placeholderProps), ((placeholderFields || componentRendering.fields) && {
|
|
124
142
|
fields: Object.assign(Object.assign({}, placeholderFields), componentRendering.fields),
|
|
125
143
|
})), ((placeholderParams || componentRendering.params) && {
|
|
126
144
|
params: Object.assign(Object.assign(Object.assign({}, placeholderParams), componentRendering.params), this.getSXAParams(componentRendering)),
|
|
127
145
|
})), { rendering: componentRendering });
|
|
128
|
-
|
|
146
|
+
let rendered = react_1.default.createElement(component, this.props.modifyComponentProps ? this.props.modifyComponentProps(finalProps) : finalProps);
|
|
147
|
+
if (!isEmpty) {
|
|
148
|
+
// assign type based on passed element - type='text/sitecore' should be ignored when renderEach Placeholder prop function is being used
|
|
149
|
+
const type = rendered.props.type === 'text/sitecore' ? rendered.props.type : '';
|
|
150
|
+
// wrapping with error boundary could cause problems in case where parent component uses withPlaceholder HOC and tries to access its children props
|
|
151
|
+
// that's why we need to expose element's props here
|
|
152
|
+
rendered = (react_1.default.createElement(ErrorBoundary_1.default, Object.assign({ key: rendered.type + '-' + index, errorComponent: this.props.errorComponent, componentLoadingMessage: this.props.componentLoadingMessage, type: type, isDynamic: ((_a = component.render) === null || _a === void 0 ? void 0 : _a.preload) ? true : false }, rendered.props), rendered));
|
|
153
|
+
}
|
|
154
|
+
// if editMode is equal to 'metadata' then emit shallow chromes for hydration in Pages
|
|
155
|
+
if (((_b = this.props.sitecoreContext) === null || _b === void 0 ? void 0 : _b.editMode) === layout_1.EditMode.Metadata) {
|
|
156
|
+
return (react_1.default.createElement(PlaceholderMetadata_1.PlaceholderMetadata, { key: key, rendering: rendering }, rendered));
|
|
157
|
+
}
|
|
158
|
+
return rendered;
|
|
129
159
|
})
|
|
130
|
-
.filter((element) => element)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
160
|
+
.filter((element) => element); // remove nulls
|
|
161
|
+
if (((_a = this.props.sitecoreContext) === null || _a === void 0 ? void 0 : _a.editMode) === layout_1.EditMode.Metadata) {
|
|
162
|
+
return [
|
|
163
|
+
react_1.default.createElement(PlaceholderMetadata_1.PlaceholderMetadata, { key: this.props.rendering.uid, placeholderName: name, rendering: this.props.rendering }, transformedComponents),
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
return transformedComponents;
|
|
136
167
|
}
|
|
137
168
|
getComponentForRendering(renderingDefinition) {
|
|
138
169
|
var _a;
|
|
@@ -208,4 +239,5 @@ PlaceholderCommon.propTypes = {
|
|
|
208
239
|
prop_types_1.default.func,
|
|
209
240
|
]),
|
|
210
241
|
modifyComponentProps: prop_types_1.default.func,
|
|
242
|
+
sitecoreContext: prop_types_1.default.object,
|
|
211
243
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PlaceholderMetadata = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const layout_1 = require("@sitecore-jss/sitecore-jss/layout");
|
|
9
|
+
/**
|
|
10
|
+
* default value of uid for root placeholder when uid is not present.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_PLACEHOLDER_UID = '00000000-0000-0000-0000-000000000000';
|
|
13
|
+
/**
|
|
14
|
+
* A React component to generate metadata blocks for a placeholder or rendering.
|
|
15
|
+
* It utilizes dynamic attributes based on whether the component acts as a placeholder
|
|
16
|
+
* or as a rendering to properly render the surrounding code blocks.
|
|
17
|
+
*
|
|
18
|
+
* @param {object} props The properties passed to the component.
|
|
19
|
+
* @param {ComponentRendering} props.rendering The rendering data.
|
|
20
|
+
* @param {string} [props.placeholderName] The name of the placeholder.
|
|
21
|
+
* @param {JSX.Element} props.children The child components or elements to be wrapped by the metadata code blocks.
|
|
22
|
+
* @returns {JSX.Element} A React fragment containing open and close code blocks surrounding the children elements.
|
|
23
|
+
*/
|
|
24
|
+
const PlaceholderMetadata = ({ rendering, placeholderName, children, }) => {
|
|
25
|
+
const getCodeBlockAttributes = (kind, id, placeholderName) => {
|
|
26
|
+
const chrometype = placeholderName ? 'placeholder' : 'rendering';
|
|
27
|
+
const attributes = {
|
|
28
|
+
type: 'text/sitecore',
|
|
29
|
+
chrometype: chrometype,
|
|
30
|
+
className: 'scpm',
|
|
31
|
+
kind: kind,
|
|
32
|
+
};
|
|
33
|
+
if (kind === 'open') {
|
|
34
|
+
if (chrometype === 'placeholder' && placeholderName) {
|
|
35
|
+
let phId = '';
|
|
36
|
+
for (const placeholder of Object.keys(rendering.placeholders)) {
|
|
37
|
+
if (placeholderName === placeholder) {
|
|
38
|
+
phId = id
|
|
39
|
+
? `${placeholderName}_${id}`
|
|
40
|
+
: `${placeholderName}_${DEFAULT_PLACEHOLDER_UID}`;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
// Check if the placeholder is a dynamic placeholder
|
|
44
|
+
if ((0, layout_1.isDynamicPlaceholder)(placeholder)) {
|
|
45
|
+
const pattern = (0, layout_1.getDynamicPlaceholderPattern)(placeholder);
|
|
46
|
+
// Check if the placeholder matches the dynamic placeholder pattern
|
|
47
|
+
if (pattern.test(placeholderName)) {
|
|
48
|
+
phId = id ? `${placeholder}_${id}` : `${placeholder}_${DEFAULT_PLACEHOLDER_UID}`;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
attributes.id = phId;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
attributes.id = id;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return attributes;
|
|
60
|
+
};
|
|
61
|
+
const renderComponent = (uid, placeholderName) => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
62
|
+
react_1.default.createElement("code", Object.assign({}, getCodeBlockAttributes('open', uid, placeholderName))),
|
|
63
|
+
children,
|
|
64
|
+
react_1.default.createElement("code", Object.assign({}, getCodeBlockAttributes('close', uid, placeholderName)))));
|
|
65
|
+
return react_1.default.createElement(react_1.default.Fragment, null, renderComponent(rendering.uid, placeholderName));
|
|
66
|
+
};
|
|
67
|
+
exports.PlaceholderMetadata = PlaceholderMetadata;
|