diff --git a/Classes/Aspects/AugmentationAspect.php b/Classes/Aspects/AugmentationAspect.php index f57ed7d88c..281e812d1f 100644 --- a/Classes/Aspects/AugmentationAspect.php +++ b/Classes/Aspects/AugmentationAspect.php @@ -38,24 +38,12 @@ class AugmentationAspect */ protected $nodeAuthorizationService; - /** - * @Flow\Inject - * @var UserLocaleService - */ - protected $userLocaleService; - /** * @Flow\Inject * @var HtmlAugmenter */ protected $htmlAugmenter; - /** - * @Flow\Inject - * @var NodeInfoHelper - */ - protected $nodeInfoHelper; - /** * @Flow\Inject * @var SessionInterface @@ -126,16 +114,7 @@ public function contentElementAugmentation(JoinPointInterface $joinPoint) $attributes['data-__neos-node-contextpath'] = $node->getContextPath(); $attributes['data-__neos-fusion-path'] = $fusionPath; - $this->userLocaleService->switchToUILocale(); - - $serializedNode = json_encode($this->nodeInfoHelper->renderNodeWithPropertiesAndChildrenInformation($node, $this->controllerContext)); - - $this->userLocaleService->switchToUILocale(true); - - $wrappedContent = $this->htmlAugmenter->addAttributes($content, $attributes, 'div'); - $wrappedContent .= ""; - - return $wrappedContent; + return $this->htmlAugmenter->addAttributes($content, $attributes); } /** diff --git a/Classes/ContentRepository/Service/NodeService.php b/Classes/ContentRepository/Service/NodeService.php index 0e725bb277..372a33867a 100644 --- a/Classes/ContentRepository/Service/NodeService.php +++ b/Classes/ContentRepository/Service/NodeService.php @@ -11,8 +11,13 @@ * source code. */ +use Doctrine\ORM\EntityManagerInterface; +use Neos\ContentRepository\Domain\Factory\NodeFactory; +use Neos\ContentRepository\Domain\Model\NodeData; use Neos\ContentRepository\Domain\Model\NodeInterface; use Neos\ContentRepository\Domain\Model\Workspace; +use Neos\ContentRepository\Domain\Repository\NodeDataRepository; +use Neos\ContentRepository\Domain\Service\Context; use Neos\ContentRepository\Domain\Service\ContextFactoryInterface; use Neos\ContentRepository\Domain\Utility\NodePaths; use Neos\Eel\FlowQuery\FlowQuery; @@ -46,6 +51,35 @@ class NodeService */ protected $domainRepository; + /** + * @Flow\Inject + * @var NodeDataRepository + */ + protected $nodeDataRepository; + + /** + * @Flow\Inject + * @var EntityManagerInterface + */ + protected $entityManager; + + /** + * @Flow\Inject + * @var NodeFactory + */ + protected $nodeFactory; + + /** + * @var array + */ + protected array $contextCache = []; + + /** + * @Flow\InjectConfiguration(path="nodeTypeRoles.ignored", package="Neos.Neos.Ui") + * @var string + */ + protected $ignoredNodeTypeRole; + /** * Helper method to retrieve the closest document for a node * @@ -86,11 +120,72 @@ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $ $nodePath = $nodePathAndContext['nodePath']; $workspaceName = $nodePathAndContext['workspaceName']; $dimensions = $nodePathAndContext['dimensions']; + $siteNodeName = $site ? $site->getNodeName() : explode('/', $nodePath)[2]; + + // Prevent reloading the same context multiple times + $contextHash = md5(implode('|', [$siteNodeName, $workspaceName, json_encode($dimensions), $includeAll])); + if (isset($this->contextCache[$contextHash])) { + $context = $this->contextCache[$contextHash]; + } else { + $contextProperties = $this->prepareContextProperties($workspaceName, $dimensions); + + if ($site === null) { + $site = $this->siteRepository->findOneByNodeName($siteNodeName); + } + + if ($domain === null) { + $domain = $this->domainRepository->findOneBySite($site); + } + $contextProperties['currentSite'] = $site; + $contextProperties['currentDomain'] = $domain; + if ($includeAll === true) { + $contextProperties['invisibleContentShown'] = true; + $contextProperties['removedContentShown'] = true; + $contextProperties['inaccessibleContentShown'] = true; + } + + $context = $this->contextFactory->create( + $contextProperties + ); + + $workspace = $context->getWorkspace(false); + if (!$workspace) { + return new Error( + sprintf('Could not convert the given source to Node object because the workspace "%s" as specified in the context node path does not exist.', $workspaceName), + 1451392329 + ); + } + $this->contextCache[$contextHash] = $context; + } + + return $context->getNode($nodePath); + } + + /** + * Converts given context paths to a node objects + * + * @param string[] $nodeContextPaths + * @return NodeInterface[]|Error + */ + public function getNodesFromContextPaths(array $nodeContextPaths, Site $site = null, Domain $domain = null, $includeAll = false): array|Error + { + if (!$nodeContextPaths) { + return []; + } + + $nodePaths = array_map(static function($nodeContextPath) { + return NodePaths::explodeContextPath($nodeContextPath)['nodePath']; + }, $nodeContextPaths); + + $nodePathAndContext = NodePaths::explodeContextPath($nodeContextPaths[0]); + $nodePath = $nodePathAndContext['nodePath']; + $workspaceName = $nodePathAndContext['workspaceName']; + $dimensions = $nodePathAndContext['dimensions']; + $siteNodeName = explode('/', $nodePath)[2]; $contextProperties = $this->prepareContextProperties($workspaceName, $dimensions); if ($site === null) { - list(, , $siteNodeName) = explode('/', $nodePath); $site = $this->siteRepository->findOneByNodeName($siteNodeName); } @@ -105,10 +200,7 @@ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $ $contextProperties['removedContentShown'] = true; $contextProperties['inaccessibleContentShown'] = true; } - - $context = $this->contextFactory->create( - $contextProperties - ); + $context = $this->contextFactory->create($contextProperties); $workspace = $context->getWorkspace(false); if (!$workspace) { @@ -118,7 +210,183 @@ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $ ); } - return $context->getNode($nodePath); + // Query nodes and their variants from the database + $queryBuilder = $this->entityManager->createQueryBuilder(); + $workspaces = $this->collectWorkspaceAndAllBaseWorkspaces($workspace); + $workspacesNames = array_map(static function(Workspace $workspace) { return $workspace->getName(); }, $workspaces); + + // Filter by workspace and its parents + $queryBuilder->select('n') + ->from(NodeData::class, 'n') + ->where('n.workspace IN (:workspaces)') + ->andWhere('n.movedTo IS NULL') + ->andWhere('n.path IN (:nodePaths)') + ->setParameter('workspaces', $workspacesNames) + ->setParameter('nodePaths', $nodePaths); + $query = $queryBuilder->getQuery(); + $nodeDataWithVariants = $query->getResult(); + + // Remove node duplicates + $reducedNodeData = $this->reduceNodeVariantsByWorkspacesAndDimensions($nodeDataWithVariants, $workspaces, $dimensions); + + // Convert nodedata objects to nodes + return array_reduce($reducedNodeData, function (array $carry, NodeData $nodeData) use ($context) { + $node = $this->nodeFactory->createFromNodeData($nodeData, $context); + if ($node !== null) { + $carry[] = $node; + } + $context->getFirstLevelNodeCache()->setByPath($node->getPath(), $node); + return $carry; + }, []); + } + + /** + * @param NodeInterface[] $parentNodes + */ + public function preloadChildNodesForNodes(array $parentNodes): void + { + if (empty($parentNodes)) { + return; + } + + $workspace = $parentNodes[0]->getWorkspace(); + $context = $parentNodes[0]->getContext(); + $dimensions = $context->getDimensions(); + + $parentPaths = array_map(static function(NodeInterface $parentNode) { + return $parentNode->getPath(); + }, $parentNodes); + + // Query nodes and their variants from the database + $queryBuilder = $this->entityManager->createQueryBuilder(); + $workspaces = $this->collectWorkspaceAndAllBaseWorkspaces($workspace); + $workspacesNames = array_map(static function(Workspace $workspace) { return $workspace->getName(); }, $workspaces); + + // Filter by workspace and its parents + $queryBuilder->select('n') + ->from(NodeData::class, 'n') + ->where('n.workspace IN (:workspaces)') + ->andWhere('n.movedTo IS NULL') + ->andWhere('n.parentPath IN (:parentPaths)') + ->setParameter('workspaces', $workspacesNames) + ->setParameter('parentPaths', $parentPaths); + $query = $queryBuilder->getQuery(); + $nodeDataWithVariants = $query->getResult(); + + // Remove node duplicates + $reducedNodeData = $this->reduceNodeVariantsByWorkspacesAndDimensions( + $nodeDataWithVariants, + $workspaces, + $dimensions + ); + + // Convert nodedata objects to nodes and group them by parent path + $childNodesByParentPath = array_reduce($reducedNodeData, function (array $carry, NodeData $nodeData) use ($context) { + $node = $this->nodeFactory->createFromNodeData($nodeData, $context); + if ($node !== null) { + if (!isset($carry[$node->getParentPath()])) { + $carry[$node->getParentPath()] = [$node]; + } else { + $carry[$node->getParentPath()][] = $node; + } + } + return $carry; + }, []); + + foreach ($childNodesByParentPath as $parentPath => $childNodes) { + usort($childNodes, static function(NodeInterface $a, NodeInterface $b) { + return $a->getIndex() <=> $b->getIndex(); + }); + $context->getFirstLevelNodeCache()->setChildNodesByPathAndNodeTypeFilter( + $parentPath, '!' . + $this->ignoredNodeTypeRole, + $childNodes + ); + } + } + + /** + * Given an array with duplicate nodes (from different workspaces and dimensions) those are reduced to uniqueness (by node identifier) + * Copied from Neos\ContentRepository\Domain\Repository\NodeDataRepository + * + * @param NodeData[] $nodes NodeData result with multiple and duplicate identifiers (different nodes and redundant results for node variants with different dimensions) + * @param Workspace[] $workspaces + * @param array $dimensions + * @return NodeData[] Array of unique node results indexed by identifier + */ + protected function reduceNodeVariantsByWorkspacesAndDimensions(array $nodes, array $workspaces, array $dimensions): array + { + $reducedNodes = []; + + $minimalDimensionPositionsByIdentifier = []; + + $workspaceNames = array_map(static fn (Workspace $workspace) => $workspace->getName(), $workspaces); + + foreach ($nodes as $node) { + $nodeDimensions = $node->getDimensionValues(); + + // Find the position of the workspace, a smaller value means more priority + $workspacePosition = array_search($node->getWorkspace()->getName(), $workspaceNames); + if ($workspacePosition === false) { + throw new \Exception(sprintf( + 'Node workspace "%s" not found in allowed workspaces (%s), this could result from a detached workspace entity in the context.', + $node->getWorkspace()->getName(), + implode(', ', $workspaceNames) + ), 1718740117); + } + + // Find positions in dimensions, add workspace in front for highest priority + $dimensionPositions = []; + + // Special case for no dimensions + if ($dimensions === []) { + // We can just decide if the given node has no dimensions. + $dimensionPositions[] = ($nodeDimensions === []) ? 0 : 1; + } + + foreach ($dimensions as $dimensionName => $dimensionValues) { + if (isset($nodeDimensions[$dimensionName])) { + foreach ($nodeDimensions[$dimensionName] as $nodeDimensionValue) { + $position = array_search($nodeDimensionValue, $dimensionValues); + if ($position === false) { + $position = PHP_INT_MAX; + } + $dimensionPositions[$dimensionName] = isset($dimensionPositions[$dimensionName]) ? min( + $dimensionPositions[$dimensionName], + $position + ) : $position; + } + } else { + $dimensionPositions[$dimensionName] = isset($dimensionPositions[$dimensionName]) ? min( + $dimensionPositions[$dimensionName], + PHP_INT_MAX + ) : PHP_INT_MAX; + } + } + $dimensionPositions[] = $workspacePosition; + + $identifier = $node->getIdentifier(); + // Yes, it seems to work comparing arrays that way! + if (!isset($minimalDimensionPositionsByIdentifier[$identifier]) || $dimensionPositions < $minimalDimensionPositionsByIdentifier[$identifier]) { + $reducedNodes[$identifier] = $node; + $minimalDimensionPositionsByIdentifier[$identifier] = $dimensionPositions; + } + } + + return $reducedNodes; + } + + /** + * @return Workspace[] + */ + protected function collectWorkspaceAndAllBaseWorkspaces(Workspace $workspace): array + { + $workspaces = []; + while ($workspace !== null) { + $workspaces[] = $workspace; + $workspace = $workspace->getBaseWorkspace(); + } + return $workspaces; } /** diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index a120ba48f6..f69c2342d3 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -532,28 +532,39 @@ public function flowQueryAction(array $chain): string $createContext = array_shift($chain); $finisher = array_pop($chain); - $flowQuery = new FlowQuery(array_map( - function ($envelope) { - return $this->nodeService->getNodeFromContextPath($envelope['$node']); - }, - $createContext['payload'] - )); + $nodeContextPaths = array_unique(array_column($createContext['payload'], '$node')); + $nodes = $this->nodeService->getNodesFromContextPaths($nodeContextPaths); + + $flowQuery = new FlowQuery($nodes); foreach ($chain as $operation) { $flowQuery = call_user_func_array([$flowQuery, $operation['type']], $operation['payload']); } + $nodes = array_filter($flowQuery->get()); + $this->nodeService->preloadChildNodesForNodes(array_values($nodes)); + $nodeInfoHelper = new NodeInfoHelper(); $result = []; switch ($finisher['type']) { case 'get': - $result = $nodeInfoHelper->renderNodes(array_filter($flowQuery->get()), $this->getControllerContext()); + $result = $nodeInfoHelper->renderNodes( + $nodes, + $this->getControllerContext() + ); break; case 'getForTree': - $result = $nodeInfoHelper->renderNodes(array_filter($flowQuery->get()), $this->getControllerContext(), true); + $result = $nodeInfoHelper->renderNodes( + $nodes, + $this->getControllerContext(), + true + ); break; case 'getForTreeWithParents': - $result = $nodeInfoHelper->renderNodesWithParents(array_filter($flowQuery->get()), $this->getControllerContext()); + $result = $nodeInfoHelper->renderNodesWithParents( + $nodes, + $this->getControllerContext() + ); break; } diff --git a/Classes/Domain/Service/UserLocaleService.php b/Classes/Domain/Service/UserLocaleService.php index b7dc351b24..e4451b4369 100644 --- a/Classes/Domain/Service/UserLocaleService.php +++ b/Classes/Domain/Service/UserLocaleService.php @@ -37,6 +37,13 @@ class UserLocaleService */ protected $rememberedContentLocale; + /** + * Remebered content locale for locale switching + * + * @var Locale + */ + protected $rememberedUserLocale; + /** * For serialization, we need to respect the UI locale, rather than the content locale * @@ -47,11 +54,15 @@ public function switchToUILocale($reset = false) if ($reset === true) { // Reset the locale $this->i18nService->getConfiguration()->setCurrentLocale($this->rememberedContentLocale); + } elseif ($this->rememberedUserLocale) { + // Restore the local + $this->i18nService->getConfiguration()->setCurrentLocale($this->rememberedUserLocale); } else { $this->rememberedContentLocale = $this->i18nService->getConfiguration()->getCurrentLocale(); $userLocalePreference = ($this->userService->getCurrentUser() ? $this->userService->getCurrentUser()->getPreferences()->getInterfaceLanguage() : null); $defaultLocale = $this->i18nService->getConfiguration()->getDefaultLocale(); $userLocale = $userLocalePreference ? new Locale($userLocalePreference) : $defaultLocale; + $this->rememberedUserLocale = $userLocale; $this->i18nService->getConfiguration()->setCurrentLocale($userLocale); } } diff --git a/Classes/FlowQueryOperations/NeosUiDefaultNodesOperation.php b/Classes/FlowQueryOperations/NeosUiDefaultNodesOperation.php index 141da9a32a..b198f312e4 100644 --- a/Classes/FlowQueryOperations/NeosUiDefaultNodesOperation.php +++ b/Classes/FlowQueryOperations/NeosUiDefaultNodesOperation.php @@ -72,8 +72,9 @@ public function canEvaluate($context) public function evaluate(FlowQuery $flowQuery, array $arguments) { /** @var TraversableNodeInterface $siteNode */ + $siteNode = $flowQuery->getContext()[0]; /** @var TraversableNodeInterface $documentNode */ - list($siteNode, $documentNode) = $flowQuery->getContext(); + $documentNode = $flowQuery->getContext()[1] ?? $siteNode; /** @var string[] $toggledNodes */ list($baseNodeType, $loadingDepth, $toggledNodes, $clipboardNodesContextPaths) = $arguments; diff --git a/Classes/Fusion/Helper/NodeInfoHelper.php b/Classes/Fusion/Helper/NodeInfoHelper.php index 64d2cda626..87a10970a5 100644 --- a/Classes/Fusion/Helper/NodeInfoHelper.php +++ b/Classes/Fusion/Helper/NodeInfoHelper.php @@ -116,7 +116,7 @@ public function renderNode(NodeInterface $node, ControllerContext $controllerCon /** * @param NodeInterface $node * @param ControllerContext|null $controllerContext - * @param string $nodeTypeFilterOverride + * @param string|null $nodeTypeFilterOverride * @return array|null */ public function renderNodeWithMinimalPropertiesAndChildrenInformation(NodeInterface $node, ControllerContext $controllerContext = null, string $nodeTypeFilterOverride = null) @@ -137,15 +137,9 @@ public function renderNodeWithMinimalPropertiesAndChildrenInformation(NodeInterf if ($controllerContext !== null) { $nodeInfo = array_merge($nodeInfo, $this->getUriInformation($node, $controllerContext)); - if ($controllerContext->getRequest()->hasArgument('presetBaseNodeType')) { - $presetBaseNodeType = $controllerContext->getRequest()->getArgument('presetBaseNodeType'); - } } - $baseNodeType = $nodeTypeFilterOverride ? $nodeTypeFilterOverride : (isset($presetBaseNodeType) ? $presetBaseNodeType : $this->defaultBaseNodeType); - $nodeTypeFilter = $this->buildNodeTypeFilterString($this->nodeTypeStringsToList($baseNodeType), $this->nodeTypeStringsToList($this->ignoredNodeTypeRole)); - - $nodeInfo['children'] = $this->renderChildrenInformation($node, $nodeTypeFilter); + $nodeInfo['children'] = $this->renderChildrenInformation($node); $this->userLocaleService->switchToUILocale(true); @@ -155,7 +149,7 @@ public function renderNodeWithMinimalPropertiesAndChildrenInformation(NodeInterf /** * @param NodeInterface $node * @param ControllerContext|null $controllerContext - * @param string $nodeTypeFilterOverride + * @param string|null $nodeTypeFilterOverride * @return array|null */ public function renderNodeWithPropertiesAndChildrenInformation(NodeInterface $node, ControllerContext $controllerContext = null, string $nodeTypeFilterOverride = null) @@ -172,13 +166,9 @@ public function renderNodeWithPropertiesAndChildrenInformation(NodeInterface $no if ($controllerContext !== null) { $nodeInfo = array_merge($nodeInfo, $this->getUriInformation($node, $controllerContext)); - if ($controllerContext->getRequest()->hasArgument('presetBaseNodeType')) { - $presetBaseNodeType = $controllerContext->getRequest()->getArgument('presetBaseNodeType'); - } } - $baseNodeType = $nodeTypeFilterOverride ? $nodeTypeFilterOverride : (isset($presetBaseNodeType) ? $presetBaseNodeType : $this->defaultBaseNodeType); - $nodeInfo['children'] = $this->renderChildrenInformation($node, $baseNodeType); + $nodeInfo['children'] = $this->renderChildrenInformation($node); $this->userLocaleService->switchToUILocale(true); @@ -234,26 +224,17 @@ protected function getBasicNodeInformation(NodeInterface $node): array /** * Get information for all children of the given parent node. - * - * @param NodeInterface $node - * @param string $nodeTypeFilterString - * @return array */ - protected function renderChildrenInformation(NodeInterface $node, string $nodeTypeFilterString): array + protected function renderChildrenInformation(NodeInterface $node): array { - $documentChildNodes = $node->getChildNodes($nodeTypeFilterString); - // child nodes for content tree, must not include those nodes filtered out by `baseNodeType` - $contentChildNodes = $node->getChildNodes($this->buildContentChildNodeFilterString()); - $childNodes = array_merge($documentChildNodes, $contentChildNodes); + $childNodes = $node->getChildNodes($this->buildNodeTypeFilterString([], [$this->ignoredNodeTypeRole])); - $mapper = function (NodeInterface $childNode) { + return array_map(static function (NodeInterface $childNode) { return [ 'contextPath' => $childNode->getContextPath(), - 'nodeType' => $childNode->getNodeType()->getName() // TODO: DUPLICATED; should NOT be needed!!! + 'nodeType' => $childNode->getNodeType()->getName(), ]; - }; - - return array_map($mapper, $childNodes); + }, $childNodes); } /** diff --git a/Resources/Private/Translations/nl/Main.xlf b/Resources/Private/Translations/nl/Main.xlf index 8e8f595ad6..04c2d6dbcb 100644 --- a/Resources/Private/Translations/nl/Main.xlf +++ b/Resources/Private/Translations/nl/Main.xlf @@ -505,7 +505,7 @@ Copy node type to clipboard - Kopieer node type naar klembord + Kopieer node type naar klembord diff --git a/packages/neos-ui-guest-frame/src/initializeGuestFrame.js b/packages/neos-ui-guest-frame/src/initializeGuestFrame.js index 0fa946f957..62e3f302b0 100644 --- a/packages/neos-ui-guest-frame/src/initializeGuestFrame.js +++ b/packages/neos-ui-guest-frame/src/initializeGuestFrame.js @@ -1,21 +1,22 @@ -import {takeEvery, put, select} from 'redux-saga/effects'; +import {put, select, takeEvery} from 'redux-saga/effects'; import {$get} from 'plow-js'; -import {selectors, actions, actionTypes} from '@neos-project/neos-ui-redux-store'; +import {actions, actionTypes, selectors} from '@neos-project/neos-ui-redux-store'; import {requestIdleCallback} from '@neos-project/utils-helpers'; import initializeContentDomNode from './initializeContentDomNode'; import { - getGuestFrameWindow, - getGuestFrameDocument, + dispatchCustomEvent, findAllNodesInGuestFrame, findInGuestFrame, findNodeInGuestFrame, - dispatchCustomEvent + getGuestFrameDocument, + getGuestFrameWindow } from './dom'; import style from './style.module.css'; import {SelectionModeTypes} from '@neos-project/neos-ts-interfaces'; +import backend from '@neos-project/neos-ui-backend-connector'; // // Get all parent elements of the event target. @@ -60,13 +61,45 @@ export default ({globalRegistry, store}) => function * initializeGuestFrame() { return; } - const nodes = Object.assign({}, guestFrameWindow['@Neos.Neos.Ui:Nodes'], { - [documentInformation.metaData.documentNode]: documentInformation.metaData.documentNodeSerialization + // Load legacy node data scripts from guest frame - remove with Neos 9.0 + const legacyNodeData = guestFrameWindow['@Neos.Neos.Ui:Nodes'] || {}; + + // Load all nodedata for nodes in the guest frame and filter duplicates + const {q} = yield backend.get(); + const nodeContextPathsInGuestFrame = findAllNodesInGuestFrame().map(node => node.getAttribute('data-__neos-node-contextpath')); + + // Filter nodes that are already present in the redux store and duplicates + const nodesByContextPath = store.getState().cr.nodes.byContextPath; + const nodesAlreadyPresentInStore = {}; + const notFullyLoadedNodeContextPaths = [...new Set(nodeContextPathsInGuestFrame)].filter((contextPath) => { + const node = nodesByContextPath[contextPath]; + const nodeIsLoaded = node !== undefined && node.isFullyLoaded; + if (nodeIsLoaded){ + nodesAlreadyPresentInStore[contextPath] = node; + return false; + } + return true; }); + // Load remaining list of not fully loaded nodes from the backend if there are any + const fullyLoadedNodesFromContent = notFullyLoadedNodeContextPaths.length > 0 ? (yield q(notFullyLoadedNodeContextPaths).get()).reduce((nodes, node) => { + nodes[node.contextPath] = node; + return nodes; + }, {}) : []; + + const nodes = Object.assign( + {}, + legacyNodeData, // Merge legacy node data from the guest frame - remove with Neos 9.0 + nodesAlreadyPresentInStore, + fullyLoadedNodesFromContent, + { + [documentInformation.metaData.documentNode]: documentInformation.metaData.documentNodeSerialization + } + ); + yield put(actions.CR.Nodes.merge(nodes)); - // Remove the inline scripts after initialization + // Remove the legacy inline scripts after initialization - remove with Neos 9.0 Array.prototype.forEach.call(guestFrameWindow.document.querySelectorAll('script[data-neos-nodedata]'), element => element.parentElement.removeChild(element)); const state = store.getState();