Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Add fusion-prototypes Component, Editable, ContentComponent and Augmenter #1752

Merged
merged 9 commits into from
Dec 5, 2017
63 changes: 63 additions & 0 deletions Neos.Fusion/Classes/FusionObjects/ComponentImplementation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
namespace Neos\Fusion\FusionObjects;

/*
* This file is part of the Neos.Fusion package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\Flow\Annotations as Flow;
use Neos\Fusion\FusionObjects\ArrayImplementation;

/**
* A Fusion Component-Object
*
* All properties except ``renderer`` are pushed into a context variable ``props``
* afterwards the ``renderer`` is evaluated
*
* //fusionPath renderer The variable to display a dump of.
* //fusionPath * generic Fusion values that will be added to the ``props`` object in the context
* @api
*/
class ComponentImplementation extends ArrayImplementation
{
/**
* Properties that are ignored and added to the props
*
* @var array
*/
protected $ignoreProperties = ['__meta', 'renderer'];

/**
* Evaluate the fusion-keys and transfer the result into the context as ``props``
* afterwards evaluate the ``renderer`` with this context
*
* @return void|string
*/
public function evaluate()
{
$sortedChildFusionKeys = $this->sortNestedFusionKeys();

$props = [];
foreach ($sortedChildFusionKeys as $key) {
try {
$props[$key] = $this->fusionValue($key);
} catch (\Exception $e) {
$props[$key] = $this->runtime->handleRenderingException($this->path . '/' . $key, $e);
}
}

$context = $this->runtime->getCurrentContext();
$context['props'] = $props;
$this->runtime->pushContextArray($context);
$result = $this->runtime->render($this->path . '/renderer');
$this->runtime->popContext();

return $result;
}
}
2 changes: 2 additions & 0 deletions Neos.Fusion/Resources/Private/Fusion/Root.fusion
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ prototype(Neos.Fusion:Matcher).@class = 'Neos\\Fusion\\FusionObjects\\MatcherImp
prototype(Neos.Fusion:Renderer).@class = 'Neos\\Fusion\\FusionObjects\\RendererImplementation'
prototype(Neos.Fusion:Value).@class = 'Neos\\Fusion\\FusionObjects\\ValueImplementation'
prototype(Neos.Fusion:Debug).@class = 'Neos\\Fusion\\FusionObjects\\DebugImplementation'
prototype(Neos.Fusion:Component).@class = 'Neos\\Fusion\\FusionObjects\\ComponentImplementation'

