Output a page tree
Page trees can be created in different ways:
Method | When to use it |
---|---|
Lazy-loading trees | You should almost always use this – it offers good performance and usability |
Render the page tree dynamically, based on the Confluence page hierarchy | This option is useful for generic themes that should work out of the box, and should be used if you need the tree unfolded at all times |
Include page content from a page that contains a (nested) list of links | Use this if you want to configure what is displayed by changing the macro settings in Confluence. This option offers more flexibility, but requires some more work (users need to create a page with a certain name that is included for the navigation) |
By hard-coding it into the template | Simple, but inflexible – not recommended in normal circumstances |
Lazy-loading tree
The lazy-loading tree method is recommended in most scenarios. It offers good performance, and the page tree also remembers which pages are collapsed as you navigate. It's the approach we use in the WebHelp theme that we ship with Scroll Viewport.
You can add a lazy loading tree in Scroll Viewport by adding a REST API that can be used by templates to load children of a specific page. In order to use the REST API, we provide the scrollTree jQuery plugin.
Add a lazy-loading tree using the scrollTree jQuery plugin
Download the scrollTree jQuery Plugin, add it to your theme and load it in the HTML head:
CODE<script src="${theme.baseUrl}/js/jquery.scroll-tree.js"></script>
Add an element where the page tree should be displayed:
CODE<ul class="nav sp-tree" data-viewport-id="$viewport.id" data-root="$tree.root.link" data-current="$page.link"> </ul>
Initialize the jQuery scrollTree plugin when the document is loaded:
CODE$(document).ready(function () { $('.sp-tree').scrollTree({ 'contextPath': '' // this should be adapted to the Confluence instance }); });
You have now added the lazy-loading tree to your template.
Hide pages
In Scroll Versions, pages with a dot (.) in front of the title are hidden by default. This does not work for the lazy-loaded trees. For this to work, you need to change how list items are rendered.
You can do this by passing a function to the options object:
function escapeHtml(input){
return $('<div />').text(input).html();
}
$('.sp-tree').scrollTree({
'contextPath': '',
'renderChildLi': function (child, opts) {
if (child.title.indexOf('.') === 0) {
return '';
}
return '<li class=" + opts.css[child.type] + "><span class="sp-toggle"></span><a href="' + child.link + '">' + escapeHtml(child.title) + '</a></li>';
}
});
This script hides all pages starting with a dot in the page title. Instead of rendering the list item, the script returns an empty string. For a list of options to pass, to further overwrite the page tree, see below.
Further customization
There are several more options for customized tree outputs. These are useful, for example, if you are not happy with the classes or with the display of list items.
option | input | note | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
contextPath | string | Sets the origin for rest-calls | ||||||||||||
renderChildrenUl | function() | Set how children ULs are rendered | ||||||||||||
renderChildrenLi | function(child, opts) | Set how children LIs are rendered
| ||||||||||||
css | object | Object of key-value pairs for classes used, see below | ||||||||||||
css.ancestor | string | parent items | ||||||||||||
css.current | string | currently viewed item | ||||||||||||
css.normal | string | children items | ||||||||||||
css.expanded | string | item is expanded | ||||||||||||
css.collaped | string | children of collapsed trees | ||||||||||||
css.leaf | string | children of expanded trees |
These are the default options: (note that there is no normal class)
function escapeHtml(input) {
return $('<div />').text(input).html();
}
var DEFAULT_OPTIONS = {
'contextPath': '',
'css': {
'ancestor': 'active',
'current': 'active',
"leaf": 'leaf',
'loading': 'sp-loading',
'collapsed': 'sp-collapsed',
'expanded': 'sp-expanded',
'error': 'sp-error'
},
'renderChildrenUl': function () {
return '<ul class="nav"></ul>';
},
'renderChildLi': function (child, opts) {
return '<li class=" + opts.css[child.type] + "><span class="sp-toggle"></span><a href="' + child.link + '">' + escapeHtml(child.title) + '</a></li>'
}
};
Creating the page tree dynamically – server-side
Use this page tree if you need the tree unfolded at all times.
In the page.vm
, include the tree template as follows:
page.vm
$include.template("includes/navigation-tree-entry.vm")
In the folder includes
(create one, if it isn't there already), create the file that will recursively render the tree:
includes/navigation-tree-entry.vm
#macro (createTree $children)
#foreach($child in $children)
<li>
<a href="$child.link">$child.title</a>
#if ($child.hasChildren)
<ul>
#createTree($child.children)
</ul>
#end
</li>
#end
#end
<ul>
#createTree($pages.home.children)
</ul>
That's it - Your page will now create a nested list with all pages. Styling the tree is left as an exercise to the reader, as this is always an individual requirement. For bigger page trees, you should use the Output a page tree#lazy. Described further down on this page.
Page tree with levels
If you want to control how many children levels should get rendered in your page tree you can extend the example from above with the following:
#macro ( createTree $children $levels $topLevelClickAble )
#foreach( $child in $children )
<li>
#if( $topClickAble )
#if( $child.hasChildren )
<span>
<a href="$child.link">$child.title</a>
</span>
#else
<a href="$child.link">$child.title</a>
#end
#else
#if( $child.hasChildren )
<a>$child.title</a>
#else
<a href="$child.link">$child.title</a>
#end
#end
#set( $levels = $levels - 1)
#if ( $child.hasChildren && $levels > 0 )
<ul>
#createTree( $child.children, $levels, true )
</ul>
#end
</li>
#end
#end
<ul>
#createTree( $pages.home.children, 2, false )
</ul>
In this example we used two levels for the page tree and the first level is not clickable as a page. If you open the page tree of this documentation, you can have a look on how the tree gets rendered.
Creating a page tree for blog posts
If you want to have the same blog post overview as you see in Confluence, use the code below. (By default, the overview is rendered as 'Blog Posts in Dec 2016'. As this can become quite cluttered, you can replace it with just the full month ('December' in this case) using the following code.)
#set($months = {"Jan":"January", "Feb":"February", "Mar":"March", "Apr":"April", "May":"May", "Jun":"June", "Jul":"July", "Aug":"August", "Sep":"September", "Oct":"October", "Nov":"November", "Dec":"December"})
#macro (createTree $children)
#foreach($child in $children)
<li>
#if ($child.class.name.indexOf('BlogOverviewPagePlaceholder') != -1)
#set($month = $child.title.replace('Blog Posts in ', ''))
#set($test = "value")
#set($isMonthlyOverview = false)
#foreach($mon in $months.keySet())
#if($month.indexOf($mon) != -1)
#set($isMonthlyOverview = true)
<a href="$child.link">$months.get($mon)</a>
#end
#end
#if($isMonthlyOverview == false)
<a href="$child.link">$month</a>
#end
#else
<a href="$child.link">$child.title</a>
#end
#if ($child.hasChildren)
<ul>
#createTree($child.children)
</ul>
#end
</li>
#end
#end
<ul>
#createTree($page.children)
</ul>
Creating the page tree from a Confluence page
Create a page called '_NavigationTree' and create the navigation tree using a nested unordered list or the children macro.
In page.vm (or any other template), include the content of the wiki page:
page.vm
$include.page("_NavigationTree")
Hard-coding the tree in the template
This is actually really simple, just create a list of HTML elements and hard-code the links:
page.vm
<ul>
<li><a href="/path/to/page-1">Page 1</a></li>
<li><a href="/path/to/page-2">Page 2</a></li>
</ul>
Of course, this approach is very inflexible, but can be suitable if a quick solution is needed.