/** * @param string $html * @param array $attributes * @param string $fallbackTagName * @param string $expectedResult * @param array $exclusiveAttributes * @test * @dataProvider addAttributesDataProvider */ public function addAttributesTests($html, array $attributes, $fallbackTagName, $exclusiveAttributes, $expectedResult) { if ($fallbackTagName === null) { $fallbackTagName = 'div'; } $actualResult = $this->htmlAugmenter->addAttributes($html, $attributes, $fallbackTagName, $exclusiveAttributes); $this->assertSame($expectedResult, $actualResult); }
/** * Hooks into the editable viewhelper to render those attributes needed for the package's inline editing * * @Flow\Around("method(TYPO3\Neos\Service\ContentElementEditableService->wrapContentProperty())") * @param JoinPointInterface $joinPoint the join point * @return mixed */ public function editableElementAugmentation(JoinPointInterface $joinPoint) { if (!$this->session->isStarted() || !$this->session->getData('__neosEnabled__')) { return $joinPoint->getAdviceChain()->proceed($joinPoint); } $property = $joinPoint->getMethodArgument('property'); $node = $joinPoint->getMethodArgument('node'); $content = $joinPoint->getAdviceChain()->proceed($joinPoint); $attributes = ['data-__neos-property' => $property]; if ($node !== null) { $attributes += ['data-__neos-editable-node-contextpath' => $node->getContextPath()]; } return $this->htmlAugmenter->addAttributes($content, $attributes, 'span'); }
/** * Wrap the $content identified by $node with the needed markup for the backend. * * @param NodeInterface $node * @param string $property * @param string $content * @return string */ public function wrapContentProperty(NodeInterface $node, $property, $content) { /** @var $contentContext ContentContext */ $contentContext = $node->getContext(); if ($contentContext->getWorkspaceName() === 'live' || !$this->privilegeManager->isPrivilegeTargetGranted('TYPO3.Neos:Backend.GeneralAccess')) { return $content; } if (!$this->nodeAuthorizationService->isGrantedToEditNode($node)) { return $content; } $attributes = array(); $attributes['class'] = 'neos-inline-editable'; $attributes['property'] = 'typo3:' . $property; $attributes['data-neos-node-type'] = $node->getNodeType()->getName(); return $this->htmlAugmenter->addAttributes($content, $attributes, 'span'); }
/** * @test */ public function wrapContentPropertyDoesNotAddEditingMetaDataIfEditNodePrivilegeIsNotGranted() { $this->mockContentContext->expects($this->atLeastOnce())->method('getWorkspaceName')->will($this->returnValue('not-live')); $this->mockPrivilegeManager->expects($this->atLeastOnce())->method('isPrivilegeTargetGranted')->with('TYPO3.Neos:Backend.GeneralAccess')->will($this->returnValue(true)); $this->mockNodeAuthorizationService->expects($this->atLeastOnce())->method('isGrantedToEditNode')->will($this->returnValue(false)); $this->mockHtmlAugmenter->expects($this->never())->method('addAttributes'); $this->contentElementEditableService->wrapContentProperty($this->mockNode, 'someProperty', '<div>someRenderedPropertyValue</div>'); }
/** * @param NodeInterface $node * @param string $content * @param string $typoScriptPath * @return string */ public function wrapCurrentDocumentMetadata(NodeInterface $node, $content, $typoScriptPath) { if ($this->needsMetadata($node, true) === false) { return $content; } $attributes = []; $attributes['data-node-__typoscript-path'] = $typoScriptPath; $attributes = $this->addGenericEditingMetadata($attributes, $node); $attributes = $this->addNodePropertyAttributes($attributes, $node); $attributes = $this->addDocumentMetadata($attributes, $node); $attributes = $this->addCssClasses($attributes, $node, []); return $this->htmlAugmenter->addAttributes($content, $attributes, 'div', ['typeof']); }
/** * Wrap the $content identified by $node with the needed markup for the backend. * * @param NodeInterface $node * @param string $typoScriptPath * @param string $content * @param boolean $renderCurrentDocumentMetadata When this flag is set we will render the global metadata for the current document * @return string */ public function wrapContentObject(NodeInterface $node, $typoScriptPath, $content, $renderCurrentDocumentMetadata = false) { /** @var $contentContext ContentContext */ $contentContext = $node->getContext(); if ($contentContext->getWorkspaceName() === 'live' || !$this->privilegeManager->isPrivilegeTargetGranted('TYPO3.Neos:Backend.GeneralAccess')) { return $content; } $nodeType = $node->getNodeType(); $attributes = array(); $attributes['typeof'] = 'typo3:' . $nodeType->getName(); $attributes['about'] = $node->getContextPath(); $classNames = array(); if ($renderCurrentDocumentMetadata === true) { $attributes['data-neos-site-name'] = $contentContext->getCurrentSite()->getName(); $attributes['data-neos-site-node-context-path'] = $contentContext->getCurrentSiteNode()->getContextPath(); // Add the workspace of the TYPO3CR context to the attributes $attributes['data-neos-context-workspace-name'] = $contentContext->getWorkspaceName(); $attributes['data-neos-context-dimensions'] = json_encode($contentContext->getDimensions()); if (!$this->nodeAuthorizationService->isGrantedToEditNode($node)) { $attributes['data-node-__read-only'] = 'true'; $attributes['data-nodedatatype-__read-only'] = 'boolean'; } } else { if (!$this->nodeAuthorizationService->isGrantedToEditNode($node)) { return $content; } if ($node->isRemoved()) { $classNames[] = 'neos-contentelement-removed'; } if ($node->isHidden()) { $classNames[] = 'neos-contentelement-hidden'; } if ($nodeType->isOfType('TYPO3.Neos:ContentCollection')) { $attributes['rel'] = 'typo3:content-collection'; // This is needed since the backend relies on this class (should not be necessary) $classNames[] = 'neos-contentcollection'; } else { $classNames[] = 'neos-contentelement'; } $uiConfiguration = $nodeType->hasConfiguration('ui') ? $nodeType->getConfiguration('ui') : array(); if (isset($uiConfiguration['inlineEditable']) && $uiConfiguration['inlineEditable'] !== true || !isset($uiConfiguration['inlineEditable']) && !$this->hasInlineEditableProperties($node)) { $classNames[] = 'neos-not-inline-editable'; } $attributes['tabindex'] = 0; } if ($node instanceof Node && !$node->dimensionsAreMatchingTargetDimensionValues()) { $classNames[] = 'neos-contentelement-shine-through'; } if (count($classNames) > 0) { $attributes['class'] = implode(' ', $classNames); } // Add the actual workspace of the node, the node identifier and the TypoScript path to the attributes $attributes['data-node-_identifier'] = $node->getIdentifier(); $attributes['data-node-__workspace-name'] = $node->getWorkspace()->getName(); $attributes['data-node-__typoscript-path'] = $typoScriptPath; // these properties are needed together with the current NodeType to evaluate Node Type Constraints // TODO: this can probably be greatly cleaned up once we do not use CreateJS or VIE anymore. if ($node->getParent()) { $attributes['data-node-__parent-node-type'] = $node->getParent()->getNodeType()->getName(); } if ($node->isAutoCreated()) { $attributes['data-node-_name'] = $node->getName(); $attributes['data-node-_is-autocreated'] = 'true'; } if ($node->getParent() && $node->getParent()->isAutoCreated()) { $attributes['data-node-_parent-is-autocreated'] = 'true'; // we shall only add these properties if the parent is actually auto-created; as the Node-Type-Switcher in the UI relies on that. $attributes['data-node-__parent-node-name'] = $node->getParent()->getName(); $attributes['data-node-__grandparent-node-type'] = $node->getParent()->getParent()->getNodeType()->getName(); } $attributes = $this->addNodePropertyAttributes($node, $attributes); return $this->htmlAugmenter->addAttributes($content, $attributes, 'div', array('typeof')); }