Commit a8f3c283 authored by Ricco Førgaard's avatar Ricco Førgaard

Initial commit.

parents
www/
node_modules/
*-sublime.*
# React.js Based Tag Wall
This project is a small test of [Facebook's UI framework, React.js](http://facebook.github.io/react). It is an implementation of the [Getting Started tutorial](http://facebook.github.io/react/docs/tutorial.html).
## Running
Run `npm install` to install necessary Grunt modules. Then use `grunt watch` to compile and copy and let Grunt watch the files for changes.
Also run `server.js` as a node script. This is a small server that will deliver the files plus a JSON document with comment data. When you post a comment in the app, this process will store it internally.
It will not persist the comments, so if you restart the server process, everything is lost.
**Enjoy**.
\ No newline at end of file
/*global module, require */
module.exports = function(grunt) {
// Load libs
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-react');
grunt.loadNpmTasks('grunt-browserify');
// Setup
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
main: {
src: 'index.html',
dest: 'www/index.html'
}
},
browserify: {
options: {
transform: [ require('grunt-react').browserify ],
extension: 'jsx'
},
app: {
src: 'src/main.js',
dest: 'www/js/app.js'
}
},
watch: {
//Install browser extension to get watch to trigger automatic
//browser reload: http://goo.gl/o7SBk
options: {
livereload: true,
atBegin: true
},
tasks: ['default'],
files: ['index.html', 'src/**/*.js*']
}
});
// Tasks
grunt.registerTask('default', [
'copy',
'browserify'
]);
};
<!DOCTYPE html>
<html>
<head>
<title>ReactJS-driven tag wall</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
<script type="text/javascript">
var converter = new Showdown.converter();
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.5.2/react.js"></script>
<script data-main="js/app.js" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.9/require.min.js"></script>
<script src="http://code.jquery.com/jquery-2.0.3.min.js" type="text/javascript" encoding="utf-8"></script>
<style type="text/css">
body {
font-family: sans-serif;
font-size: 16px;
color: #333;
}
#content {
max-width: 500px;
margin: 0 auto;
}
ul.commentList {
list-style-type: none;
margin: 0;
padding: 0;
}
li.comment {
margin-bottom: 1em;
border-bottom: 1px solid #ddd;
}
h2>small {
margin-left: .5em;
font-size: 80%;
font-weight: normal;
color: #999;
font-style: italic;
}
.commentForm>div {
padding: 1em;
}
.commentForm label {
display: inline;
float: left;
min-width: 140px;
}
.commentForm textarea {
width: 320px;
height: 200px;
font-size: 20px;
font-family: 'courier new', monospace;
}
</style>
</head>
<body>
<div id="content"></div>
</body>
</html>
\ No newline at end of file
{
"name": "react-test",
"version": "0.0.0",
"description": "A basic implementation of a tagwall using ReactJS.",
"main": "gruntfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "MIT",
"devDependencies": {
"grunt-react": "~0.6.0",
"grunt-contrib-watch": "~0.5.3",
"browserify": "~3.4.0",
"grunt-browserify": "~1.3.0",
"grunt-contrib-copy": "~0.4.1"
}
}
var root = './www',
data = [],
http = require('http'),
fs = require('fs'),
qs = require('querystring'),
isNotAfile = function (possibleFile) {
var isValidFile = (typeof possibleFile === 'string' || Buffer.isBuffer(possibleFile));
console.log("is valid", isValidFile);
return !isValidFile;
},
write404 = function (response) {
response.writeHead(404, {'Content-Type': 'text/plain'});
response.end(':-(');
},
writeFileResponse = function (path, file, response) {
var contentType = (path.indexOf('.html') !== -1)
? 'text/html'
: 'application/javascript';
response.writeHead(200, {'Content-Type': contentType});
response.write(file);
response.end();
},
serveFile = function (path, response) {
console.log("Serving index.html");
fs.readFile(root + path, function (err, file) {
if (err || isNotAfile(file)) {
write404(response);
} else {
writeFileResponse(path, file, response);
}
});
},
serveData = function (response) {
console.log("Serve data");
response.writeHead(200, {'Content-Type': 'application/json'});
response.end(JSON.stringify(data));
},
handlePOST = function (request, response) {
var requestBody = '';
request.on('data', function (data) {
requestBody += data;
});
request.on('end', function () {
var formData = qs.parse(requestBody);
data.push(formData);
serveData(response);
});
},
server = http.createServer(function (request, response) {
console.log(request.method, request.url);
if (request.method === 'GET') {
if (request.url === '/comments.json') {
serveData(response);
} else {
serveFile(request.url, response);
}
} else if (request.method === 'POST') {
handlePOST(request, response);
}
}).listen(8000);
/** @jsx React.DOM */
var CommentBox = require('./templates/commentbox.jsx'),
initialize = function () {
React.renderComponent(
<CommentBox url="comments.json" pollInterval={2000} />,
document.getElementById('content')
);
}
initialize();
\ No newline at end of file
/** @jsx React.DOM */
var Comment = React.createClass({
render: function () {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<li className="comment">
<h2 className="commentAuthor">
{this.props.author}<small>sez:</small>
</h2>
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</li>
);
}
});
module.exports = Comment;
\ No newline at end of file
/** @jsx React.DOM */
var CommentList = require('./commentlist.jsx'),
CommentForm = require('./commentform.jsx'),
CommentBox = React.createClass({
getInitialState: function () {
return {data: []};
},
loadCommentsFromServer: function () {
$.ajax({
url: 'comments.json',
success: function (data) {
this.setState({data: data});
}.bind(this)
});
},
handleCommentSubmit: function (comment) {
$.ajax({
url: this.props.url,
type: 'POST',
data: comment,
success: function (data) {
this.setState({data: data});
}.bind(this)
});
},
componentWillMount: function () {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function () {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
module.exports = CommentBox;
\ No newline at end of file
/** @jsx React.DOM */
var CommentForm = React.createClass({
handleSubmit: function (event) {
event.preventDefault();
var author = this.refs.author.getDOMNode().value.trim(),
text = this.refs.text.getDOMNode().value.trim();
this.props.onCommentSubmit({author: author, text: text});
this.refs.author.getDOMNode().value = '';
this.refs.text.getDOMNode().value = '';
},
render: function () {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<h3>Leave a comment</h3>
<div>
<label htmlFor="author">Your name:</label>
<input type="text" placeholder="Your name..." ref="author" />
</div>
<div>
<label htmlFor="text">Your comment:</label>
<textarea placeholder="What do you have to say...?" ref="text"></textarea>
</div>
<input type="submit" value="Post" />
</form>
);
}
});
module.exports = CommentForm;
\ No newline at end of file
/** @jsx React.DOM */
var Comment = require('./comment.jsx'),
CommentList = React.createClass({
render: function () {
var commentNodes = this.props.data.map(function (comment) {
var markedUpCommentText = converter.makeHtml(comment.text.toString());
return <Comment author={comment.author}>{comment.text}</Comment>;
});
return (
<ul className="commentList">
{commentNodes}
</ul>
);
}
});
module.exports = CommentList;
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment