Skip to content

Instantly share code, notes, and snippets.

@Sergic
Last active May 8, 2017 18:53
Show Gist options
  • Save Sergic/3ba7813ef4468294677ea640b2bba68a to your computer and use it in GitHub Desktop.
Save Sergic/3ba7813ef4468294677ea640b2bba68a to your computer and use it in GitHub Desktop.
Scala menu builder
case class MenuItem(name: String, uri: Option[String], title: String, parent: Option[MenuItem], submenus: Seq[MenuItem] = Seq.empty[MenuItem], access: Seq[Role]) {
def isGranted(role: Role) = access.contains(role)
def isCurrent(currentUri: String) = uri.contains(currentUri)
def addChild(item: MenuItem): MenuItem = copy(submenus = (submenus :+ item).map(_.addParent(this)))
def addParent(item: MenuItem) = copy(parent = Some(item))
}
object MenuBuilder {
def createItem(name: String, uri: Option[String], title: String, access: Seq[Role] = Role.ALL_PERMISSION): MenuItem = {
MenuItem(name, uri, title, None, Seq.empty[MenuItem], access)
}
}
case class MenuAccessor(menus: Seq[MenuItem], currentUri: String) {
def current = currentFromMenus(menus)
def itemByName(name: String): Option[MenuItem] = itemByName(menus, name)
private def itemByName(menus: Seq[MenuItem], name: String): Option[MenuItem] = {
if (menus.nonEmpty) {
menus.flatMap { item =>
if (item.name == name) Some(item)
else itemByName(item.submenus, name)
}.headOption
} else {
None
}
}
def itemsByAccess(role: Role) = itemsByAccess(menus, role)
private def itemsByAccess(menus: Seq[MenuItem], role: Role): Seq[MenuItem] = {
menus.filter(_.isGranted(role)).map { item =>
item.copy(submenus = itemsByAccess(item.submenus, role))
}
}
def currentFromMenus(menus: Seq[MenuItem]): Option[MenuItem] = {
if (menus.nonEmpty) {
menus.flatMap { item =>
if (item.isCurrent(currentUri)) Some(item)
else currentFromMenus(item.submenus)
}.headOption
} else {
None
}
}
def breadcrumbs: Option[List[(MenuItem, Boolean)]] = current.flatMap(itemToList(true))
def breadcrumbs(name: String): Option[List[(MenuItem, Boolean)]] = itemByName(name).flatMap(itemToList(true))
private def itemToList(current: Boolean): MenuItem => Option[List[(MenuItem, Boolean)]] = menuItem => menuItem.parent.map(addBreadcrumbs(_, (menuItem, current) :: Nil))
private def addBreadcrumbs(menuItem: MenuItem, items: List[(MenuItem, Boolean)]): List[(MenuItem, Boolean)] = {
val allItems = (menuItem, false) :: items
menuItem.parent.map { parent =>
addBreadcrumbs(parent, allItems)
}.getOrElse(allItems)
}
}
object MenuAccessor {
def build(menus: Seq[MenuItem], currentUri: String) = new MenuAccessor(menus, currentUri)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment