In Lift we create menus for our application defining Sitemap and MenuItems. These classes give us a great power to combine and create the required menu but it has some limitation related with the generated Html. If you choose to use frameworks like Bootstrap, Foundation, etc. we need to set css classes or use a combination of tags to get a modern html menu. To specify a way to construct the html using those libraries was not a Sitemap requirement. This task will be accomplished by using FlexMenuBuilder.
To provide a way to introduce and build the menu using the specific front-end framework, the trait FlexMenuBuilder will be defined.
FlexMenuBuilder: in order to construct a menu with the required configuration, this trait will read the defined Sitemap in Lift’s bootstrap and apply the configuration specified in a subclass of this trait. This will be done with some common methods and properties – used by front-end frameworks – that are defined in FlexMenuBuilder.
Besides FlexMenuBuilder we will need to define a subclass that will creates the final menu.
The chosen architecture for this component is a trait that must be extended with the required configuration.
The idea of usage is similar to Menu.builder, its construction must be placed in the main template. FlexMenuBuilder will call render method to show the menu in every page loaded – is recommended to use it as an object- that is created using the defined Sitemap.
The new trait comes with some definitions that can and should be overriden
Since the render method need to run on every page to create the current menu, it can be modified to use memoization or dynamic programming to avoid repeated computations and provide a method to reload when necessary.
package net.liftweb.sitemap
trait FlexMenuBuilder {
type StructBuildItem = AnyRef {
def buildItem(kids : List[MenuItem], current : Boolean, path : Boolean) : Box[MenuItem]
}
def linkToSelf : Boolean
def expandAll : Boolean
protected def expandAny : Boolean
protected def buildItemMenu[A](loc : Loc[A], currLoc : Box[Loc[_]], expandAll : Boolean) : List[MenuItem]
def toRender : Seq[MenuItem]
protected def emptyGroup : NodeSeq
protected def emptyMenu : NodeSeq
protected def emptyPlaceholder : NodeSeq
protected def updateForPath(nodes : Elem, path : Boolean) : Elem
protected def updateForCurrent(nodes : Elem, current : Boolean) : Elem
protected def buildInnerTag(contents : NodeSeq, path : Boolean, current : Boolean) : Elem
protected def renderPlaceholder(item : MenuItem, renderInner : Function1[Seq[MenuItem], NodeSeq]) : Elem
protected def renderSelfLinked(item : MenuItem, renderInner : Function1[Seq[MenuItem], NodeSeq]) : Elem
protected def renderSelfNotLinked(item : MenuItem, renderInner : Function1[Seq[MenuItem], NodeSeq]) : Elem
protected def renderSelf(item : MenuItem) : NodeSeq
protected def renderLink(uri : NodeSeq, text : NodeSeq, path : Boolean, current : Boolean) : NodeSeq
protected def renderItemInPath(item : MenuItem, renderInner : Function1[Seq[MenuItem], NodeSeq]) : Elem
protected def renderItem(item : MenuItem, renderInner : Function1[Seq[MenuItem], NodeSeq]) : Elem
protected def renderOuterTag(inner : NodeSeq, top : Boolean) : NodeSeq
protected def renderWhat(expandAll : Boolean) : Seq[MenuItem]
def render : NodeSeq
}
<span>{item.text}</span>
.<a href={uri}>{text}</a>
.> git clone https://github.com/antidata/FlexMenuBuilderExample.git
> sh sbt.sh
> container:start
then load the page http://localhost:8080
The snippet created to extend the new trait is the object in MyMenu.scala.
The reference to the snippet is in /templates-hidden/default.html
<span data-lift="MyMenu.builder"></span>