From c6a7d3bcfcf83948ae6864d952b06bd8a0c88b43 Mon Sep 17 00:00:00 2001 From: Naoki Takezoe Date: Fri, 24 Nov 2017 20:41:23 +0900 Subject: [PATCH 1/2] Add helpers to render forms in Scalate templates --- build.sbt | 5 ++++- .../scalate/ScalatraFormsHelpers.scala | 20 +++++++++++++++++++ .../scalate/ScalatraRenderContext.scala | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala diff --git a/build.sbt b/build.sbt index 2b6ef8be2..4cf0c424e 100644 --- a/build.sbt +++ b/build.sbt @@ -132,7 +132,10 @@ lazy val scalatraScalate = Project( libraryDependencies += scalate, description := "Scalate integration with Scalatra" ) -) dependsOn(scalatraCore % "compile;test->test;provided->provided") +) dependsOn( + scalatraCore % "compile;test->test;provided->provided", + scalatraForms % "compile;test->test;provided->provided" +) lazy val scalatraJson = Project( id = "scalatra-json", diff --git a/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala b/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala new file mode 100644 index 000000000..6e4738a62 --- /dev/null +++ b/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala @@ -0,0 +1,20 @@ +package org.scalatra.scalate + +import org.fusesource.scalate.servlet.ServletRenderContext +import org.scalatra.forms + +/** + * Supplies helper methods to render forms in Scalate templates. + */ +trait ScalatraFormsHelpers { self: ServletRenderContext => + + def text(name: String, attributes: (String, String)*): Unit = unescape(forms.views.text(name, attributes: _*)(request)) + def password(name: String, attributes: (String, String)*): Unit = unescape(forms.views.password(name, attributes: _*)(request)) + def textarea(name: String, attributes: (String, String)*): Unit = unescape(forms.views.textarea(name, attributes: _*)(request)) + def checkbox(name: String, value: String, attributes: (String, String)*): Unit = unescape(forms.views.checkbox(name, value, attributes: _*)(request)) + def radio(name: String, value: String, attributes: (String, String)*): Unit = unescape(forms.views.radio(name, value, attributes: _*)(request)) + def select(name: String, values: Seq[(String, String)], multiple: Boolean, attributes: (String, String)*): Unit = unescape(forms.views.select(name, values, multiple, attributes: _*)(request)) + def error(name: String): Option[String] = forms.views.error(name)(request) + def errors(name: String): Seq[String] = forms.views.errors(name)(request) + +} diff --git a/scalate/src/main/scala/org/scalatra/scalate/ScalatraRenderContext.scala b/scalate/src/main/scala/org/scalatra/scalate/ScalatraRenderContext.scala index d08c29436..6cda85fa6 100644 --- a/scalate/src/main/scala/org/scalatra/scalate/ScalatraRenderContext.scala +++ b/scalate/src/main/scala/org/scalatra/scalate/ScalatraRenderContext.scala @@ -17,7 +17,7 @@ class ScalatraRenderContext( engine: TemplateEngine, out: PrintWriter, req: HttpServletRequest, - res: HttpServletResponse) extends ServletRenderContext(engine, out, req, res, kernel.servletContext) { + res: HttpServletResponse) extends ServletRenderContext(engine, out, req, res, kernel.servletContext) with ScalatraFormsHelpers { def flash: scala.collection.Map[String, Any] = kernel match { case flashMapSupport: FlashMapSupport => flashMapSupport.flash(request) From c0473c43d7c1c7d66cfffbc5d602b3d5e3c01a8a Mon Sep 17 00:00:00 2001 From: Naoki Takezoe Date: Sat, 25 Nov 2017 12:17:22 +0900 Subject: [PATCH 2/2] Remove physical dependency of ScalatraFormsHelpers to scalatra-forms --- build.sbt | 5 +- .../scalate/ScalatraFormsHelpers.scala | 99 +++++++++++++++++-- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/build.sbt b/build.sbt index 4cf0c424e..c72048467 100644 --- a/build.sbt +++ b/build.sbt @@ -132,10 +132,7 @@ lazy val scalatraScalate = Project( libraryDependencies += scalate, description := "Scalate integration with Scalatra" ) -) dependsOn( - scalatraCore % "compile;test->test;provided->provided", - scalatraForms % "compile;test->test;provided->provided" -) +) dependsOn(scalatraCore % "compile;test->test;provided->provided") lazy val scalatraJson = Project( id = "scalatra-json", diff --git a/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala b/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala index 6e4738a62..c810962d2 100644 --- a/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala +++ b/scalate/src/main/scala/org/scalatra/scalate/ScalatraFormsHelpers.scala @@ -1,20 +1,101 @@ package org.scalatra.scalate import org.fusesource.scalate.servlet.ServletRenderContext -import org.scalatra.forms +import org.scalatra.MultiParams /** * Supplies helper methods to render forms in Scalate templates. */ trait ScalatraFormsHelpers { self: ServletRenderContext => - def text(name: String, attributes: (String, String)*): Unit = unescape(forms.views.text(name, attributes: _*)(request)) - def password(name: String, attributes: (String, String)*): Unit = unescape(forms.views.password(name, attributes: _*)(request)) - def textarea(name: String, attributes: (String, String)*): Unit = unescape(forms.views.textarea(name, attributes: _*)(request)) - def checkbox(name: String, value: String, attributes: (String, String)*): Unit = unescape(forms.views.checkbox(name, value, attributes: _*)(request)) - def radio(name: String, value: String, attributes: (String, String)*): Unit = unescape(forms.views.radio(name, value, attributes: _*)(request)) - def select(name: String, values: Seq[(String, String)], multiple: Boolean, attributes: (String, String)*): Unit = unescape(forms.views.select(name, values, multiple, attributes: _*)(request)) - def error(name: String): Option[String] = forms.views.error(name)(request) - def errors(name: String): Seq[String] = forms.views.errors(name)(request) + private val RequestAttributeParamsKey = "org.scalatra.forms.params" + private val RequestAttributeErrorsKey = "org.scalatra.forms.errors" + /** + * Render a text field. + */ + def text(name: String, attributes: (String, String)*): Unit = { + unescape(s"""""") + } + + /** + * Render a password field. + */ + def password(name: String, attributes: (String, String)*): Unit = { + unescape(s"""""") + } + + /** + * Render a textarea. + */ + def textarea(name: String, attributes: (String, String)*): Unit = { + unescape(s"""""") + } + + /** + * Render a checkbox. + */ + def checkbox(name: String, value: String, attributes: (String, String)*): Unit = { + val checked = if (params(name).contains(value)) "checked" else "" + unescape(s"""""") + } + + /** + * Render a radio button. + */ + def radio(name: String, value: String, attributes: (String, String)*): Unit = { + val checked = if (param(name) == value) "checked" else "" + unescape(s"""""") + } + + /** + * Render a select box. + */ + def select(name: String, values: Seq[(String, String)], multiple: Boolean, attributes: (String, String)*): Unit = { + val sb = new StringBuilder() + sb.append(s"""") + unescape(sb.toString) + } + + /** + * Retrieve an error message of the specified field. + */ + def error(name: String): Option[String] = { + Option(request.getAttribute(RequestAttributeErrorsKey)).flatMap { errors => + errors.asInstanceOf[Seq[(String, String)]].find(_._1 == name).map(_._2) + } + } + + /** + * Retrieve all error messages of the specified field. + */ + def errors(name: String): Seq[String] = { + Option(request.getAttribute(RequestAttributeErrorsKey)).map { errors => + errors.asInstanceOf[Seq[(String, String)]].collect { case error if error._1 == name => error._2 } + }.getOrElse(Nil) + } + + private def escape(value: String): String = { + value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """) + } + + private def params(name: String): Seq[String] = { + Option(request.getAttribute(RequestAttributeParamsKey)).flatMap { params => + params.asInstanceOf[MultiParams].get(name) + }.getOrElse(Nil) + } + + private def param(name: String): String = { + params(name).headOption.getOrElse("") + } + + private def attrs(attrs: (String, String)*): String = { + attrs.map { case (name, value) => s"""${escape(name)}="${escape(value)}"""" }.mkString(" ") + } }