Skip to content

Instantly share code, notes, and snippets.

@timperrett
Created September 28, 2012 10:17
Show Gist options
  • Save timperrett/3799017 to your computer and use it in GitHub Desktop.
Save timperrett/3799017 to your computer and use it in GitHub Desktop.
light js dsl
trait js {
implicit def arrayExpr[A](es: Seq[A])(implicit f: A => Expr): ArrayExpr =
ArrayExpr(es.map(f))
implicit def objectExpr[A](fs: Seq[(String, A)])(implicit f: A => Expr): ObjectExpr =
ObjectExpr(fs.map { case (k, v) => (k, f(v)) })
implicit def booleanLiteral(b: Boolean): LiteralBoolean = LiteralBoolean(b)
implicit def nodeSeqLiteral(ns: NodeSeq): LiteralNodeSeq = LiteralNodeSeq(ns)
implicit def numericLiteral[A: Numeric](n: A): LiteralNumeric[A] = LiteralNumeric(n)
implicit def stringLiteral(s: String): LiteralString = LiteralString(s)
implicit def symbolReference(in: Symbol): Reference = Reference(in.name)
implicit def exprToJsExpr(in: Expr): JsExp = new JsExp { def toJsCmd = in.toJs }
implicit def exprToJsCmd(in: Expr): JsCmd = new JsCmd { def toJsCmd = in.toJs + ";" }
implicit def exprsToJsCmd(in: Seq[Expr]): JsCmd = new JsCmd { def toJsCmd = in.map(_.toJs).mkString("", ";", ";") }
implicit def cmdToJsCmd(in: Cmd): JsCmd = new JsCmd { def toJsCmd = in.toJs }
implicit def cmdsToJsCmd(in: Seq[Cmd]): JsCmd = new JsCmd { def toJsCmd = in.map(_.toJs).mkString("") }
trait Expr {
val toJs: String
def expr: this.type = this
def apply(in: Expr*): Apply = Apply(this, in)
def ^ (s: String): Select = select(s)
def ^ (s: Symbol): Select = select(s)
def & (e: Expr): Cmds = Cmds(Vector(Statement(this), Statement(e)))
def & (c: Cmd): Cmds = Cmds(Vector(Statement(this), c))
def select(s: String): Select = Select(this, s)
def select(s: Symbol): Select = Select(this, s.name)
def call(s: String, as: Expr*): Apply = Apply(this ^ s, as)
def call(s: Symbol, as: Expr*): Apply = Apply(this ^ s, as)
}
trait Cmd {
val toJs: String
def & (c: Cmd): Cmds = Cmds(Vector(this, c))
}
final case class Cmds(cmds: Vector[Cmd]) extends Cmd {
override def & (c: Cmd): Cmds = Cmds(cmds :+ c)
def & (cs: Cmds): Cmds = Cmds(cmds ++ cs.cmds)
lazy val toJs = cmds.map(_.toJsCmd).mkString("")
}
final case class Statement(in: Expr) extends Cmd { val toJs = in.toJs + ";" }
final case class Return(in: Expr) extends Cmd { val toJs = "return " + in.toJs + ";" }
final case class ArrayExpr(elements: Seq[Expr]) extends Expr {
lazy val toJs = elements.map(_.toJs).mkString("[", ",", "]")
}
final case class ObjectExpr(fields: Seq[(String, Expr)]) extends Expr {
lazy val toJs = fields.map { case (k, v) => k.encJs + ":" + v.toJs }.mkString("{", ",", "}")
}
final case class Reference(identifier: String) extends Expr { val toJs = identifier }
final case class Select(root: Expr, selection: String) extends Expr {
lazy val toJs = root.toJs + "." + selection
}
final case class LiteralBoolean(value: Boolean) extends Expr { val toJs = value.toString }
final case class LiteralString(value: String) extends Expr { val toJs = value.encJs }
final case class LiteralNodeSeq(value: NodeSeq) extends Expr { val toJs = JsNull.fixHtmlFunc("inline", value)(identity) }
final case class LiteralNumeric[A: Numeric](value: A) extends Expr { val toJs = value.toString }
final case class Apply(func: Expr, args: Seq[Expr]) extends Expr {
lazy val toJs: String = func.toJs + args.map(_.toJs).mkString("(", ",", ")")
}
implicit def jqExpr(in: Expr): JqExpr = new JqExpr {
val underlying = in
}
trait JqExpr {
val underlying: Expr
lazy val addClass: Select = (underlying ^ 'addClass)
lazy val appendTo: Select = (underlying ^ 'appendTo)
lazy val index: Select = (underlying ^ 'eq)
lazy val insertBefore: Select = (underlying ^ 'insertBefore)
lazy val remove: Select = (underlying ^ 'remove)
lazy val removeClass: Select = (underlying ^ 'removeClass)
}
def js(in: Expr): Expr = in
val jQuery = Reference("jQuery")
def jQueryId(s: String) = jQuery("#" + s)
}
final def insertRow(index: Option[Int], ev: Event): JsCmd = {
val renderedEvent = renderEvent(ev)
index match {
case Some(i) =>
jQuery(renderedEvent).insertBefore(jQueryId(uniqueId + "-events").index(i * eventTemplate.size))
// JS: jQuery("<html blob>").insertBefore(jQuery("#uniqueId-events").index(1234))
case None =>
jQuery(renderedEvent).appendTo(jQueryId(uniqueId + "-events"))
// JS: jQuery("<html blob>").appendTo(jQuery("#uniqueId-events"))
}
}
final def deleteRow(index: Int): JsCmd =
jQueryId(uniqueId + "-events").index(index * eventTemplate.size).remove()
// JS: jQuery("#uniqueId-events").index(1234).remove()
val onclickJS = (
'showDetailPopup('event, event._id.toString) & Return(false)
// JS: showDetailPopup(event, "eventId"); return false;
).toJs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment