Skip to content

Commit e36352c

Browse files
committed
Threw in the tutorial and started on specs.
1 parent 5da88e1 commit e36352c

14 files changed

+431
-15
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
*.js
22
bower_components
3-
3+
node_modules

bower.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "purescript-react",
3+
"version": "0.0.1",
4+
"homepage": "https://github.com/purescript-contrib/purescript-react",
5+
"description": "Purescript bindings for React.js",
6+
"keywords": [
7+
"purescript",
8+
"react"
9+
],
10+
"license": "MIT",
11+
"ignore": [
12+
"**/.*",
13+
"node_modules",
14+
"bower_components",
15+
"test",
16+
"tests"
17+
],
18+
"devDependencies": {
19+
"react": "~0.10.0"
20+
}
21+
}
File renamed without changes.

example/index.html renamed to example/app/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</style>
1212
</head>
1313
<body>
14-
<script src="bower_components/react/react.js"></script>
14+
<script src="../../bower_components/react/react.js"></script>
1515
<script src="app.js"></script>
1616
</body>
1717
</html>

example/tutorial/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
React.js tutorial in PureScript
2+
===============================
3+
4+
This is just a quick implementation of the React.js [tutorial][tutorial]
5+
6+
To view it in action:
7+
8+
1. `bower install` in this directory.
9+
It has different dependencies.
10+
1. `gulp example-tutorial` from the root directory.
11+
Paths are tricky.
12+
1. `python server.py` in this directory.
13+
It needs a simple server since it's dishing off AJAX.
14+
1. Visit `http://localhost:8000` in the browser and play around.
15+
16+
[tutorial]: http://facebook.github.io/react/docs/tutorial.html

example/tutorial/bower.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "purescript-react-tutorial",
3+
"version": "0.0.1",
4+
"homepage": "https://github.com/purescript-contrib/purescript-react",
5+
"description": "Purescript implementation of React.js tutorial",
6+
"keywords": [
7+
"purescript",
8+
"react"
9+
],
10+
"license": "MIT",
11+
"ignore": [
12+
"**/.*",
13+
"node_modules",
14+
"bower_components",
15+
"test",
16+
"tests"
17+
],
18+
"private": true,
19+
"devDependencies": {
20+
"react": "~0.10.0",
21+
"showdown": "~0.3.1",
22+
"purescript-showdown": "https://github.com/joneshf/purescript-showdown.git",
23+
"purescript-arrays": "~0.1.3",
24+
"jquery": "~2.1.1"
25+
}
26+
}

example/tutorial/comments.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[{
2+
"text": "This is one comment",
3+
"author": "Pete Hunt"
4+
}, {
5+
"text": "This is *another* comment",
6+
"author": "Jordan Walke"
7+
}]

example/tutorial/index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>React.js tutorial in PureScript</title>
5+
<script src="bower_components/jquery/dist/jquery.min.js"></script>
6+
<script src="bower_components/react/react.js"></script>
7+
<script src="bower_components/showdown/compressed/showdown.js"></script>
8+
</head>
9+
<body>
10+
<div id="content"></div>
11+
<script src="tutorial.js"></script>
12+
</body>
13+
</html>

