# HG changeset patch # User Tomas Zeman # Date 1334230605 -7200 # Node ID 523c5c5b84e5a01e6dba842d7e9dd1f212fe189e # Parent d67905a2c39d053d82a6982d0543098c7734cb0d [mq]: twitter-bootstrap-forms-error+help.patch diff -r d67905a2c39d -r 523c5c5b84e5 src/main/scala/bootstrap/liftweb/Boot.scala --- a/src/main/scala/bootstrap/liftweb/Boot.scala Thu Apr 12 10:52:42 2012 +0200 +++ b/src/main/scala/bootstrap/liftweb/Boot.scala Thu Apr 12 13:36:45 2012 +0200 @@ -46,6 +46,8 @@ LiftRules.htmlProperties.default.set { r: Req => Html5Properties(r.userAgent) } + + ScreenRules.init() } } diff -r d67905a2c39d -r 523c5c5b84e5 src/main/scala/fis/base/ui/BootstrapScreen.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/fis/base/ui/BootstrapScreen.scala Thu Apr 12 13:36:45 2012 +0200 @@ -0,0 +1,203 @@ +/* + * Copyright 2012 Tomas Zeman + * + * 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. + * + * BootstrapScreen is based on ScreenWizardRendered which is + * Copyright 2010-2011 WorldWide Conferencing, LLC + * + */ +package fis.base.ui + +import net.liftweb.common._ +import net.liftweb.http._ +import net.liftweb.http.js._ +import net.liftweb.http.js.JsCmds._ +import net.liftweb.util._ +import net.liftweb.util.Helpers._ +import scala.xml._ + +trait BootstrapScreen extends ScreenWizardRendered { + + protected override def renderAll(currentScreenNumber: Box[NodeSeq], + screenCount: Box[NodeSeq], + wizardTop: Box[Elem], + screenTop: Box[Elem], + fields: List[ScreenFieldInfo], + prev: Box[Elem], + cancel: Box[Elem], + next: Box[Elem], + finish: Box[Elem], + screenBottom: Box[Elem], + wizardBottom: Box[Elem], + nextId: (String, () => JsCmd), + prevId: Box[(String, () => JsCmd)], + cancelId: (String, () => JsCmd), + theScreen: AbstractScreen, + ajax_? : Boolean): NodeSeq = { + + val notices: List[(NoticeType.Value, NodeSeq, Box[String])] = S.getAllNotices + + def bindFieldLine(xhtml: NodeSeq): NodeSeq = { + fields.flatMap { + f => + val theFormEarly = f.input + val curId = theFormEarly.flatMap(Helpers.findId) or + f.field.uniqueFieldId openOr Helpers.nextFuncName + + val theForm = theFormEarly.map { + fe => { + val f = Helpers.deepEnsureUniqueId(fe) + val id = Helpers.findBox(f)(_.attribute("id"). + map(_.text). + filter(_ == curId)) + if (id.isEmpty) { + Helpers.ensureId(f, curId) + } else { + f + } + } + } + + val myNotices = notices.filter(fi => fi._3.isDefined && fi._3 == curId) + val maxNotice = myNotices.map(_._1).sortWith { _.id > _.id }.headOption + + def doLabel(in: NodeSeq): NodeSeq = + bind("wizard", in, AttrBindParam("for", curId, "for"), "bind" -%> f.text) + + val line = bind("wizard", xhtml, + "label" -%> doLabel _, + "form" -%> theForm, + FuncBindParam("help", xml => { + f.help match { + case Full(hlp) => bind("wizard", xml, "bind" -%> hlp) + case _ => NodeSeq.Empty + } + }), + FuncBindParam("field_errors", xml => { + myNotices match { + case Nil => NodeSeq.Empty + case xs => bind("wizard", xml, "error" -%> + (innerXml => xs.flatMap { + case (noticeType, msg, _) => + val metaData: MetaData = noticeTypeToAttr(theScreen).map(_(noticeType)) openOr Null + bind("wizard", innerXml, "bind" -%> msg).map { + case e: Elem => e % metaData + case x => x + } + })) + } + })) + + maxNotice map { t => + (".control-group [class+]" #> t.lowerCaseTitle)(line) + } getOrElse line + } + } + + def url = S.uri + + val snapshot = createSnapshot + + def bindErrors(xhtml: NodeSeq): NodeSeq = notices.filter(_._3.isEmpty) match { + case Nil => NodeSeq.Empty + case xs => + def doErrors(in: NodeSeq): NodeSeq = xs.flatMap { + case (noticeType, msg, _) => + val metaData: MetaData = noticeTypeToAttr(theScreen).map(_(noticeType)) openOr Null + bind("wizard", in, "bind" -%> + (msg)).map { + case e: Elem => e % metaData + case x => x + } + } + + bind("wizard", xhtml, + "item" -%> doErrors _) + } + + def bindFields(xhtml: NodeSeq): NodeSeq = { + val ret = + (
+ {S.formGroup(-1)(SHtml.hidden(() => + snapshot.restore()))}{bind("wizard", xhtml, + "line" -%> bindFieldLine _)}{S.formGroup(4)( + SHtml.hidden(() => { + val res = nextId._2(); + if (!ajax_?) { + val localSnapshot = createSnapshot + S.seeOther(url, () => { + localSnapshot.restore + }) + } + res + }))} +
% + theScreen.additionalAttributes) ++ + prevId.toList.map { + case (id, func) => +
+ {SHtml.hidden(() => { + snapshot.restore(); + val res = func(); + if (!ajax_?) { + val localSnapshot = createSnapshot; + S.seeOther(url, () => localSnapshot.restore) + } + res + })} +
+ } ++ +
+ {SHtml.hidden(() => { + snapshot.restore(); + val res = cancelId._2() // WizardRules.deregisterWizardSession(CurrentSession.is) + if (!ajax_?) { + S.seeOther(Referer.get) + } + res + })} +
+ + if (ajax_?) { + SHtml.makeFormsAjax(ret) + } else { + ret + } + } + + def bindScreenInfo(xhtml: NodeSeq): NodeSeq = (currentScreenNumber, screenCount) match { + case (Full(num), Full(cnt)) => + bind("wizard", xhtml, "screen_number" -%> num /*Text(CurrentScreen.is.map(s => (s.myScreenNum + 1).toString) openOr "")*/ , + "total_screens" -%> cnt /*Text(screenCount.toString)*/) + case _ => NodeSeq.Empty + } + + Helpers.bind("wizard", allTemplate, + "screen_info" -%> bindScreenInfo _, + FuncBindParam("wizard_top", xml => (wizardTop.map(top => bind("wizard", xml, "bind" -%> top)) openOr NodeSeq.Empty)), + FuncBindParam("screen_top", xml => (screenTop.map(top => bind("wizard", xml, "bind" -%> top)) openOr NodeSeq.Empty)), + FuncBindParam("wizard_bottom", xml => (wizardBottom.map(bottom => bind("wizard", xml, "bind" -%> bottom)) openOr NodeSeq.Empty)), + FuncBindParam("screen_bottom", xml => (screenBottom.map(bottom => bind("wizard", xml, "bind" -%> bottom)) openOr NodeSeq.Empty)), + "prev" -%> (prev openOr EntityRef("nbsp")), + "next" -%> ((next or finish) openOr EntityRef("nbsp")), + "cancel" -%> (cancel openOr EntityRef("nbsp")), + "errors" -%> bindErrors _, + FuncBindParam("fields", bindFields _)) + + } +} + + +// vim: set ts=2 sw=2 et: diff -r d67905a2c39d -r 523c5c5b84e5 src/main/scala/fis/base/ui/screen.scala --- a/src/main/scala/fis/base/ui/screen.scala Thu Apr 12 10:52:42 2012 +0200 +++ b/src/main/scala/fis/base/ui/screen.scala Thu Apr 12 13:36:45 2012 +0200 @@ -15,9 +15,9 @@ */ package fis.base.ui -import net.liftweb.http.LiftScreen +import net.liftweb.http._ import net.tz.lift.model._ -import scala.xml.{Elem, Text, UnprefixedAttribute} +import scala.xml.{Elem, MetaData, Null, Text, UnprefixedAttribute} trait SaveButton { self: LiftScreen => override def finishButton: Elem = @@ -38,9 +38,19 @@ } -trait HorizontalScreen extends LiftScreen { +trait HorizontalScreen extends LiftScreen with BootstrapScreen { override def additionalAttributes = new UnprefixedAttribute("class", Text("form-horizontal"), super.additionalAttributes) } +object ScreenRules { + def init() { + LiftScreenRules.messageStyles.default.set(() => { + case NoticeType.Notice => new UnprefixedAttribute("class", "notice", Null) + case NoticeType.Warning => new UnprefixedAttribute("class", "warning", Null) + case NoticeType.Error => new UnprefixedAttribute("class", "error", Null) + }: PartialFunction[NoticeType.Value, MetaData]) + } +} + // vim: set ts=2 sw=2 et: diff -r d67905a2c39d -r 523c5c5b84e5 src/main/scala/net/tz/lift/model/FieldHelp.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/net/tz/lift/model/FieldHelp.scala Thu Apr 12 13:36:45 2012 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright 2012 Tomas Zeman + * + * 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.tz.lift.model + +import net.liftweb.common._ +import net.liftweb.record._ +import net.liftweb.util.Helpers._ + +/** + * Generic field help. + * Field help is taken from resource bundle. + */ +trait FieldHelp { self: OwnedField[_ <: Record[_]] => + override def helpAsHtml = Box !! i18n("%s.%s.help".format( + camelifyMethod(owner.getClass.getSimpleName), + camelifyMethod(name)) filterNot {_ == '$'}) +} + +// vim: set ts=2 sw=2 et: diff -r d67905a2c39d -r 523c5c5b84e5 src/main/webapp/css/base.css --- a/src/main/webapp/css/base.css Thu Apr 12 10:52:42 2012 +0200 +++ b/src/main/webapp/css/base.css Thu Apr 12 13:36:45 2012 +0200 @@ -56,6 +56,14 @@ font-weight: bold; } +.control-group label { + float: left; +} + +p.inline { + margin: 0px 0px 0px 0px; +} + #secnav li { float: left; padding: 0px 10px 10px 0; diff -r d67905a2c39d -r 523c5c5b84e5 src/main/webapp/templates-hidden/wizard-all.html --- a/src/main/webapp/templates-hidden/wizard-all.html Thu Apr 12 10:52:42 2012 +0200 +++ b/src/main/webapp/templates-hidden/wizard-all.html Thu Apr 12 13:36:45 2012 +0200 @@ -10,26 +10,26 @@
-
- - - -
- - - - - + +
+ + + +
+ -
    - -
  • -
    -
+ +

+
+ + +

+
+
- +
-
+