aboutsummaryrefslogtreecommitdiff
path: root/examples/scalajs-react-example
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2016-06-17 22:38:18 -0400
committerChristopher Vogt <oss.nsp@cvogt.org>2016-06-19 20:57:54 -0400
commit47cc41ecaa2eaf5677fcb1794db7bbba6533b559 (patch)
tree8708b8cd5954dfa03f2478b77440340c7664972b /examples/scalajs-react-example
parent12d5bad267b5759e941b7101578808aeb6351e66 (diff)
downloadcbt-47cc41ecaa2eaf5677fcb1794db7bbba6533b559.tar.gz
cbt-47cc41ecaa2eaf5677fcb1794db7bbba6533b559.tar.bz2
cbt-47cc41ecaa2eaf5677fcb1794db7bbba6533b559.zip
refactor/simplify scalaJs plugin and example
- Restructure code as 1 library case class and 1 Build mixin trait. A library is generally easier to understand and could be re-used independently. 1 trait seems simpler than several here. - Let not the plugin create the multi-project build, but the user project manually. I think while this adds some minor code overhead it is much simpler to understand. Fewer tasks and other moving parts needed. - Remove verbose nested sbt-style folder structure. It's simpler without it :).
Diffstat (limited to 'examples/scalajs-react-example')
-rw-r--r--examples/scalajs-react-example/README.md11
-rw-r--r--examples/scalajs-react-example/js/App.scala15
-rw-r--r--examples/scalajs-react-example/js/Pictures.scala102
-rw-r--r--examples/scalajs-react-example/js/build/build.scala22
-rw-r--r--examples/scalajs-react-example/js/build/build/build.scala4
-rw-r--r--examples/scalajs-react-example/jvm/build/build.scala6
-rw-r--r--examples/scalajs-react-example/server/app.js39
-rw-r--r--examples/scalajs-react-example/server/package.json14
-rw-r--r--examples/scalajs-react-example/server/public/index.html18
-rw-r--r--examples/scalajs-react-example/shared/Picture.scala3
10 files changed, 234 insertions, 0 deletions
diff --git a/examples/scalajs-react-example/README.md b/examples/scalajs-react-example/README.md
new file mode 100644
index 0000000..74e015a
--- /dev/null
+++ b/examples/scalajs-react-example/README.md
@@ -0,0 +1,11 @@
+
+Compilation instructions
+-------------------------------------------
+1. `cbt fastOptJS`
+
+Execution instructions
+-------------------------------------------
+1. `cd server`
+2. `npm install`
+3. `node app.js`
+4. Go to http://localhost:3000 in a browser \ No newline at end of file
diff --git a/examples/scalajs-react-example/js/App.scala b/examples/scalajs-react-example/js/App.scala
new file mode 100644
index 0000000..0cd170e
--- /dev/null
+++ b/examples/scalajs-react-example/js/App.scala
@@ -0,0 +1,15 @@
+package prototype
+
+import japgolly.scalajs.react.ReactDOM
+import org.scalajs.dom
+
+import scala.scalajs.js.JSApp
+import scala.scalajs.js.annotation.JSExport
+
+@JSExport("App")
+object App extends JSApp {
+ def main(): Unit = {
+ val doc = dom.document
+ ReactDOM.render(Pictures.PictureComponent(), doc.getElementById("main"))
+ }
+}
diff --git a/examples/scalajs-react-example/js/Pictures.scala b/examples/scalajs-react-example/js/Pictures.scala
new file mode 100644
index 0000000..db1d7ef
--- /dev/null
+++ b/examples/scalajs-react-example/js/Pictures.scala
@@ -0,0 +1,102 @@
+package prototype
+
+import japgolly.scalajs.react.{ReactComponentB, BackendScope, Callback}
+import org.scalajs.dom
+
+import scala.scalajs._
+import japgolly.scalajs.react.vdom.all._
+
+import scala.scalajs.js.JSON
+
+object Pictures {
+
+ case class State(pictures: List[Picture], favourites: List[Picture])
+
+ type PicClick = (String, Boolean) => Callback
+
+ class Backend($: BackendScope[Unit, State]) {
+
+ def onPicClick(id: String, favorite: Boolean) =
+ $.state flatMap { s =>
+ if (favorite) {
+ val newPics = s.pictures.map(p => if (p.id == id) p.copy(favorite = false) else p)
+ val newFavs = s.favourites.filter(p => p.id != id)
+ $.modState(_ => State(newPics, newFavs))
+ } else {
+ var newPic: Picture = null
+ val newPics = s.pictures.map(p => if (p.id == id) {
+ newPic = p.copy(favorite = true); newPic
+ } else p)
+ val newFavs = s.favourites.+:(newPic)
+ $.modState(_ => State(newPics, newFavs))
+ }
+ }
+
+ def render(s: State) =
+ div(
+ h1("Popular Pixabay Pics"),
+ pictureList((s.pictures, onPicClick)),
+ h1("Your favorites"),
+ favoriteList((s.favourites, onPicClick)))
+ }
+
+ val picture = ReactComponentB[(Picture, PicClick)]("picture")
+ .render_P { case (p, b) =>
+ div(if (p.favorite) cls := "picture favorite" else cls := "picture", onClick --> b(p.id, p.favorite))(
+ img(src := p.src, title := p.title)
+ )
+ }
+ .build
+
+ val pictureList = ReactComponentB[(List[Picture], PicClick)]("pictureList")
+ .render_P { case (list, b) =>
+ div(`class` := "pictures")(
+ if (list.isEmpty) span("Loading Pics..")
+ else {
+ list.map(p => picture.withKey(p.id)((p, b)))
+ }
+ )
+ }
+ .build
+
+ val favoriteList = ReactComponentB[(List[Picture], PicClick)]("favoriteList")
+ .render_P { case (list, b) =>
+ div(`class` := "favorites")(
+ if (list.isEmpty) span("Click an image to mark as favorite")
+ else {
+ list.map(p => picture.withKey(p.id)((p, b)))
+ }
+ )
+ }
+ .build
+
+ val PictureComponent = ReactComponentB[Unit]("PictureComponent")
+ .initialState(State(Nil, Nil))
+ .renderBackend[Backend]
+ .componentDidMount(scope => Callback {
+ import scalajs.js.Dynamic.{global => g}
+ def isDefined(g: js.Dynamic): Boolean =
+ g.asInstanceOf[js.UndefOr[AnyRef]].isDefined
+ val url = "http://localhost:3000/data"
+ val xhr = new dom.XMLHttpRequest()
+ xhr.open("GET", url)
+ xhr.onload = { (e: dom.Event) =>
+ if (xhr.status == 200) {
+ val result = JSON.parse(xhr.responseText)
+ if (isDefined(result) && isDefined(result.hits)) {
+ val hits = result.hits.asInstanceOf[js.Array[js.Dynamic]]
+ val pics = hits.toList.map(item => Picture(
+ item.id.toString,
+ item.pageURL.toString,
+ item.previewURL.toString,
+ if (item.tags != null) item.tags.asInstanceOf[js.Array[String]].mkString(",") else ""))
+ //if (item.caption != null) item.caption.text.toString else ""))
+ scope.modState(_ => State(pics, Nil)).runNow()
+ }
+ }
+ }
+ xhr.send()
+ })
+ .buildU
+
+}
diff --git a/examples/scalajs-react-example/js/build/build.scala b/examples/scalajs-react-example/js/build/build.scala
new file mode 100644
index 0000000..29f1c73
--- /dev/null
+++ b/examples/scalajs-react-example/js/build/build.scala
@@ -0,0 +1,22 @@
+import cbt._
+class Build(val context: Context) extends ScalaJsBuild{
+ override val projectName = "my-project"
+
+ override def sources = super.sources ++ Seq(
+ projectDirectory.getParentFile ++ "/shared"
+ )
+
+ override def dependencies = (
+ super.dependencies ++
+ Resolver( mavenCentral ).bind(
+ //"org.scalatest" %%% "scalatest" % "3.0.0-RC2",
+ "com.github.japgolly.scalajs-react" %%% "core" % "0.10.4", // for example
+ // for example if you want explicitely state scala version
+ "org.scala-js" % "scalajs-dom_sjs0.6_2.11" % "0.9.0"
+ )
+ )
+
+ override protected def fastOptJSFile = {
+ projectDirectory.getParentFile ++ "/server/public" ++ ("/"++super.fastOptJSFile.getName)
+ }
+}
diff --git a/examples/scalajs-react-example/js/build/build/build.scala b/examples/scalajs-react-example/js/build/build/build.scala
new file mode 100644
index 0000000..b30e005
--- /dev/null
+++ b/examples/scalajs-react-example/js/build/build/build.scala
@@ -0,0 +1,4 @@
+import cbt._
+class Build(val context: Context) extends BuildBuild{
+ override def dependencies = super.dependencies :+ plugins.scalaJs
+}
diff --git a/examples/scalajs-react-example/jvm/build/build.scala b/examples/scalajs-react-example/jvm/build/build.scala
new file mode 100644
index 0000000..327d705
--- /dev/null
+++ b/examples/scalajs-react-example/jvm/build/build.scala
@@ -0,0 +1,6 @@
+import cbt._
+class Build(val context: Context) extends BaseBuild{
+ override def sources = super.sources ++ Seq(
+ projectDirectory.getParentFile ++ "/shared"
+ )
+}
diff --git a/examples/scalajs-react-example/server/app.js b/examples/scalajs-react-example/server/app.js
new file mode 100644
index 0000000..620c26a
--- /dev/null
+++ b/examples/scalajs-react-example/server/app.js
@@ -0,0 +1,39 @@
+var express = require('express');
+var https = require('https');
+
+var app = express();
+
+app.get('/data', function(req, res){
+
+ var request = https.get(
+ //'https://api.instagram.com/v1/media/popular?client_id=642176ece1e7445e99244cec26f4de1f&callback=?',
+ 'https://pixabay.com/api/?key=2741116-9706ac6d4a58f2b5416225505&q=yellow+flowers&image_type=photo',
+ function(response) {
+
+ var body = "";
+ response.on('data', function(data) {
+ body += data;
+ });
+ response.on('end', function() {
+ console.log(body);
+ try {
+ res.send(JSON.parse(body));
+ } catch (e) {
+ return console.error(e);
+ }
+ });
+ });
+ request.on('error', function(e) {
+ console.log('Problem with request: ' + e.message);
+ });
+ request.end();
+});
+
+app.use(express.static(__dirname + '/public'));
+
+var server = app.listen(3000, function () {
+ var host = server.address().address;
+ var port = server.address().port;
+
+ console.log('Example app listening at http://%s:%s', host, port);
+});
diff --git a/examples/scalajs-react-example/server/package.json b/examples/scalajs-react-example/server/package.json
new file mode 100644
index 0000000..d20ec98
--- /dev/null
+++ b/examples/scalajs-react-example/server/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "description": "prototype",
+ "main": "app.js",
+ "author": "Katrin",
+ "license": "UNLICENSED",
+ "private": true,
+ "dependencies": {
+ "express": "^4.13.3",
+ "express-ws": "^0.2.6",
+ "body-parser": "^1.14.1"
+ }
+}
diff --git a/examples/scalajs-react-example/server/public/index.html b/examples/scalajs-react-example/server/public/index.html
new file mode 100644
index 0000000..08de20d
--- /dev/null
+++ b/examples/scalajs-react-example/server/public/index.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Prototype</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+
+ <div id="main"></div>
+
+ <script src="https://fb.me/react-15.1.0.min.js"></script>
+ <script src="https://fb.me/react-dom-15.1.0.min.js"></script>
+ <script type="text/javascript" src="./my-project-fastopt.js"></script>
+ <script type="text/javascript">
+ App().main();
+ </script>
+</body>
+</html>
diff --git a/examples/scalajs-react-example/shared/Picture.scala b/examples/scalajs-react-example/shared/Picture.scala
new file mode 100644
index 0000000..dbb985a
--- /dev/null
+++ b/examples/scalajs-react-example/shared/Picture.scala
@@ -0,0 +1,3 @@
+package prototype
+
+case class Picture(id: String, url: String, src: String, title: String, favorite: Boolean = false)