example/tutorial/server.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# This is originally from https://github.com/nebstrebor/react-tutorial-simpleserver
2+
# It was modified a bit in the process.
3+
4+
import BaseHTTPServer
5+
import SimpleHTTPServer
6+
import json
7+
import urlparse
8+
9+
10+
class ReactTutorialHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
11+
"""
12+
Extension of SimpleHTTPRequestHandler that works with the react.js tutorial.
13+
In addition to standard SimpleHTTPServer file-webserver functionality, adds
14+
POST-ability.
15+
16+
USAGE: python server.py to serve files from the cwd
17+
(works the same as running python -m SimpleHTTPServer in the directory)
18+
"""
19+
def do_POST(self):
20+
# (1) get posted data & convert it to python dict
21+
content_length = int(self.headers['Content-Length'])
22+
post_data = dict(urlparse.parse_qsl(self.rfile.read(content_length).decode('utf-8')))
23+
# (2) open the file at the requested URL (404 if bad)
24+
with open(self.translate_path(self.path), 'rw+') as f:
25+
data = f.read()
26+
# (3) load the file's contents into a list & append the posted data
27+
current_list = json.loads(data)
28+
current_list.append(post_data)
29+
# (4) write the updated content back to the file
30+
json_data = json.dumps(current_list)
31+
f.seek(0)
32+
f.write(json_data)
33+
f.truncate()
34+
# (5) return the updated content (defers to do_GET)
35+
return self.do_GET()
36+
37+
38+
def test(HandlerClass=ReactTutorialHTTPRequestHandler,
39+
ServerClass=BaseHTTPServer.HTTPServer):
40+
BaseHTTPServer.test(HandlerClass, ServerClass)
41+
42+
43+
if __name__ == '__main__':
44+
test()

example/tutorial/tutorial.purs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
module Tutorial where
2+
3+
-- This is a mostly PureScript implementation of the tutorial found here:
4+
-- http://facebook.github.io/react/docs/tutorial.html
5+
6+
import Control.Monad.Eff
7+
import Data.Array
8+
import React
9+
import Showdown
10+
11+
import qualified React.DOM as DOM
12+
13+
cBoxRender = do
14+
state <- readState
15+
pure $ DOM.div { className: "commentBox" }
16+
[ DOM.h1 {} [ DOM.text "Comments" ]
17+
, commentList { data': state }
18+
, commentForm { onCommentSubmit: handle commentSubmit }
19+
]
20+
foreign import initialState
21+
"function initialState() { return {state: []}; }" :: forall a b. a -> b
22+
23+
commentBox = mkStatefulUIFromSpec $
24+
defaultStatefulSpec { getInitialState = initialState
25+
, componentWillMount = componentWillMount
26+
, render = cBoxRender
27+
}
28+
29+
commentList = mkUI do
30+
props <- getProps
31+
pure $ DOM.div { className: "commentList" }
32+
(commentNodes <$> props.data')
33+
34+
commentForm = mkUI do
35+
props <- getProps
36+
pure $ DOM.form { className: "commentForm"
37+
, onSubmit: handle submit
38+
}
39+
[ DOM.input { attrType: "text"
40+
, placeholder: "Your name"
41+
, ref: "author"
42+
}
43+
[]
44+
, DOM.input { attrType: "text"
45+
, placeholder: "Say something..."
46+
, ref: "text"
47+
}
48+
[]
49+
, DOM.input { attrType: "submit"
50+
, value: "Post"
51+
}
52+
[]
53+
]
54+
55+
comment = mkUI do
56+
props <- getProps
57+
pure $ DOM.div { className: "comment" }
58+
[ DOM.h2 { className: "commentAuthor" }
59+
[ DOM.text props.author ]
60+
, DOM.span { dangerouslySetInnerHTML: { __html: makeHtml props.children } }
61+
[]
62+
]
63+
64+
commentNodes c = comment { author: c.author, children: c.text }
65+
66+
foreign import commentSubmit
67+
"function commentSubmit(comment) {\
68+
\ var comments = this.state.state;\
69+
\ var newComments = comments.concat([comment]);\
70+
\ this.setState({state: newComments});\
71+
\ $.ajax({\
72+
\ url: this.props.url,\
73+
\ dataType: 'json',\
74+
\ type: 'POST',\
75+
\ data: comment,\
76+
\ success: function(data) {\
77+
\ this.setState({state: data});\
78+
\ }.bind(this)\
79+
\ });\
80+
\}" :: forall eff. Eff eff {}
81+
82+
foreign import submit
83+
"function submit() {\
84+
\ var author = this.refs.author.getDOMNode().value.trim();\
85+
\ var text = this.refs.text.getDOMNode().value.trim();\
86+
\ this.props.onCommentSubmit.call(this, {author: author, text: text});\
87+
\ this.refs.author.getDOMNode().value = '';\
88+
\ this.refs.text.getDOMNode().value = '';\
89+
\ return false;\
90+
\}" :: forall eff. Eff eff Boolean
91+
92+
foreign import loadCommentsFromServer
93+
"function loadCommentsFromServer() {\
94+
\ $.ajax({\
95+
\ url: this.props.url,\
96+
\ dataType: 'json',\
97+
\ success: function(data) {\
98+
\ this.replaceState({state: data});\
99+
\ }.bind(this)\
100+
\ });\
101+
\}" :: forall a r. {props :: {url :: String}, replaceState :: {state :: a} -> {} | r} -> {}
102+
103+
foreign import componentWillMount
104+
"function componentWillMount() {\
105+
\ var load = loadCommentsFromServer.bind(this);\
106+
\ load();\
107+
\ setInterval(function() { load(); }, this.props.pollInterval);\
108+
\}" :: forall r. {} -> {}
109+
110+
main = renderToElementById "content" $ commentBox { url: "comments.json"
111+
, pollInterval: 2000
112+
}

