
net.liftweb.mapper.view.Util.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2009-2011 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.liftweb
package mapper
package view
import common.Full
import util._
import Helpers._
import scala.xml.NodeSeq
/**
* Provides a number of methods that make complex Mapper-based view snippets
* easier to build.
* @author nafg
*/
object Util {
/**
* Binds all nodes whose names are names of fields on the specified mapper.
* This makes it unnecessary to write repetitious bindings like
* "field1" -> field1.toForm,
* "field2" -> field2.toform
* Instead it automates such bindings but you have to pass it a function
* that will generate a NodeSeq from the field, e.g.,
* (f: MappedField[_,_]) => f.toForm
* Usage: Pass as a Full Box to the bind overload that takes a nodeFailureXform
* argument.
*/
def bindFields[T <: Mapper[T]](mapper: T, nsfn: MappedField[_,T]=>NodeSeq): NodeSeq=>NodeSeq = {
case scala.xml.Elem(_, name, _, _, _*) =>
mapper.fieldByName(name) match {
case Full(field) => nsfn(field)
case _ => NodeSeq.Empty
}
case ns => ns
}
/**
* Iterates over the fields of the specified mapper. If the node currently being processed by bind
* has an attribute "fields" then it is taken as a whitespace-delimited list of fields to iterate
* over; otherwise all form fields are used. The specified function returns a BindParam for doing
* processing specific to that field.
* Returns a bind function (NodeSeq=>NodeSeq) that can be used to bind an xml node that should be
* repeated for each field.
* Usage: if you want to repeat xml markup for each field, the view should use the "field:" prefix
* for field-specific nodes. The snippet should bind the containing (repeating) node to the function
* returned by this method, passing this method the mapper instance whose fields should be used and
* a function that returns BindParams to process the "field:" prefixed nodes.
* This method takes an additional filter function to restrict certain fields from being
* displayed. There is an overload without it too.
*/
def eachField[T<:net.liftweb.mapper.Mapper[T]](
mapper: T,
fn:MappedField[_,T]=>CssSel,
filter: MappedField[_,T]=>Boolean
): NodeSeq=>NodeSeq = {
def fieldBindIfWanted(fieldName: String) = {
mapper.fieldByName(fieldName).filter(filter) match {
case Full(field) =>
Some(fn(field))
case _ =>
None
}
}
"^" #> { ns: NodeSeq =>
val fieldsAttribute = (ns \ "@fields")
val bind: Seq[CssSel] =
if (fieldsAttribute.nonEmpty) {
for {
fieldName <- fieldsAttribute.text.split("\\s+").toIndexedSeq
// the following hackery is brought to you by the Scala compiler not
// properly typing MapperField[_, T] in the context of the for
// comprehension
fieldBind <- fieldBindIfWanted(fieldName)
} yield {
".field" #> fieldBind
}
} else {
mapper.formFields.filter(filter).map {
case field: MappedField[_, T] =>
".field" #> fn(field)
}
}
bind.map(_(ns))
}
}
def eachField[T<:net.liftweb.mapper.Mapper[T]](
mapper: T,
fn: MappedField[_,T] => CssSel
): NodeSeq => NodeSeq = eachField(mapper, fn, (_: MappedField[_,T]) => true)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy