Skip to content

Commit eac022f

Browse files
committed
generate the JS using js.scala in a separate project
1 parent 62b1c85 commit eac022f

File tree

6 files changed

+230
-14
lines changed

6 files changed

+230
-14
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@(name: String)(implicit request: RequestHeader)
2+
3+
@main("cursors -- " + name)(name) {
4+
<script src="@routes.Assets.at("javascripts/cursor_.js")" type="text/javascript"></script>
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@(name: String)(implicit request: RequestHeader)
2+
3+
@main("drawing -- " + name)(name) {
4+
<canvas id="canvas" style="width:800px; height:600px;"></canvas>
5+
<script src="@routes.Assets.at("javascripts/drawing_.js")" type="text/javascript"></script>
6+
}
Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
11
@()(implicit request: RequestHeader)
22

3-
@main("cursors") {
4-
5-
<script type="text/javascript">
6-
function createSocket() {
7-
var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket
8-
return new WS("@routes.Application.drawing("index").webSocketURL()")
9-
}
10-
</script>
11-
12-
<script src="@routes.Assets.at("javascripts/mice.js")" type="text/javascript"></script>
13-
14-
}
3+
@cursors("index")

drawing-play/app/views/main.scala.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@(title: String)(content: Html)
1+
@(title: String)(name: String)(content: Html)(implicit request: RequestHeader)
22

33
<!DOCTYPE html>
44

@@ -10,7 +10,13 @@
1010
<link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
1111
<script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
1212
</head>
13-
<body>
13+
<body onLoad="main();">
14+
<script type="text/javascript">
15+
function createSocket() {
16+
var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket
17+
return new WS("@routes.Application.drawing(name).webSocketURL()")
18+
}
19+
</script>
1420
@content
1521
</body>
1622
</html>

drawing-play/jsgen/build.sbt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name := "drawing-play-jsgen"
2+
3+
organization := "js-scala"
4+
5+
version := "0.1-SNAPSHOT"
6+
7+
scalaVersion := Option(System.getenv("SCALA_VIRTUALIZED_VERSION")).getOrElse("2.10.0-M1-virtualized")
8+
9+
scalacOptions ++= Seq("-deprecation", "-unchecked", "-Xexperimental", "-Yvirtualize")
10+
11+
resolvers ++= Seq(
12+
ScalaToolsSnapshots
13+
)
14+
15+
libraryDependencies ++= Seq(
16+
"EPFL" %% "js-scala" % "0.2-SNAPSHOT"
17+
)
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package drawing
2+
3+
import scala.js._
4+
import scala.virtualization.lms.common._
5+
6+
import java.io.PrintWriter
7+
8+
trait MiceApi extends JSProxyBase with JSLiteral {
9+
val window: Rep[Any]
10+
11+
type DataLiteral = JSLiteral {val data : String}
12+
def initWebSocket(): Rep[WebSocket]
13+
trait WebSocket {
14+
var onmessage: Rep[DataLiteral => Any]
15+
def send(data: Rep[String]): Rep[Unit]
16+
}
17+
implicit def repToSocket(x: Rep[WebSocket]): WebSocket = repProxy[WebSocket](x)
18+
19+
type ActionLiteral = JSLiteral {val action: String; val id: String}
20+
type MoveLiteral = JSLiteral {val id: String; val cx: Int; val cy: Int; val w: Int; val h: Int; val color: String}
21+
22+
def currentTime(): Rep[Int]
23+
24+
val json: Rep[JSON]
25+
trait JSON {
26+
def stringify(literal: Rep[JSLiteral]): Rep[String]
27+
def parse[T <: JSLiteral](data: Rep[String]): Rep[T]
28+
}
29+
implicit def repToJSON(x: Rep[JSON]): JSON = repProxy[JSON](x)
30+
31+
def jQuery(x: Rep[Any]): Rep[JQuery]
32+
trait JQuery {
33+
var length: Rep[Int]
34+
35+
def width(): Rep[Int]
36+
def height(): Rep[Int]
37+
38+
def append(s: Rep[String]): Rep[JQuery]
39+
def css(o: Rep[JSLiteral]): Rep[JQuery]
40+
def click(fn: Rep[JQueryEvent => Any]): Rep[JQuery]
41+
def mousemove(fn: Rep[JQueryEvent => Any]): Rep[JQuery]
42+
def remove(): Rep[JQuery]
43+
}
44+
implicit def repToJQuery(x: Rep[JQuery]): JQuery = repProxy[JQuery](x)
45+
type JQueryEvent = JSLiteral {val pageX: Int; val pageY: Int}
46+
}
47+
48+
trait MiceApiExp extends MiceApi with JSProxyExp with JSLiteralExp with DomsExp {
49+
50+
case object WindowVar extends Exp[Any]
51+
val window = WindowVar
52+
53+
case object InitWebSocket extends Def[WebSocket]
54+
def initWebSocket() = reflectEffect(InitWebSocket)
55+
56+
case object CurrentTime extends Def[Int]
57+
def currentTime() = reflectEffect(CurrentTime)
58+
59+
case object JSONVar extends Exp[JSON]
60+
val json = JSONVar
61+
62+
case class JQueryCall(x: Exp[Any]) extends Def[JQuery]
63+
def jQuery(x: Exp[Any]) = JQueryCall(x)
64+
}
65+
66+
trait JSGenMiceApi extends JSGenProxy with JSGenLiteral {
67+
val IR: MiceApiExp
68+
import IR._
69+
70+
override def quote(x: Exp[Any]) : String = x match {
71+
case WindowVar => "window"
72+
case JSONVar => "JSON"
73+
case _ => super.quote(x)
74+
}
75+
76+
override def emitNode(sym: Sym[Any], rhs: Def[Any]) = rhs match {
77+
case InitWebSocket => emitValDef(sym,
78+
"createSocket()")
79+
case CurrentTime => emitValDef(sym,
80+
"(new Date()).getTime()")
81+
case JQueryCall(x) => emitValDef(sym,
82+
"$(" + quote(x) + ")")
83+
case _ => super.emitNode(sym, rhs)
84+
}
85+
}
86+
87+
object Mice {
88+
trait DrawingProg extends MiceProg {
89+
override lazy val move = fun { (mouse: Rep[MoveLiteral]) =>
90+
val canvas = document.getElementById("canvas").as[Canvas]
91+
val c = canvas.getContext("2d")
92+
val x = (mouse.cx*6)/17
93+
val y = (mouse.cy*4)/17
94+
log(string_plus("(", string_plus(String.valueOf(x), string_plus(", ", string_plus(String.valueOf(y), ")")))))
95+
c.fillStyle = mouse.color
96+
c.fillRect(x, y, 5, 5)
97+
}
98+
override lazy val initialPen = false
99+
}
100+
101+
trait CursorProg extends MiceProg {
102+
override lazy val move = fun { (mouse: Rep[MoveLiteral]) =>
103+
if (jQuery("#mouse_"+mouse.id).length == 0)
104+
jQuery("body").append("<span class='mouse' id='mouse_"+mouse.id+"'><span style='display:none;' class='chat'/></span>")
105+
jQuery("#mouse_"+mouse.id).css(new JSLiteral {
106+
val left = ((jQuery(window).width() - mouse.w) / 2 + mouse.cx) + "px"
107+
val top = mouse.cy + "px"
108+
val `background-color` = mouse.color
109+
})
110+
()
111+
}
112+
override lazy val initialPen = true
113+
}
114+
115+
trait MiceProg extends JS with MiceApi with LiftVariables with Doms with JSDebug with Casts {
116+
val move: Rep[MoveLiteral => Unit]
117+
val initialPen: Boolean
118+
def main(): Rep[Unit] = {
119+
var penDown = initialPen
120+
121+
val ratelimit = fun { (ms: Rep[Int]) => fun { (fn: Rep[JQueryEvent => Any]) =>
122+
var last = currentTime()
123+
fun { (e: Rep[JQueryEvent]) =>
124+
val now = currentTime()
125+
if (now - last > ms) {
126+
last = now
127+
fn(e)
128+
}
129+
}
130+
}
131+
}
132+
133+
val socket = initWebSocket()
134+
socket.onmessage = fun { (m: Rep[DataLiteral]) =>
135+
val data = json.parse(m.data).asInstanceOf[Rep[ActionLiteral]]
136+
if (data.action == "close")
137+
jQuery("#mouse_"+data.id).remove()
138+
else if (data.action == "move")
139+
move(data.asInstanceOf[Rep[MoveLiteral]])
140+
}
141+
142+
if (!initialPen) {
143+
jQuery(document).click { (e: Rep[JQueryEvent]) =>
144+
penDown = !penDown
145+
}
146+
}
147+
148+
jQuery(document).mousemove {
149+
val r = ratelimit(40)
150+
r { (e: Rep[JQueryEvent]) =>
151+
if (penDown) {
152+
socket.send(json.stringify(new JSLiteral {
153+
val action = "move"
154+
val cx = e.pageX
155+
val cy = e.pageY
156+
val w = jQuery(window).width()
157+
val h = jQuery(window).height()
158+
}))
159+
}
160+
}
161+
}
162+
163+
()
164+
}
165+
}
166+
167+
trait MiceProgExp extends MiceProg with JSExp with MiceApiExp with LiftVariables with DomsExp with JSDebugExp with Casts
168+
169+
def codegenDrawing(pw: PrintWriter) {
170+
new DrawingProg with MiceProgExp { self =>
171+
val codegen = new JSGenOpt with JSGenMiceApi with GenDoms with JSGenDebug { val IR: self.type = self }
172+
codegen.emitSource0(main _, "main", pw)
173+
}
174+
}
175+
176+
def codegenCursor(pw: PrintWriter) {
177+
new CursorProg with MiceProgExp { self =>
178+
val codegen = new JSGenOpt with JSGenMiceApi with GenDoms with JSGenDebug { val IR: self.type = self }
179+
codegen.emitSource0(main _, "main", pw)
180+
}
181+
}
182+
183+
def writeJs(filename: String, codegen: PrintWriter => Unit) = {
184+
val out = new PrintWriter(filename)
185+
codegen(out)
186+
out.close()
187+
}
188+
}
189+
190+
object Main extends App {
191+
Mice.writeJs("../public/javascripts/drawing_.js", Mice.codegenDrawing)
192+
Mice.writeJs("../public/javascripts/cursor_.js", Mice.codegenCursor)
193+
}

0 commit comments

Comments
 (0)