Generating nested lists - typo3

I'm pretty much new to typoscript. I know about wrapping but how do you generate well-formed nested lists?
Here is the code I'm using at the moment:
// Side menu with each li acting as a category
lib.subMenu.1 {
NO.allWrap=<li class="category">|</li>
// (...)
lib.subMenu {
2 < .1
// LI placed just underneath and wrapped inside a UL.
// Ideally the UL should be inside the LI described above.
2.wrap = <li><ul class="items">|</ul></li>

you need to use wrapItemAndSub for wrapping items
lib.subMenu = HMENU
lib.submenu {
1 = TMENU
1 {
wrap = <ul>|</ul>
NO.wrapItemAndSub = <li>|</li>
}
2 < .1
2.wrap = <ul class="level_2">|</ul>
}

Related

Typoscript HMENU: get level 1 title in level 2 navigation

I need to create a menu where, for mobile purposes, before all entries of level 2 there is the title of level 1. Example: my structure looks like this:
team
Max
Sepp
projects
project 1
project 2
now I want my navigation to look like this:
<ul>
<li>
<a>Team</a>
<div class="dropdown-menu">
<ul>
<li>Team</li>
<li><a>Max</a></li>
<li><a>Sepp</a></li>
</ul>
</div>
</li>
<li>
<a>Projects</a>
<div class="dropdown-menu">
<ul>
<li>Projects</li>
<li><a>Project 1</a></li>
<li><a>Project 2</a></li>
</ul>
</div>
</li>
</ul>
So I need in level 2 the title of level 1. how to I access field: nav_title for the parent element?
My typoscript looks like this:
temp.nav = HMENU
temp.nav {
1 = TMENU
1 {
expAll = 1
wrap = |
noBlur = 1
stdWrap.innerWrap.cObject = LOAD_REGISTER
stdWrap.innerWrap.cObject {
level1Title.field = nav_title//title
}
NO = 1
NO {
...
}
}
2 = TMENU
2 {
expAll = 1
stdWrap.dataWrap = <ul><li> {register:level1Title}</li>|</ul><a>Jetzt Mitglied werden</a></div>
noBlur = 1
NO = 1
NO {
...
}
}
}
I tried it with LOAD_REGISTER but that doesnt work. Any suggestions?
what you want is the default behaviour of TYPO3 menus. You just need to set the correct wrapping. Do the wrapping where it belongs:
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
expAll = 1
wrap = <ul>|</ul>
NO = 1
NO {
wrapItemAndSub = <li>|</li>
}
}
// as you have no specific wrapping all levels can be generated the same:
2 < .1
3 < .2
}
if you want specific wraps on each level you can adapt it after copying (in this example you can see where a wrapping is coming from)
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
wrap = <ul class="level1">|</ul>
NO = 1
NO {
wrapItemAndSub = <li class="lev1">|</li>
}
}
2 < .1
2 {
wrap = <ul class="level2">|</ul>
NO.wrapItemAndSub = <li class="lev2">|</li>
}
3 < .2
3 {
wrap = <ul class="level3">|</ul>
NO.wrapItemAndSub = <li class="lev3">|</li>
}
}
.
EDIT: after clarification of problem:
working with LOADREGISTER in menus would result in a mess as the menu items are not generated inline recursive.
If you want to repeat the menuitem you should generate it in place.
Therefore you need to split the clean wrappings and use soem enhanced menu magic.
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
wrap = <ul class="level1">|</ul>
NO = 1
NO.wrapItemAndSub = <li>|</li>
// only for menuitems which contains further pages:
IFSUB < .NO
IFSUB {
// beginning the part of the submenu
after.cObject = TEXT
after.cObject {
field = nav_title // title
wrap = <div class="dropdown-menu"><ul><li>|</li>
}
}
}
2 < .1
2 {
// no beginning in wrap needed as it is done at level 1
wrap = |</ul></div>
}
}
further levels need additional handling. e.g.: 2.IFSUB > and 3.wrap = <ul>|</ul>
Note: If you want a clean html with indentions you need to use .noTrimWrap and multi line values in typoscript.

TypoScript Menu with manual columns

I have a typical grid-based dropdown menu with predefined columns, as you find them in foundation, bootstrap etc.
Now I'd like to manually let the editor control which items go in which column – without having to hardwire too many pids or creating additional pagetree nodes (Pages like "Group for column 1") in the BE.
How do I do that with TypoScript?
The page type "Spacer" or "Separator" (doktype 199) is perfect for this:
It can be rendered as html content, using the SPC state. Editors can place it in their pagetree where they want to split up columns.
lib.main_nav_1 = HMENU
lib.main_nav_1 {
special = directory
special.value = {$pidEntryPoint}
wrap = <div class="columns small-12 medium-3"><ul>|</ul></div>
1 = TMENU
1 {
expAll = 1
NO {
text = nav_title // title
wrapItemAndSub=<li>|</li>
}
ACT < .NO
ACT {
wrapItemAndSub = <li class="active">|</li>
}
ACT = 1
CUR < .NO
CUR {
wrapItemAndSub = <li class="current">|</li>
}
CUR = 1
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = </ul></div><div class="columns small-12 medium-3">|<ul>
}
}
2 < .1
2 {
wrap = <ul>|</ul>
SPC = 0
}
}
}

TMENU - only mark current page as active, not parents

I have a menu currently looking like this. Not only the current active item is marked as active, but also its parents and all the way up. How can I make it so parents aren't marked?
Here's the menu typoscript.
lib.secondNavi = HMENU
lib.secondNavi.entryLevel=0
lib.secondNavi.1 = TMENU
lib.secondNavi.1 {
wrap = <ul id="secondNavi">|</ul>
expAll = 0
NO.allWrap = <li>|</li>
RO < .NO
RO = 1
CUR < .NO
CUR = 1
CUR.allWrap = <li class="active">|</li>
ACT < .CUR
}
lib.secondNavi.2 < lib.secondNavi.1
lib.secondNavi.2 {
wrap = <ul>|</ul>
}
lib.secondNavi.3 < lib.secondNavi.2
lib.secondNavi.3 {
wrap = <ul>|</ul>
}
Using Typo3 6.1.7.
Active (ACT) in TypoScript means current page AND each parent in the page tree.
Current page (CUR) is only the page that you are on (determined by its ID)
documentation
You are copying settings of CUR to ACT so you have mark the pages on rootline as well, just remove the ACT < .CUR line or on other levels empty it by: ACT >

Id counting in TYPO3 menu using register:count_MENUOBJ

I made the menu in TYPO3 for bootstrap framework. Everything working just fine, but I have problem with counting the id element using register:count_MENUOBJ. The whole menu is constructed from two parts - main menu and sub menu:
page = PAGE
page.10 = HMENU
page.10.special = directory
page.10.entryLevel = 0
page.10.maxItems = 6
page.10 {
1 = TMENU
1 {
wrap = <div class="row"><ul class="nav nav-tabs pull-right" id="myTab" role="tablist">|</ul></div>
noBlur = 1
expAll = 1
NO {
ATagTitle.field = title
wrapItemAndSub = <li class="dropdown">|</li>
stdWrap.htmlSpecialChars = 1
accessKey = 1
}
IFSUB < .NO
IFSUB = 1
IFSUB {
wrapItemAndSub = <li class="dropdown">|</li>
linkWrap= |
ATagParams = role="button" data-toggle="collapse" data-target="#item-{register:count_MENUOBJ}"
ATagParams.insertData = 1
ATagBeforeWrap = 1
stdWrap.htmlSpecialChars = 1
}
ACTIFSUB < .IFSUB
ACTIFSUB {
wrapItemAndSub = <li class="active dropdown">|</li>
}
ACT < .NO
ACT = 1
ACT {
wrapItemAndSub = <li class="active">|</li>
}
CURIFSUB < .IFSUB
CURIFSUB = 1
CURIFSUB {
wrapItemAndSub = <li class="active dropdown">|</li>
}
}
}
page.20 = HMENU
page.20.special = directory
page.20.entryLevel = 0
page.20.maxItems = 6
page.20 {
1 = TMENU
1 {
wrap = <div class="row"><div class="tab-content">|</div></div>
noBlur = 1
expAll = 1
NO.doNotShowLink = 1
}
# second level
2.maxItems = 5
2 = TMENU
2.stdWrap.wrap = <div class="tab-pane fade in active pull-right" id="item-{register:count_MENUOBJ}"><nav class="navbar navbar-default pull-right submenu" role="navigation"><ul class="nav navbar-nav in">|</ul></nav></div>
2.stdWrap.wrap.insertData = 1
2{
expAll = 1
NO{
ATagTitle.field = title
wrapItemAndSub = <li>|</li>
}
IFSUB = 1
IFSUB{
ATagTitle.field = title
wrapItemAndSub = <li>|</li>
}
}
}
In the first menu block links has the correct value: data-target="#item-1", data-target="#item-2" etc..
In the second block the all links are generated in this form: id="item-5" staring and ending on item-5
Any suggestions?
register:count_MENUOBJ is counting the menu-items in the context where it's used.
In the first menu it's used in the context of the main-items and therefore counting in the natural order of the menu-items like an index. This might be the reason that the function of register:count_MENUOBJ is still confusing, even usable in that context.
In the second menu register:count_MENUOBJ is used in the context of the sub-menu items and counting the sub-items on level 2. So if on level two are 3 sub-items the register is 3. If 5 sub-items it's 5. In this context register:count_MENUOBJ is not usable as index as the amount of sub-items never reflects the expected value according to the question.
Therefore to get unique id's it's common practice to use p{field:uid} for pages or for content-elements c{field:uid}.
Example:
...
NO.wrapItemAndSub = <li id="nav-main-p{field:uid}">|</li>
NO.wrapItemAndSub.insertData = 1
...
Another alternative is to use register:count_MENUOBJ in the second menu also on the first level. Question if the menu in the question would have the required properties then.
Use the MenuProcessor instead of HMENU. I always had problems with the custom rendering of HMENU and than i turned to MenuProcessor because the html markup may be created directly in fluid.
Typoscript:
page = PAGE
page.10 = FLUIDTEMPLATE
page.10 {
...
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
10 {
as = navigationMain
}
}
}
FLUID:
<f:for each="{navigationMain}" as="menuItem">
<!-- There you have access to menu items -->
</f:for>
Documentation: https://docs.typo3.org/typo3cms/SitePackageTutorial/MainMenuCreation/Index.html
In general #David already gave all relevant information.
For clarification and as hint for an easier implementation:
In your example you used the count register in page.20.2.stdWrap.wrap. this Wrap is executed in context of second level menu, but after the menu is allready generated, so it contains the number of elements in this menu level.
You need to use the count register in first level, and so it is a wrap to the second level you can use it in .1.IFSUB.wrapItemAndSub, as you have no content in first level it will be a wrap only for the second level menu.
And also mentioned from #David:
You also could use the uids from the pages itself.
Use it in page.10, and in page.20.2 you could use the field pid from any page on that level.
As you want to use it out of the context of a menuItem you might get the problem: there is no real field pid. Either you do the wrap on the first page/ menuItem (hint: optionsplit) or do it in the first level again.
(I doubt that for .1.stdWrap you are in the context of the first level page, so you could use field uid.)
you probably have to insert the following (not tested):
page.15 = RESTORE_REGISTER
just before page.20 = HMENU ... normally used in combination with LOAD_REGISTER but it looks as if your second HMENU has the count_MENUOBJ stuck at the last value of the first ...