prototype(Neos.Fusion:Collection) {
@class = 'Neos\\Fusion\\FusionObjects\\CollectionImplementation'
itemName = 'item'
Expand Down
59 changes: 59 additions & 0 deletions Neos.Fusion/Tests/Functional/FusionObjects/ComponentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
namespace Neos\Fusion\Tests\Functional\FusionObjects;

/*
* This file is part of the Neos.Fusion package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

/**
* Testcase for the Component Fusion object
*
*/
class ComponentTest extends AbstractFusionObjectTest
{
/**
* @test
*/
public function componentBasicRenderer()
{
$view = $this->buildView();
$view->setFusionPath('component/basicRenderer');
$this->assertEquals('Hello World', $view->render());
}

/**
* @test
*/
public function componentNestedRenderer()
{
$view = $this->buildView();
$view->setFusionPath('component/nestedRenderer');
$this->assertEquals('Hello World', $view->render());
}

/**
* @test
*/
public function componentStaticRenderer()
{
$view = $this->buildView();
$view->setFusionPath('component/staticRenderer');
$this->assertEquals('Hello World', $view->render());
}

/**
* @test
*/
public function componentSandboxRenderer()
{
$view = $this->buildView();
$view->setFusionPath('component/sandboxRenderer');
$this->assertEquals('Hello ', $view->render());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
prototype(Neos.Fusion:Component).@class = 'Neos\\Fusion\\FusionObjects\\ComponentImplementation'
prototype(Neos.Fusion:Value).@class = 'Neos\\Fusion\\FusionObjects\\ValueImplementation'
prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer'


prototype(Neos.Fusion:Sandbox) < prototype(Neos.Fusion:Component) {
hello = null
world = null

renderer = ${props.hello + ' ' + props.world}
}

component.basicRenderer = Neos.Fusion:Component {
hello = 'Hello'
world = 'World'

renderer = ${props.hello + ' ' + props.world}
}

component.nestedRenderer = Neos.Fusion:Component {
hello = 'Hello'
world = 'World'

renderer = Neos.Fusion:Value {
value = ${props.hello + ' ' + props.world}
}
}

component.staticRenderer = Neos.Fusion:Component {
renderer = 'Hello World'
}

component.sandboxRenderer = Neos.Fusion:Component {
hello = 'Hello'
world = 'World'

renderer = Neos.Fusion:Value {
value = Neos.Fusion:Sandbox {
hello = ${props.hello}
}
}
}
64 changes: 64 additions & 0 deletions Neos.Neos/Classes/Fusion/AugmenterImplementation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
namespace Neos\Neos\Fusion;

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\Flow\Annotations as Flow;
use Neos\Fusion\FusionObjects\ArrayImplementation;
use Neos\Neos\Service\HtmlAugmenter;

/**
* A Fusion Augmenter-Object
*
* The fusion object can be used to add html-attributes to the rendererd content
*
* @api
*/
class AugmenterImplementation extends ArrayImplementation
{

/**
* @var HtmlAugmenter
* @Flow\Inject
*/
protected $htmlAugmenter;

/**
* Properties that are ignored
*
* @var array
*/
protected $ignoreProperties = ['__meta', 'fallbackTagName', 'content'];

/**
* @return void|string
*/
public function evaluate()
{
$content = $this->fusionValue('content');
$fallbackTagName = $this->fusionValue('fallbackTagName');

$sortedChildFusionKeys = $this->sortNestedFusionKeys();

$attributes = [];
foreach ($sortedChildFusionKeys as $key) {
if ($fusionValue = $this->fusionValue($key)) {
$attributes[$key] = $fusionValue;
}
}

if ($attributes && is_array($attributes) && count($attributes) > 0) {
return $this->htmlAugmenter->addAttributes($content, $attributes, $fallbackTagName);
} else {
return $content;
}
}
}
114 changes: 114 additions & 0 deletions Neos.Neos/Documentation/References/NeosFusionReference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,42 @@ Example::
# the value of this object is the formatted debug output of all keys given to the object


.. _Neos_Fusion__Component:

Neos.Fusion:Component
---------------------

Create a component that adds all properties to the props context and afterward evaluates the renderer.

:renderer: (mixed, **required**) The value which gets rendered

Example::

prototype(Vendor.Site:Component) < prototype(Neos.Fusion:Component) {
title = 'Hello World'
titleTagName = 'h1'
description = 'Description of the Neos World'
bold = false

renderer = Neos.Fusion:Tag {
attributes.class = Neos.Fusion:RawArray {
component = 'component'
bold = ${props.bold ? 'component--bold' : false}
}
content = Neos.Fusion:Array {
headline = Neos.Fusion:Tag {
tagName = ${props.titleTagName}
content = ${props.title}
}

description = Neos.Fusion:Tag {
content = ${props.description}
}
}
}
}


.. _Neos_Fusion__Template:

Neos.Fusion:Template
Expand Down Expand Up @@ -614,6 +650,84 @@ Example::
# title = ${q(node).property('title')}
}


.. _Neos_Neos__ContentComponent:

ContentComponent
----------------

Base type to render component based content nodes, extends :ref:`Neos_Fusion__Component`.

:renderer: (mixed, **required**) The value which gets rendered


.. _Neos_Neos__Augmenter:

Augmenter
---------

The Augmenter component can be used as processor or as a standalone prototype

:content: (string) The content that shall be augmented
:fallbackTagName: (string) If more than one tag is found the content is wrapped in the fallback tag before augmentation which has `div` as default
:[key]: All other fusion properties are added to the html content as html attributes

Example as a standalone augmenter::

augmentedContent = Neos.Neos:Augmenter {

content = Neos.Fusion:Array {
title = Neos.Fusion:Tag {
@if.hasContent = ${this.content}
tagName = 'h2'
content = ${q(node).property('title')}
}
text = Neos.Fusion:Tag {
@if.hasContent = ${this.content}
tagName = 'p'
content = ${q(node).property('text')}
}
}

fallbackTagName = 'header'

class = 'header'
data-foo = 'bar'
}


Example as a processor augmenter::

augmentedContent = Neos.Fusion:Tag {
tagName = 'h2'
content = 'Hello World'
@process.augment = Neos.Neos:Augmenter {
class = 'header'
data-foo = 'bar'
}
}


.. _Neos_Neos__Editable:

Editable
--------

Create an editable tag for a property. In the frontend, only the content of the property gets rendered.

:node: (node) A node instance that should be used to read the property. Default to `${node}`
:property: (string) The name of the property which should be accessed
:block: (boolean) Decides if the editable tag should be a block element (`div`) or an inline element (`span`). Default to `true`


Example::

title = Neos.Neos:Editable {
property = 'title'
block = false
}


.. _Neos_Neos__Plugin:

Plugin
Expand Down
2 changes: 2 additions & 0 deletions Neos.Neos/Resources/Private/Fusion/DefaultFusion.fusion
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
include: Prototypes/ContentCase.fusion
include: Prototypes/Document.fusion
include: Prototypes/Content.fusion
include: Prototypes/ContentComponent.fusion
include: Prototypes/PrimaryContent.fusion
include: Prototypes/ContentCollection.fusion
include: Prototypes/Page.fusion
include: Prototypes/Shortcut.fusion
include: Prototypes/Augmenter.fusion
include: Prototypes/BreadcrumbMenu.fusion
include: Prototypes/DimensionsMenu.fusion
include: Prototypes/Menu.fusion
Expand Down
13 changes: 13 additions & 0 deletions Neos.Neos/Resources/Private/Fusion/Prototypes/Augmenter.fusion
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# The Augmenter-component can be used as processor or as a standalone prototype

prototype(Neos.Neos:Augmenter) < prototype(Neos.Fusion:Component) {
@class = 'Neos\\Neos\\Fusion\\AugmenterImplementation'

# If more than one tag is found the content is wrapped in the fallback tag before augmentation
fallbackTagName = 'div'

# The content that shall be augmented
content = ${value}

# All other fusion properties are added to the html content as html attributes
}