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! 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/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" } } diff --git a/public/index.html b/public/index.html index c6220169..50666b76 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,7 @@ Hello React + @@ -11,6 +12,6 @@
- + diff --git a/public/scripts/example.js b/public/scripts/app.js similarity index 79% rename from public/scripts/example.js rename to public/scripts/app.js index fad2ea73..ee97193d 100644 --- a/public/scripts/example.js +++ b/public/scripts/app.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}); @@ -112,9 +100,9 @@ var CommentForm = React.createClass({ render: function() { return (
- - - + + +
); } 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 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.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})); 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