gulpfile.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
var gulp = require('gulp')
2+
, purescript = require('gulp-purescript');
3+
4+
var paths = {
5+
src: [
6+
'src/**/*.purs',
7+
'bower_components/purescript-*/src/**/*.purs'
8+
],
9+
example: {
10+
app: {
11+
src: [
12+
'src/**/*.purs',
13+
'example/app/app.purs',
14+
'bower_components/purescript-*/src/**/*.purs'
15+
]
16+
},
17+
tutorial: {
18+
src: [
19+
'src/**/*.purs',
20+
'example/tutorial/tutorial.purs',
21+
'bower_components/purescript-*/src/**/*.purs',
22+
'example/tutorial/bower_components/purescript-*/src/**/*.purs'
23+
]
24+
}
25+
}
26+
};
27+
28+
var options = {
29+
example: {
30+
app: {
31+
output: 'example/app/app.js',
32+
main: true
33+
},
34+
tutorial: {
35+
output: 'example/tutorial/tutorial.js',
36+
main: 'Tutorial'
37+
}
38+
}
39+
};
40+
41+
var compile = function(paths, options) {
42+
return function() {
43+
// We need this hack for now until gulp does something about
44+
// https://github.com/gulpjs/gulp/issues/71
45+
var psc = purescript.psc(options);
46+
psc.on('error', function(e) {
47+
console.error(e.message);
48+
psc.end();
49+
});
50+
return gulp.src(paths.src)
51+
.pipe(psc)
52+
.pipe(gulp.dest(paths.dest || 'js'));
53+
};
54+
};
55+
56+
gulp.task('src', compile(paths, {}));
57+
58+
gulp.task('example-app', compile(paths.example.app, options.example.app));
59+
60+
gulp.task('example-tutorial',
61+
compile(paths.example.tutorial, options.example.tutorial));
62+
63+
gulp.task('watch', function() {
64+
gulp.watch(paths.src, ['src']);
65+
});
66+
67+
gulp.task('default', ['src', 'watch']);
68+
69+
gulp.task('examples', ['example-app', 'example-tutorial']);

package.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "purescript-react",
3+
"version": "0.0.1",
4+
"description": "Purescript bindings for React.js ",
5+
"repository": {
6+
"type": "git",
7+
"url": "git://github.com/purescript-contrib/purescript-react.git"
8+
},
9+
"keywords": [
10+
"purescript",
11+
"react"
12+
],
13+
"author": "",
14+
"license": "MIT",
15+
"bugs": {
16+
"url": "https://github.com/purescript-contrib/purescript-react/issues"
17+
},
18+
"homepage": "https://github.com/purescript-contrib/purescript-react",
19+
"devDependencies": {
20+
"gulp": "^3.6.2",
21+
"gulp-purescript": "0.0.4"
22+
}
23+
}

0 commit comments

Comments
 (0)