/scalate-core/src/main/scala/org/fusesource/scalate/support/RenderHelper.scala

http://github.com/scalate/scalate · Scala · 148 lines · 96 code · 8 blank · 44 comment · 1 complexity · 3229d3b65a6fd65902006c493eda84b9 MD5 · raw file

  1. /**
  2. * Copyright (C) 2009-2011 the original author or authors.
  3. * See the notice.md file distributed with this work for additional
  4. * information regarding copyright ownership.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. /*
  19. * Copyright (c) 2009 Matthew Hildebrand <matt.hildebrand@gmail.com>
  20. *
  21. * Permission to use, copy, modify, and/or distribute this software for any
  22. * purpose with or without fee is hereby granted, provided that the above
  23. * copyright notice and this permission notice appear in all copies.
  24. *
  25. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  26. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  27. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  28. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  29. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  30. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  31. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32. */
  33. package org.fusesource.scalate
  34. package support
  35. import scala.collection.mutable.LinkedHashMap
  36. object RenderHelper {
  37. /**
  38. * Pads the text following newlines with the specified
  39. * indent amount so that the text is indented.
  40. */
  41. def indent(amount: String, text: Any): String = text.toString.replaceAll("\n(.)", "\n" + amount + "$1")
  42. def indentAmount(level: Int, kind: String): String = {
  43. val rc = new StringBuilder
  44. var i = 0
  45. while (i < level) {
  46. rc.append(kind)
  47. i += 1
  48. }
  49. rc.toString
  50. }
  51. /**
  52. * Converts newlines into the XML entity: &#x000A;
  53. * so that multiple lines encode to a sinle long HTML source line
  54. * but still render in browser as multiple lines.
  55. */
  56. def preserve(text: Any): String = text.toString.replaceAll("\n", "&#x000A;")
  57. /**
  58. * Escapes any XML special characters.
  59. */
  60. def sanitize(text: String): String =
  61. text.foldLeft(new StringBuffer)((acc, ch) => sanitize(ch, acc)).toString
  62. private def sanitize(ch: Char, buffer: StringBuffer): StringBuffer = {
  63. ch match {
  64. case '"' => buffer.append("&quot;")
  65. case '&' => buffer.append("&amp;")
  66. case '<' => buffer.append("&lt;")
  67. case '>' => buffer.append("&gt;")
  68. // Not sure if there are other chars the need sanitization.. but if we do find
  69. // some, then the following might work:
  70. // case xxx => buffer.append( "&#x" + ch.toInt.toHexString + ";" )
  71. case _ => buffer.append(ch)
  72. }
  73. }
  74. def attributes(context: RenderContext, entries: List[(Any, Any)]): Unit = {
  75. val (entries_class, tmp) = entries.partition { x => { x._1 match { case "class" => true; case _ => false } } }
  76. val (entries_id, entries_rest) = tmp.partition { x => { x._1 match { case "id" => true; case _ => false } } }
  77. val map = LinkedHashMap[Any, Any]()
  78. def isEnabled(value: Any) = value != null && (!value.isInstanceOf[Boolean] || value.asInstanceOf[Boolean])
  79. val flattener = (x: (Any, Any)) => {
  80. if (isEnabled(x._2)) {
  81. List(x._2)
  82. } else {
  83. Nil
  84. }
  85. }
  86. val ids = entries_id.flatMap(flattener)
  87. if (!ids.isEmpty) {
  88. map += "id" -> ids.last
  89. }
  90. val classes = entries_class.flatMap(flattener)
  91. if (!classes.isEmpty) {
  92. map += "class" -> classes.mkString(" ")
  93. }
  94. entries_rest.foreach { me => map += me._1 -> me._2 }
  95. if (!map.isEmpty) {
  96. map.foreach {
  97. case (name, value) =>
  98. if (isEnabled(value)) {
  99. context << " "
  100. context << name
  101. context << "=\""
  102. if (value.isInstanceOf[Boolean]) {
  103. context << name
  104. } else {
  105. context.escape(value)
  106. }
  107. context << "\""
  108. }
  109. }
  110. }
  111. }
  112. def smart_sanitize(context: RenderContext, value: Any): String = {
  113. context.value(value).toString
  114. /*
  115. if (value == null) {
  116. return context.value(value);
  117. }
  118. value match {
  119. case x: Node =>
  120. context.value(value)
  121. case x: Traversable[Any] =>
  122. x.map( smart_sanitize(context, _) ).mkString("")
  123. case _ =>
  124. sanitize(context.value(value, false))
  125. }
  126. */
  127. }
  128. }