From f2823c9ea8da32056947e567557c078988f71376 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 21:45:00 -0700 Subject: [PATCH 1/7] init --- server.go | 108 ----------------------------------------------------- server.lua | 28 -------------- server.php | 49 ------------------------ server.py | 33 ---------------- server.rb | 42 --------------------- 5 files changed, 260 deletions(-) delete mode 100644 server.go delete mode 100644 server.lua delete mode 100644 server.php delete mode 100644 server.py delete mode 100644 server.rb diff --git a/server.go b/server.go deleted file mode 100644 index e36b5b21..00000000 --- a/server.go +++ /dev/null @@ -1,108 +0,0 @@ -/** - * This file provided by Facebook is for non-commercial testing and evaluation purposes only. - * Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "sync" -) - -type comment struct { - Author string `json:"author"` - Text string `json:"text"` -} - -const dataFile = "./comments.json" - -var commentMutex = new(sync.Mutex) - -// Handle comments -func handleComments(w http.ResponseWriter, r *http.Request) { - // Since multiple requests could come in at once, ensure we have a lock - // around all file operations - commentMutex.Lock() - defer commentMutex.Unlock() - - // Stat the file, so we can find its current permissions - fi, err := os.Stat(dataFile) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to stat the data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - // Read the comments from the file. - commentData, err := ioutil.ReadFile(dataFile) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to read the data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - switch r.Method { - case "POST": - // Decode the JSON data - comments := make([]comment, 0) - if err := json.Unmarshal(commentData, &comments); err != nil { - http.Error(w, fmt.Sprintf("Unable to Unmarshal comments from data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - // Add a new comment to the in memory slice of comments - comments = append(comments, comment{Author: r.FormValue("author"), Text: r.FormValue("text")}) - - // Marshal the comments to indented json. - commentData, err = json.MarshalIndent(comments, "", " ") - if err != nil { - http.Error(w, fmt.Sprintf("Unable to marshal comments to json: %s", err), http.StatusInternalServerError) - return - } - - // Write out the comments to the file, preserving permissions - err := ioutil.WriteFile(dataFile, commentData, fi.Mode()) - if err != nil { - http.Error(w, fmt.Sprintf("Unable to write comments to data file (%s): %s", dataFile, err), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Cache-Control", "no-cache") - io.Copy(w, bytes.NewReader(commentData)) - - case "GET": - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Cache-Control", "no-cache") - // stream the contents of the file to the response - io.Copy(w, bytes.NewReader(commentData)) - - default: - // Don't know the method, so error - http.Error(w, fmt.Sprintf("Unsupported method: %s", r.Method), http.StatusMethodNotAllowed) - } -} - -func main() { - port := os.Getenv("PORT") - if port == "" { - port = "3000" - } - http.HandleFunc("/comments.json", handleComments) - http.Handle("/", http.FileServer(http.Dir("./public"))) - log.Println("Server started: http://localhost:" + port) - log.Fatal(http.ListenAndServe(":"+port, nil)) -} diff --git a/server.lua b/server.lua deleted file mode 100644 index ec075eaa..00000000 --- a/server.lua +++ /dev/null @@ -1,28 +0,0 @@ --- --- For use with Algernon / Lua --- --- Project page: https://github.com/xyproto/algernon --- Web page: http://algernon.roboticoverlords.org/ --- - -handle("/comments.json", function() - - -- Set the headers - content("application/javascript") - setheader("Cache-Control", "no-cache") - - -- Use a JSON file for the comments - comments = JFile("comments.json") - - -- Handle requests - if method() == "POST" then - -- Add the form data table to the JSON document - comments:add(ToJSON(formdata(), 4)) - end - - -- Return the contents of the JSON file - print(tostring(comments)) - -end) - -servedir("/", "public") diff --git a/server.php b/server.php deleted file mode 100644 index b6ab88f2..00000000 --- a/server.php +++ /dev/null @@ -1,49 +0,0 @@ - $_POST['author'], - 'text' => $_POST['text']]; - - $comments = json_encode($commentsDecoded, JSON_PRETTY_PRINT); - file_put_contents('comments.json', $comments); - } - header('Content-Type: application/json'); - header('Cache-Control: no-cache'); - echo $comments; - } else { - return false; - } -} diff --git a/server.py b/server.py deleted file mode 100644 index 730e39b3..00000000 --- a/server.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file provided by Facebook is for non-commercial testing and evaluation purposes only. -# Facebook reserves all rights not expressly granted. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import json -import os -from flask import Flask, Response, request - -app = Flask(__name__, static_url_path='', static_folder='public') -app.add_url_rule('/', 'root', lambda: app.send_static_file('index.html')) - -@app.route('/comments.json', methods=['GET', 'POST']) -def comments_handler(): - - with open('comments.json', 'r') as file: - comments = json.loads(file.read()) - - if request.method == 'POST': - comments.append(request.form.to_dict()) - - with open('comments.json', 'w') as file: - file.write(json.dumps(comments, indent=4, separators=(',', ': '))) - - return Response(json.dumps(comments), mimetype='application/json', headers={'Cache-Control': 'no-cache'}) - -if __name__ == '__main__': - app.run(port=int(os.environ.get("PORT",3000))) diff --git a/server.rb b/server.rb deleted file mode 100644 index 6bfb84a1..00000000 --- a/server.rb +++ /dev/null @@ -1,42 +0,0 @@ -# This file provided by Facebook is for non-commercial testing and evaluation purposes only. -# Facebook reserves all rights not expressly granted. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -require 'webrick' -require 'json' - -port = ENV['PORT'].nil? ? 3000 : ENV['PORT'].to_i - -puts "Server started: http://localhost:#{port}/" - -root = File.expand_path './public' -server = WEBrick::HTTPServer.new :Port => port, :DocumentRoot => root - -server.mount_proc '/comments.json' do |req, res| - comments = JSON.parse(File.read('./comments.json')) - - if req.request_method == 'POST' - # Assume it's well formed - comment = {} - req.query.each do |key, value| - comment[key] = value.force_encoding('UTF-8') - end - comments << comment - File.write('./comments.json', JSON.pretty_generate(comments, :indent => ' ')) - end - - # always return json - res['Content-Type'] = 'application/json' - res['Cache-Control'] = 'no-cache' - res.body = JSON.generate(comments) -end - -trap 'INT' do server.shutdown end - -server.start From 74d304c7e524d06439b13341aaf0929ccbf57e32 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 21:56:01 -0700 Subject: [PATCH 2/7] update package --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e7491981..6b0833e5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "server.js", "dependencies": { "body-parser": "^1.4.3", - "express": "^4.4.5" + "express": "^4.4.5", + "bootstrap": "~3.3.5" }, "devDependencies": {}, "scripts": { @@ -27,7 +28,7 @@ "url": "https://github.com/reactjs/react-tutorial/issues" }, "homepage": "https://github.com/reactjs/react-tutorial", - "engines" : { - "node" : "0.12.x" + "engines": { + "node": "0.12.x" } } From 2347e1796e9f5fcbe3979fdbdcc3a080f33a1410 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 22:03:27 -0700 Subject: [PATCH 3/7] simple update --- comments.json | 6 +++++- public/index.html | 1 + server.js | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/comments.json b/comments.json index 61f5ef60..a97bcdb1 100644 --- a/comments.json +++ b/comments.json @@ -6,5 +6,9 @@ { "author": "Paul O’Shannessy", "text": "React is *great*!" + }, + { + "author": "Nil", + "text": "React is awesome" } -] +] \ No newline at end of file diff --git a/public/index.html b/public/index.html index c6220169..06f9a981 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,7 @@ Hello React + diff --git a/server.js b/server.js index 8ce83a0d..b05b6a8e 100644 --- a/server.js +++ b/server.js @@ -19,6 +19,8 @@ var app = express(); app.set('port', (process.env.PORT || 3000)); app.use('/', express.static(path.join(__dirname, 'public'))); +app.use('/bootstrap', express.static(path.join(__dirname, 'node_modules/bootstrap/dist'))); + app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); From 26df60e07075fb9734bbed01836fe9fbe99b44b1 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 22:41:31 -0700 Subject: [PATCH 4/7] simple update --- public/scripts/example.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/public/scripts/example.js b/public/scripts/example.js index fad2ea73..b889e3bc 100644 --- a/public/scripts/example.js +++ b/public/scripts/example.js @@ -1,15 +1,3 @@ -/** - * This file provided by Facebook is for non-commercial testing and evaluation purposes only. - * Facebook reserves all rights not expressly granted. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - var Comment = React.createClass({ render: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); @@ -111,10 +99,10 @@ var CommentForm = React.createClass({ }, render: function() { return ( -
- - - + + + +
); } From 082aeea946ab357d652e36d39c9167da0e8d7ba2 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 22:43:16 -0700 Subject: [PATCH 5/7] simple update --- requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 632a1efa..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Flask==0.10.1 From 29b3d51f09d7b0228a8910789d5a5d7d1f0dd3e7 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Wed, 22 Jul 2015 22:50:20 -0700 Subject: [PATCH 6/7] update --- public/index.html | 2 +- public/scripts/{example.js => app.js} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename public/scripts/{example.js => app.js} (95%) diff --git a/public/index.html b/public/index.html index 06f9a981..50666b76 100644 --- a/public/index.html +++ b/public/index.html @@ -12,6 +12,6 @@
- + diff --git a/public/scripts/example.js b/public/scripts/app.js similarity index 95% rename from public/scripts/example.js rename to public/scripts/app.js index b889e3bc..ee97193d 100644 --- a/public/scripts/example.js +++ b/public/scripts/app.js @@ -99,10 +99,10 @@ var CommentForm = React.createClass({ }, render: function() { return ( -
+ - +
); } From 4e5d33a97b0862d87914b15a4b9710596fb00b02 Mon Sep 17 00:00:00 2001 From: Ni Zhihao Date: Thu, 23 Jul 2015 00:45:36 -0700 Subject: [PATCH 7/7] change readme --- README.md | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f8aa5bc7..46f258e7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,22 @@ -[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) - # React Tutorial This is the React comment box example from [the React tutorial](http://facebook.github.io/react/docs/tutorial.html). +## To Start Building +Checkout + +- step1 +- step2 +- step3 +- step4 +- step5 +- step6 +- step7 + +branch to checkout different steps building the application + +The PowerPoint is avaliable here... + ## To use There are several simple server implementations included. They all serve static files from `public/` and handle requests to `comments.json` to fetch or add data. Start a server with one of the following: @@ -15,34 +28,4 @@ npm install node server.js ``` -### Python - -```sh -pip install -r requirements.txt -python server.py -``` - -### Ruby -```sh -ruby server.rb -``` - -### PHP -```sh -php server.php -``` - -### Go -```sh -go run server.go -``` - -### Lua - -```sh -go get github.com/xyproto/algernon -# or brew install algernon -algernon server.lua -``` - And visit . Try opening multiple tabs!