Load register inside TMENU

In a TYPO3 HMENU, the second level TMENU should reproduce the abstract of the first level page.
I do manage to fill the register with a value and use it in the second level TMENU - but I am unable to load the field's content into the register.
So
field = abstract
as well as
value = {field:abstract}
value.insertData = 1
don't produce any output.
How can that register be filled with the parent page's abstract?
Here's the full code.
temp.main_nav = HMENU
temp.main_nav {
wrap = <nav id="cbp-hrmenu" class="clearfix cbp-hrmenu span12">|</nav>
entryLevel = 0
1 = TMENU
1 {
noBlur = 1
expAll = 1
wrap = <ul class="level1">|</ul>
NO {
wrapItemAndSub=<li>|</li>
before.cObject=LOAD_REGISTER
before.cObject{
parentAbstract.stdWrap.cObject=TEXT
parentAbstract.stdWrap.cObject{
field = abstract
#value = {field:abstract}
#value.insertData = 1
}
}
}
}
2 < .1
2.stdWrap.dataWrap = <div class="cbp-hrsub"><div class="cbp-hrsub-inner"><div>{register:parentAbstract}</div><div><ul class="level2">|</ul></div></div><!-- /cbp-hrsub-inner --></div><!-- /cbp-hrsub -->
}
PS: {levelfield} seems to be problematic inside a TMENU, that's why I switched to LOAD_REGISTER
Solved it.
The problem was in
2 < .1
The second TMENU inherited the load_register from the first one and kept filling it. That's why there was a wrong abstract (e.g. an empty one) in it.
Here's the working code:
temp.main_nav = HMENU
temp.main_nav {
wrap = <nav id="cbp-hrmenu" class="clearfix cbp-hrmenu span12">|</nav>
entryLevel = 0
1 = TMENU
1 {
noBlur = 1
expAll = 1
wrap = <ul class="level1">|</ul>
NO {
wrapItemAndSub=<li>|</li>
before.cObject=LOAD_REGISTER
before.cObject{
parentAbstract.cObject=TEXT
parentAbstract.cObject{
field = abstract
}
}
}
// EDIT: if you have additional states, don't forget to add the abstract too
ACT < .NO
ACT = 1
ACT {
wrapItemAndSub=<li class="dropdown active">|</li>
}
}
2 = TMENU
2 {
noBlur = 1
expAll = 1
stdWrap.dataWrap = <div class="cbp-hrsub"><div class="cbp-hrsub-inner"><div>{register:parentAbstract}</div><div><ul class="level2">|</ul></div></div><!-- /cbp-hrsub-inner --></div><!-- /cbp-hrsub -->
NO {
wrapItemAndSub=<li>|</li>
}
}
}