New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency on scala-xml removed. Scala.js integration. #11

Merged
merged 11 commits into from Dec 31, 2013
Copy path View file
@@ -49,6 +49,7 @@ ScalaTags is hosted on [Maven Central](); to get started, simply add the followi
```scala
libraryDependencies += "com.scalatags" % "scalatags_2.10" % "0.1.4"
```
(this is for old version which uses ```scala-xml``` -[here](https://github.com/lihaoyi/scalatags/tree/b505a303dc5cdf7664b11158dd2cbd371c39cf48)-, for the current version just clone the repo and reference it on your sbt project)

And you're good to go! simply open up a `sbt console`, and you can start working through the [Examples](#Examples), which should just work when copied and pasted into the console.

@@ -74,7 +75,7 @@ And all the other good things (<em>jump to definition</em>, *extract method*, et
Examples
========

This is a bunch of simple examples to get you started using ScalaTags. Essentially, each fragment has a `.toXML` method, which turns it into a normal scala XML data structure. You can serialize it, prettyprint it, and in general do whatever you want. It's just XML.
This is a bunch of simple examples to get you started using ScalaTags. Essentially, each fragment has a `.toString` method, which turns it into a HTML string.

These examples are all in the [unit tests](https://github.com/lihaoyi/scalatags/blob/master/src/test/scala/scalatags/ExampleTests.scala).

@@ -102,14 +103,20 @@ val frag = html(
Creates a ScalaTag fragment. We could do many things with a fragment: store it, return it, but eventually you will want to convert it into HTML. In order to render the fragment to HTML, simply use:

```scala
frag.toXML
frag.toString
```

Which will give you a `scala.xml.NodeSeq` XML data structure. If we want to view it nicely, we could prettyprint it:
Which will give you a String containing the HTML representation:

```html
<html><head><script>some script</script></head><body><h1>This is my title</h1><div><p>This is my first paragraph</p><p>This is my second paragraph</p></div></body></html>
```

This representation omits unnecesary whitespace. To improve readability we could pretty print it using some XML processing:

```scala
val prettier = new scala.xml.PrettyPrinter(80, 4)
println(prettier.format(frag.toXML))
println(prettier.format(scala.xml.XML.loadString(frag.toString)))
```

executing that prints out:
@@ -396,10 +403,10 @@ prints
<script>some script</script>
</head>
<body>
<h1 style="background-color:blue">This is my title</h1>
<div style="color:red background-color:blue">
<h1 style="background-color:blue;">This is my title</h1>
<div style="color:red;background-color:blue;">
<p class="contentpara first">This is my first paragraph</p>
<a style="opacity:0.9">
<a style="opacity:0.9;">
<p class="contentpara">Goooogle</p>
</a>
</div>
@@ -515,7 +522,7 @@ prints
Unsanitized Input
-----------------
If you *really* want, for whatever reason, to put unsanitized input into your XML, simply use scala's Unparsed function:
If you *really* want, for whatever reason, to put unsanitized input into your HTML, simply put the string:

```scala
val input = "<p>i am a cow</p>"
@@ -526,7 +533,7 @@ html(
),
body(
h1("This is my title"),
Unparsed(input)
input
)
)
```
@@ -547,45 +554,6 @@ prints

Although this makes it easy to open up XSS holes, if you know what you're doing, go ahead.

Inline XML
----------

If, for some reason, you want to include XML within your ScalaTags fragment, you can easily do so:

```scala
html(
head(
<script>Stuff Inside</script>,
link()
),
body(
<div>
<h1>Title</h1>
<p>Stuff</p>
</div>
)
)
```

gets converted to

```html
<html>
<head>
<script>Stuff Inside</script>
<link></link>
</head>
<body>
<div>
<h1>Title</h1>
<p>Stuff</p>
</div>
</body>
</html>
```

As you can see, it just works.

Design Considerations
=====================
Below are some of the design considerations that went into the ~400 lines of code that make up the ScalaTags library.
@@ -638,6 +606,19 @@ This means that ScalaTags will naturally be more verbose when trying to express

The solution? Use [Markdown](http://en.wikipedia.org/wiki/Markdown) or [Textile](http://redcloth.org/textile) or even plain XML to mark up those sections, and save ScalaTags for the heavy structural parts where you can really enjoy the benefits in static checking and DRY.

Scala.js
========

ScalaTags now works out-of-the-box with [Scala.js](http://www.scala-js.org/). The folder ```scalatags-js``` includes an alternate SBT project that builds with Scala.js. Just put a dependency on it from your own project.

Scala.js tools
--------------

The Scala.js version includes an additional object ```scalatags.JSUtils``` which adds two implicit methods to interact with the DOM:

- ```.toJSDynamic```: converts the fragment into a DOM node and returns it as a js.Dynamic object.
- ```.toDOMNode```: converts the fragment into a DOM node and returns it as a org.scalajs.dom.Node object.

License
=======

Copy path View file
@@ -1 +1 @@
sbt.version=0.12.1
sbt.version=0.13.1
Copy path View file
@@ -1,3 +1,2 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8")
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8")
@@ -0,0 +1,14 @@
import sbt._
import Keys._
import scala.scalajs.sbtplugin.ScalaJSPlugin._
import ScalaJSKeys._
object Build extends sbt.Build {
lazy val root = project.in(file("."))
.settings(scalaJSSettings: _*)
.settings(
name := "scalatags-js",
version := "0.1.4",
unmanagedSourceDirectories in Compile += baseDirectory.value / ".." / "src" / "main", // test sources are omitted from js build
libraryDependencies += "org.scala-lang.modules.scalajs" %% "scalajs-dom" % "0.1-SNAPSHOT"
)
}
@@ -0,0 +1 @@
sbt.version=0.13.1
@@ -0,0 +1,14 @@
import sbt._
import Keys._

object Build extends sbt.Build {
import sbt._

override lazy val projects = Seq(root)
lazy val root =
Project("plugins", file("."))
.settings(
resolvers += Resolver.url("scala-js-releases", url("http://repo.scala-js.org/repo/releases/"))(Resolver.ivyStylePatterns),
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.1")
)
}
@@ -0,0 +1,22 @@

package scalatags

import scala.scalajs.js
import js.Dynamic.{ global => g }
import org.scalajs.dom.document

object JSUtils {
implicit def HtmlTag2JS(n: HtmlTag) = new {
def toDOMNode = {
val tmp = document.createElement("div")
tmp.innerHTML = n.toString
tmp.firstChild
}

def toJSDynamic = {
val tmp = g.document.createElement("div")
tmp.innerHTML = n.toString
tmp.firstChild
}
}
}
@@ -1,6 +1,5 @@
package scalatags

import xml.Unparsed
import util.Random

/**
@@ -1,14 +1,26 @@
package scalatags
import scala.xml._

import scala.collection.mutable.StringBuilder

/**
* A general interface for all types which can appear in a ScalaTags fragment.
*/
trait STag{
/**
* Converts an ScalaTag fragment into a `scala.xml.NodeSeq`
* Converts an ScalaTag fragment into an html string
*/
override def toString() = {
val strb = new StringBuilder
writeTo(strb)
strb.toString
}

/**
* Appends the textual representation of the ScalaTag fragment to the
* 'strb' StringBuilder, so StringBuilder can be passed to childrens.
* Used to optimize the toString() operation.
*/
def toXML(): NodeSeq
def writeTo(strb: StringBuilder): Unit

/**
* The children of a ScalaTag node
@@ -37,17 +49,30 @@ case class HtmlTag(tag: String = "",
copy(attrMap = t.foldLeft(attrMap)(_+_))
}

def toXML(): Elem = {
val c = flattenChildren(children)
var newAttrMap = attrMap
if (classes != Nil) newAttrMap = newAttrMap.updated("class", attrMap.getOrElse("class", "") + classes.map(_.toString + " ").mkString)
if (styles != Map.empty) newAttrMap = newAttrMap.updated("style", attrMap.getOrElse("style", "") + styles.map{case (k, v) => k + ": " + v + "; "}.mkString)
newAttrMap.foldLeft(new Elem(null, tag, Null, TopScope, false, c: _*))(
(e, k) => e % new UnprefixedAttribute(k._1, k._2.toString, Null)
)
def writeTo(strb: StringBuilder): Unit = {
// tag
strb ++= "<" ++= tag
// classes
if(classes != Nil)
strb ++= " class=\"" ++= classes.mkString(" ") ++= "\""
// attributes
attrMap.foreach(a => strb ++= " " ++= a._1 ++= "=\"" ++= a._2.toString ++= "\"")
// styles
if(!styles.isEmpty) {
strb ++= " style=\""
styles.foreach(s => strb ++= s._1 ++= ":" ++= s._2.toString ++= ";")
strb ++= "\""
}
if(children == Nil)
// No children - close tag
strb ++= "/>"
else {
strb ++= ">"
// Childrens
children.foreach(_.writeTo(strb))
// Closing tag
strb ++= "</" ++= tag ++= ">"
}
}

def flattenChildren(c: Seq[STag]) =
c.flatMap(_.toXML())

}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.