diff --git a/Resources/Private/Translations/en/Main.xlf b/Resources/Private/Translations/en/Main.xlf
index bb33ed1b50..0db6995fa5 100644
--- a/Resources/Private/Translations/en/Main.xlf
+++ b/Resources/Private/Translations/en/Main.xlf
@@ -11,6 +11,9 @@
+
+
+
diff --git a/Tests/IntegrationTests/utils.js b/Tests/IntegrationTests/utils.js
index 8056cef048..98e3c5b070 100644
--- a/Tests/IntegrationTests/utils.js
+++ b/Tests/IntegrationTests/utils.js
@@ -28,10 +28,6 @@ export async function checkPropTypes() {
if (error[0] && error[0].search('Warning: Unsafe legacy lifecycles') >= 0) {
delete error[0];
}
- // Quick fix to be able to use node 16 with testcafe @see https://github.com/DevExpress/testcafe/issues/7097
- if (error[0] && error[0].search('hammerhead.js') >= 0) {
- delete error[0];
- }
if (error[0]) {
console.log('These console errors were the cause of the failed test:', error);
}
diff --git a/packages/neos-ui-editors/src/SecondaryEditors/ImageCropper/index.js b/packages/neos-ui-editors/src/SecondaryEditors/ImageCropper/index.js
index 7c10da750e..2aedba50a7 100644
--- a/packages/neos-ui-editors/src/SecondaryEditors/ImageCropper/index.js
+++ b/packages/neos-ui-editors/src/SecondaryEditors/ImageCropper/index.js
@@ -93,11 +93,14 @@ export default class ImageCropper extends PureComponent {
componentDidMount() {
//
// Calculate and set maximum height for the cropped image
- const containerHeight = this.containerNode.parentElement.clientHeight;
+ // The upper toolbars (the publish tool bar and ckeditor bar) are each 41px
+ const upperToolbarHeights = 41 + 41;
+ const secondaryEditorHeight = window.innerHeight - upperToolbarHeights;
const toolbarStyles = getComputedStyle(this.toolbarNode);
const toolbarFullHeight = parseInt(toolbarStyles.height, 10) + parseInt(toolbarStyles['margin-top'], 10) + parseInt(toolbarStyles['margin-bottom'], 10);
const spacing = 32;
- const height = (containerHeight - toolbarFullHeight - spacing) + 'px';
+ const height = (secondaryEditorHeight - toolbarFullHeight - spacing) + 'px';
+
const imageNode = this.containerNode.querySelector('.ReactCrop__image');
const imageCopyNode = this.containerNode.querySelector('.ReactCrop__image-copy');
imageNode.style.maxHeight = height;
diff --git a/packages/neos-ui/src/manifest.js b/packages/neos-ui/src/manifest.js
index 87fcd05f64..7668d68c2c 100644
--- a/packages/neos-ui/src/manifest.js
+++ b/packages/neos-ui/src/manifest.js
@@ -20,6 +20,7 @@ import {
import initializeContentDomNode from '@neos-project/neos-ui-guest-frame/src/initializeContentDomNode';
import style from '@neos-project/neos-ui-guest-frame/src/style.module.css';
+import backend from '@neos-project/neos-ui-backend-connector';
manifest('main', {}, globalRegistry => {
//
@@ -513,7 +514,7 @@ manifest('main', {}, globalRegistry => {
// When the server advices to replace a node (e.g. on property change), put the delivered html to the
// correct place inside the DOM
//
- serverFeedbackHandlers.set('Neos.Neos.Ui:ReloadContentOutOfBand/Main', (feedbackPayload, {store, globalRegistry}) => {
+ serverFeedbackHandlers.set('Neos.Neos.Ui:ReloadContentOutOfBand/Main', async (feedbackPayload, {store, globalRegistry}) => {
const {contextPath, renderedContent, nodeDomAddress} = feedbackPayload;
const domNode = nodeDomAddress && findNodeInGuestFrame(
nodeDomAddress.contextPath,
@@ -543,6 +544,27 @@ manifest('main', {}, globalRegistry => {
const children = findAllChildNodes(contentElement);
+ // in case there are foreign referenced nodes, we need to put them into the store:
+ const uninitializedReferencedNodes = [];
+ for (const el of children) {
+ const contextPath = el.getAttribute('data-__neos-node-contextpath');
+ if (!selectors.CR.Nodes.byContextPathSelector(contextPath)(store.getState())) {
+ uninitializedReferencedNodes.push(contextPath);
+ }
+ }
+ if (uninitializedReferencedNodes.length) {
+ const {q} = backend.get();
+ const additionalNodes = await q(uninitializedReferencedNodes).get();
+ if (additionalNodes.length) {
+ store.dispatch(actions.CR.Nodes.merge(
+ additionalNodes.reduce((carry, node) => {
+ carry[node.contextPath] = node;
+ return carry;
+ }, {})
+ ));
+ }
+ }
+
const nodes = Object.assign(
{[contextPath]: selectors.CR.Nodes.byContextPathSelector(contextPath)(store.getState())},
...children.map(el => {
diff --git a/packages/react-ui-components/src/DateInput/dateInput.tsx b/packages/react-ui-components/src/DateInput/dateInput.tsx
index cfaf9d3ae6..9416d91dea 100644
--- a/packages/react-ui-components/src/DateInput/dateInput.tsx
+++ b/packages/react-ui-components/src/DateInput/dateInput.tsx
@@ -10,6 +10,9 @@ import {PickDefaultProps} from '../utils-typescript';
import Button from '../Button';
import Icon from '../Icon';
+// WHY: Because momentJs locales are not bundled automatically, we have to explicitly add them.
+import 'moment/locale/de';
+
export interface DateInputProps {
/**
* The Date instance which represents the selected value.
diff --git a/packages/react-ui-components/src/Dialog/dialog.tsx b/packages/react-ui-components/src/Dialog/dialog.tsx
index 144d810c0d..09c79c1db2 100644
--- a/packages/react-ui-components/src/Dialog/dialog.tsx
+++ b/packages/react-ui-components/src/Dialog/dialog.tsx
@@ -30,9 +30,9 @@ export interface DialogProps {
readonly isOpen: boolean;
/**
- * The handler which gets called once the user clicks on the close symbol in the top right corner of the Dialog.
+ * An optional handler, which gets called once the user clicks on the close symbol in the top right corner of the Dialog.
*/
- readonly onRequestClose: () => void;
+ readonly onRequestClose?: () => void;
/**
* An optional boolean flag to keep the user in the dialog.
@@ -99,7 +99,9 @@ class DialogWithOverlay extends PureComponent {
this.startShaking();
return false;
}
- this.props.onRequestClose();
+ if (this.props.onRequestClose) {
+ this.props.onRequestClose();
+ }
return true;
}
};
@@ -191,6 +193,7 @@ class DialogWithOverlay extends PureComponent {
actions,
theme,
type,
+ preventClosing,
onRequestClose,
...rest
} = this.props;