Sections
Sections Plugin
Das Plugin ist kein klassisches Plugin, welches man auf einer Seite plazieren kann, sondern es steuert nur Resourcen und Typoscript bei. Dadurch ist aber eine bessere Strukturierung und Wiederverwendbarkeit gegeben.
Im Prinzip ist es eine Art Sitemap für die aktuelle Seite, ich habe damit ein OnePage Layout realisiert.
Meine Sections Plugin bestehen aus
- Mehreren Elementen vom Typ Section
- Jede Section sollte einen je ein SectionHeader enthalten an erster Stelle
- Ein Container vom Typ Sections der die Elemente vom Typ Section beinhaltet
- Einem SectionMenu das alle SectionHeader anzeigt als Navigation
Plugin anlegen
Zum Anlegen folgendes:
./flow kickstart:package RSYS.Plugin.Sections
Dann habe ich das Manifest composer.json editiert
{
"name": "rsys/plugin-sections",
"description": "Sections plugin for TYPO3 Neos",
"type":"typo3-flow-plugin",
"license": "GPL-3.0+",
"authors": [
{
"name": "Erwin Knoll",
"email": "typo3coding@rootsystem.de"
}
],
"require": {
"typo3/flow":"*",
"typo3/neos":"*"
},
"autoload": {
"psr-0": {
"RSYS\\Plugin\\Sections": "Classes"
}
}
}
NodeTypes
NodeTypes
Dann anlegen von Configuration/NodeTypes.yaml:
##
# A custom "Menu" NodeType for Sections
#
'RSYS.Plugin.Sections:SectionMenu':
superTypes: ['TYPO3.Neos:Content']
ui:
label: 'Section menu'
icon: 'icon-file-text'
inspector:
groups:
general:
label: 'Eigenschaften'
position: 1
properties:
title:
type: string
ui:
label: 'Title'
inspector:
group: 'general'
height:
type: integer
defaultValue: '200'
ui:
label: 'Height'
inspector:
group: 'general'
backgroundImage:
type: TYPO3\Media\Domain\Model\ImageVariant
ui:
label: 'Image'
reloadIfChanged: TRUE
inspector:
group: 'general'
##
# Section
#
'RSYS.Plugin.Sections:Section':
superTypes: ['TYPO3.Neos:ContentCollection']
ui:
label: 'Section'
inspector:
groups:
document:
label: 'Section'
position: 1
properties:
caption:
type: string
ui:
label: 'Caption'
reloadIfChanged: TRUE
inspector:
group: 'document'
##
# Section Collection
#
'RSYS.Plugin.Sections:Sections':
superTypes: ['TYPO3.Neos.NodeTypes:Column']
ui:
label: 'Sections'
inspector:
groups:
document:
label: 'Document'
position: 1
properties:
title:
type: string
ui:
label: 'Title'
reloadIfChanged: TRUE
inspector:
group: 'document'
childNodes:
column0:
type: 'RSYS.Plugin.Sections:Section'
column1:
type: 'RSYS.Plugin.Sections:Section'
column2:
type: 'RSYS.Plugin.Sections:Section'
column3:
type: 'RSYS.Plugin.Sections:Section'
##
# Section Header
#
'RSYS.Plugin.Sections:SectionHeader':
superTypes: ['TYPO3.Neos:Content']
ui:
label: 'Section Header'
icon: 'icon-file-text'
inspector:
groups:
general:
label: 'Eigenschaften'
position: 1
properties:
title:
type: string
defaultValue: '<h1>Enter headline here</h1>'
ui:
inlineEditable: TRUE
aloha:
'format':
'sub': TRUE
'sup': TRUE
'p': TRUE
'h1': TRUE
'h2': TRUE
'h3': TRUE
'removeFormat': TRUE
'link':
'a': TRUE
name:
type: string
defaultValue: 'name'
ui:
label: 'Name'
inspector:
group: 'general'
height:
type: integer
defaultValue: 287
ui:
label: 'Height'
inspector:
group: 'general'
texttop:
type: string
defaultValue: 'margin-0'
ui:
label: 'Text Top'
reloadIfChanged: TRUE
inspector:
group: 'general'
editor: 'TYPO3.Neos/Inspector/Editors/SelectBoxEditor'
editorOptions:
placeholder: 'Default'
values:
'margin-0':
label: 'Keiner'
'margin-1':
label: 'Abstand 1'
'margin-2':
label: 'Abstand 2'
'margin-3':
label: 'Abstand 3'
'margin-4':
label: 'Abstand 4'
'margin-5':
label: 'Abstand 5'
imagetop:
type: integer
defaultValue: -280
ui:
label: 'Image Top'
reloadIfChanged: TRUE
inspector:
group: 'general'
backgroundImage:
type: TYPO3\Media\Domain\Model\ImageVariant
ui:
label: 'Image'
reloadIfChanged: TRUE
inspector:
group: 'general'
Typoscript
Resources/Private/TypoScripts/Library/Root.ts2
include: resource://RSYS.Plugin.Sections/Private/TypoScripts/Library/NodeTypes.ts2
Resources/Private/TypoScripts/Library/NodeTypes.ts2
#
# A Section is a Content Collection
#
prototype(RSYS.Plugin.Sections:Section) < prototype(TYPO3.Neos.NodeTypes:MultiColumnItem) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/Section.html'
sectiontitle = ${q(node).property('sectiontitle')}
caption = ${q(node).property('caption')}
attributes = TYPO3.TypoScript:Attributes {
class = 'section'
}
}
#
# A Section Header will be schown in the SectionMenu
#
prototype(RSYS.Plugin.Sections:SectionHeader) < prototype(TYPO3.Neos:Content) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/SectionHeader.html'
height = ${q(node).property('height')}
imageleft = ${q(node).property('imageleft')}
imagetop = ${q(node).property('imagetop')}
textleft = ${q(node).property('textleft')}
backgroundImage = TYPO3.TypoScript.TypoScriptObjects:ValueImplementation {
@class = 'TYPO3\\TypoScript\\TypoScriptObjects\\ValueImplementation'
value = ${q(node).property('backgroundImage')}
}
}
#
# Sections is the container for serveral Section elements
#
prototype(RSYS.Plugin.Sections:Sections) < prototype(TYPO3.Neos.NodeTypes:MultiColumn) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/Sections.html'
caption = ${q(node).property('caption')}
title = ${q(node).property('title')}
attributes = TYPO3.TypoScript:Attributes {
class = 'fullwidth-container'
}
columns = RSYS.Plugin.Sections:Section {
collection = ${q(node).children('[instanceof RSYS.Plugin.Sections:Section]')}
itemRenderer = RSYS.Plugin.Sections:Section
itemName = 'node'
}
}
#
# SectionMenu ist the navigation/menu
#
prototype(RSYS.Plugin.Sections:SectionMenu) < prototype(TYPO3.Neos:Content) {
attributes.class = 'section-menu'
height = ${q(node).property('height')}
items = ${q(node).parent().children('[instanceof RSYS.Plugin.Sections:Sections]').children('[instanceof RSYS.Plugin.Sections:Section]').children('[instanceof RSYS.Plugin.Sections:SectionHeader]')}
}
Fluid Templates
Templates/NodeTypes/Section.html
{namespace ts=TYPO3\TypoScript\ViewHelpers}
<div{attributes -> f:format.raw()}>
<ts:render path="columnContent" />
</div>
Templates/NodeTypes/SectionHeader.html
{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<f:if condition="{backgroundImage}">
<f:then>
<div class="section-header" style="background: url(/_Resources/Static/Packages/RSYS.DefaultSite/Images/bg-seil.png) 0px {imagetop}px repeat-x;">
</f:then>
<f:else>
<div class="section-header">
</f:else>
</f:if>
<f:if condition="{backgroundImage}">
<f:then>
<div id="{neos:contentElement.editable(property: 'name') -> f:format.stripTags()}" class="container" style="background: url({media:uri.image(image:backgroundImage)}) 0px {imagetop}px no-repeat; ">
</f:then>
<f:else>
<div id="{neos:contentElement.editable(property: 'name') -> f:format.stripTags()}" class="container">
</f:else>
</f:if>
<div class="row">
<div><a href="#top" class="linktotop pull-right"><img src="/_Resources/Static/Packages/RSYS.DefaultSite/Images/linktotop.png" alt="Zum Seitenanfang" title="Zum Seitenanfang" /></a></div>
</div>
<div class="row">
<div class="col-sm-4 " style="height: {height}px;">
</div>
<div class="col-sm-8 section-header-text {texttop}">
{neos:contentElement.editable(property: 'title')}
</div>
</div>
</div>
</div>
Templates/NodeTypes/Sections.html
{namespace ts=TYPO3\TypoScript\ViewHelpers}
<div{attributes -> f:format.raw()}>
<ts:render path="columns" />
</div>
Templates/NodeTypes/SectionMenu.html
{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<div class="section-menu">
<f:if condition="{backgroundImage}">
<f:then>
<div class="container" style="background: url({media:uri.image(image:backgroundImage)}) 0px -280px no-repeat;">
</f:then>
<f:else>
<div class="container">
</f:else>
</f:if>
<div class="col-sm-4 " style="height: {height}px;" >
</div>
<div class="col-sm-8">
<ul class="" >
<f:for each="{items}" as="item">
<li class="{item.state} ">
<div class="section-menu-item {item.properties.name -> f:format.stripTags()}"> <a href="#{item.properties.name -> f:format.stripTags()}">{item.properties.title -> f:format.stripTags()}</a></div>
</li>
</f:for>
</ul>
</div>
</div>
</div>
Integration
Im Root.ts2 einfügen:
include: resource://RSYS.Plugin.Sections/Private/TypoScripts/Library/Root.ts2
Inhalte dann wie folgt anlegen:
- SectionMenu
- Sections
- Section
- Section Header
- Content 1
- Content 2
- ...
- Section
- Section Header
- Content 1
- Content 2
- ...
Typoscript
Typoscript
Resources/Private/TypoScripts/Library/Root.ts2
include: resource://RSYS.Plugin.Sections/Private/TypoScripts/Library/NodeTypes.ts2
Resources/Private/TypoScripts/Library/NodeTypes.ts2
#
# A Section is a Content Collection
#
prototype(RSYS.Plugin.Sections:Section) < prototype(TYPO3.Neos.NodeTypes:MultiColumnItem) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/Section.html'
sectiontitle = ${q(node).property('sectiontitle')}
caption = ${q(node).property('caption')}
attributes = TYPO3.TypoScript:Attributes {
class = 'section'
}
}
#
# A Section Header will be schown in the SectionMenu
#
prototype(RSYS.Plugin.Sections:SectionHeader) < prototype(TYPO3.Neos:Content) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/SectionHeader.html'
height = ${q(node).property('height')}
imageleft = ${q(node).property('imageleft')}
imagetop = ${q(node).property('imagetop')}
textleft = ${q(node).property('textleft')}
backgroundImage = TYPO3.TypoScript.TypoScriptObjects:ValueImplementation {
@class = 'TYPO3\\TypoScript\\TypoScriptObjects\\ValueImplementation'
value = ${q(node).property('backgroundImage')}
}
}
#
# Sections is the container for serveral Section elements
#
prototype(RSYS.Plugin.Sections:Sections) < prototype(TYPO3.Neos.NodeTypes:MultiColumn) {
templatePath = 'resource://RSYS.Plugin.Sections/Private/Templates/NodeTypes/Sections.html'
caption = ${q(node).property('caption')}
title = ${q(node).property('title')}
attributes = TYPO3.TypoScript:Attributes {
class = 'fullwidth-container'
}
columns = RSYS.Plugin.Sections:Section {
collection = ${q(node).children('[instanceof RSYS.Plugin.Sections:Section]')}
itemRenderer = RSYS.Plugin.Sections:Section
itemName = 'node'
}
}
#
# SectionMenu ist the navigation/menu
#
prototype(RSYS.Plugin.Sections:SectionMenu) < prototype(TYPO3.Neos:Content) {
attributes.class = 'section-menu'
height = ${q(node).property('height')}
items = ${q(node).parent().children('[instanceof RSYS.Plugin.Sections:Sections]').children('[instanceof RSYS.Plugin.Sections:Section]').children('[instanceof RSYS.Plugin.Sections:SectionHeader]')}
}
Fluid Templates
Fluid Templates
Templates/NodeTypes/Section.html
{namespace ts=TYPO3\TypoScript\ViewHelpers}
<div{attributes -> f:format.raw()}>
<ts:render path="columnContent" />
</div>
Templates/NodeTypes/SectionHeader.html
{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<f:if condition="{backgroundImage}">
<f:then>
<div class="section-header" style="background: url(/_Resources/Static/Packages/RSYS.DefaultSite/Images/bg-seil.png) 0px {imagetop}px repeat-x;">
</f:then>
<f:else>
<div class="section-header">
</f:else>
</f:if>
<f:if condition="{backgroundImage}">
<f:then>
<div id="{neos:contentElement.editable(property: 'name') -> f:format.stripTags()}" class="container" style="background: url({media:uri.image(image:backgroundImage)}) 0px {imagetop}px no-repeat; ">
</f:then>
<f:else>
<div id="{neos:contentElement.editable(property: 'name') -> f:format.stripTags()}" class="container">
</f:else>
</f:if>
<div class="row">
<div><a href="#top" class="linktotop pull-right"><img src="/_Resources/Static/Packages/RSYS.DefaultSite/Images/linktotop.png" alt="Zum Seitenanfang" title="Zum Seitenanfang" /></a></div>
</div>
<div class="row">
<div class="col-sm-4 " style="height: {height}px;">
</div>
<div class="col-sm-8 section-header-text {texttop}">
{neos:contentElement.editable(property: 'title')}
</div>
</div>
</div>
</div>
Templates/NodeTypes/Sections.html
{namespace ts=TYPO3\TypoScript\ViewHelpers}
<div{attributes -> f:format.raw()}>
<ts:render path="columns" />
</div>
Templates/NodeTypes/SectionMenu.html
{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<div class="section-menu">
<f:if condition="{backgroundImage}">
<f:then>
<div class="container" style="background: url({media:uri.image(image:backgroundImage)}) 0px -280px no-repeat;">
</f:then>
<f:else>
<div class="container">
</f:else>
</f:if>
<div class="col-sm-4 " style="height: {height}px;" >
</div>
<div class="col-sm-8">
<ul class="" >
<f:for each="{items}" as="item">
<li class="{item.state} ">
<div class="section-menu-item {item.properties.name -> f:format.stripTags()}"> <a href="#{item.properties.name -> f:format.stripTags()}">{item.properties.title -> f:format.stripTags()}</a></div>
</li>
</f:for>
</ul>
</div>
</div>
</div>
Integration
Integration
Im Root.ts2 einfügen:
include: resource://RSYS.Plugin.Sections/Private/TypoScripts/Library/Root.ts2
Inhalte dann wie folgt anlegen:
- SectionMenu
- Sections
- Section
- Section Header
- Content 1
- Content 2
- ...
- Section
- Section Header
- Content 1
- Content 2
- ...