Permalink
Browse files

added 302/404/500 handling

  • Loading branch information...
rayui committed Jan 15, 2012
1 parent 269f702 commit 9eb980270e98e69bea96f15aeed7fa02c8aed5f1
Showing with 82 additions and 135 deletions.
  1. +3 −2 doc-generator.sh
  2. +1 −5 js/app.js
  3. +0 −107 js/client/js/common.js
  4. +50 −21 js/modules/server.js
  5. +14 −0 templates/404.jade
  6. +14 −0 templates/500.jade
View
@@ -1,14 +1,15 @@
#!/bin/bash
DOCROOT='docs'
-WEBROOT='assets/docs'
+WEBROOT='public/docs'
DOCINDEX="$DOCROOT/index.html"
rm -rf $DOCROOT
rm -rf $WEBROOT
docco js/*.js
docco js/modules/*.js
-docco assets/js/*.js
+docco js/modules/shared/*.js
+docco public/js/*.js
echo "<!DOCTYPE html><html>
<head><title>MVC Lesson 1/</title>
View
@@ -2,8 +2,4 @@
var ws = require('./modules/server');
//instantiate new web server
-var webServer = new ws.webServer({
- 'port':process.env.PORT || 8000,
- assets_dir:__dirname + '/../public',
- template_dir:__dirname + '/../templates'
-});
+var webServer = new ws.webServer();
View
@@ -1,107 +0,0 @@
-//- require dependencies
-$ = jQuery = require('jQuery');
-Backbone = require('backbone');
-
-//on jquery init
-$(function($){
- //simplest possible model
- var Model = Backbone.Model.extend({
- url:'/',
- validate:function(attrs) {
- //- errors array to return
- var errors = [];
-
- //- check if input is an integer and push to error array if not
- var checkInteger = function(id, value) {
- if(!((parseFloat(value) === parseInt(value, 10)) && !isNaN(value))){
- errors.push({
- id:id,
- error:'must be an integer'
- });
- }
- };
-
- //- check all field types
- for (id in attrs) {
- checkInteger(id, attrs[id]);
- }
-
- //- if elements with errors, return them
- if (errors.length) {
- return errors;
- }
-
- //- otherwise return null
- return null;
- }
- });
-
- //basic view for multiplier calculator
- var View = Backbone.View.extend({
- //- element to bind view to
- el:$('#page'),
-
- //- default events
- events:{
- 'change input[type="text"]': 'submit',
- 'submit #multiply': 'submit'
- },
-
- //- when inputs change, save the model to the server
- //- if it fails validation, the error function will kick in
- //- when a success response is received, this will trigger the model's change event and causing it to render
- submit:function() {
- var renderError = this.renderError;
- var clearErrors = this.clearErrors;
-
- this.model.save({
- 'operand1': parseInt($('input#operand1').val(), 10),
- 'operand2': parseInt($('input#operand2').val(), 10)
- },{
- error: function(model, errors) {
- clearErrors();
- for (attr in errors) {
- renderError(errors[attr]['id'], errors[attr]['error']);
- }
- }
- });
-
- return false;
- },
-
- //- renders and error notification
- renderError: function(id, error) {
- $('input#' + id).addClass('error');
- $('div#result').append('<span>' + id + ': ' + error + '</span>');
- },
-
- //- clears existing error notifications
- clearErrors: function() {
- $('input').removeClass('error');
- $('div#result').empty();
- },
-
- //- render result on server response
- render: function() {
- this.clearErrors();
- $('div#result').text(
- this.model.get('operand1') +
- ' * ' +
- this.model.get('operand2') +
- ' = ' +
- this.model.get('result')
- );
- },
-
- //- init
- initialize:function() {
- //-- instantiate Model inside View and bind new model's change event to this View's render method
- //-- note that this is backbone's bind, different from jQuery
- this.model = new Model();
- this.model.bind('change', this.render, this);
- }
- });
-
- //instantiate view
- new View();
-});
View
@@ -14,7 +14,7 @@ models.webServer = function(_options){
var options = {
port:8000,
shared_dir:__dirname + '/shared',
- assets_dir:__dirname + '/../../public',
+ public_dir:__dirname + '/../../public',
template_dir:__dirname + '/../../templates'
};
@@ -32,7 +32,7 @@ models.webServer = function(_options){
};
//validate inputs and perform multiplication
- var multiply = function(data) {
+ var multiplyData = function(data) {
data.errors = utilities.validate(data.attributes);
if (data.errors) {
data.result = undefined;
@@ -43,60 +43,75 @@ models.webServer = function(_options){
return data;
};
+ var serveError = function(res, number) {
+ jade.renderFile(options['template_dir'] + '/' + number + '.jade', {}, function(err,html){
+ res.header('Content-Type', 'text/html');
+ if (err) {
+ if (number !== 500) {
+ serveError(res, 500);
+ } else {
+ res.send('<h1>FATAL SERVER ERROR</h1>', 500)
+ }
+ } else {
+ res.send(html, number);
+ }
+ });
+ };
+
//serve static files
var serveStatic = function(res, fn, contentType) {
fs.readFile(fn, function(err,data){
res.header('Content-Type', contentType);
if(err) {
- res.send(404);
+ serveError(res, 404);
return;
}
res.send(data);
});
};
//renders a chunk of markup to the response object
- var renderHTML = function(res, data) {
+ var serveHTML = function(res, data) {
jade.renderFile(options['template_dir'] + '/index.jade', data, function(err,html){
res.header('Content-Type', 'text/html');
if (err) {
- res.send(500);
+ serveError(res, 500);
return;
}
res.send(html);
});
};
//renders a chunk of JSON to the response object
- var renderJSON = function(res, data) {
+ var serveJSON = function(res, data) {
res.json(data);
};
- //extend default options
- _.extend(options, _options);
-
//create express server with browserify
var app = express.createServer();
+ //extend default options
+ _.extend(options, _options);
+
//configure express app
app.configure(function(){
app.use(express.bodyParser());
});
- //simple get request. send undefined data
- app.get('/', function(req, res) {
- data = defaultData();
- renderHTML(res, data);
+ //routing for directories with no trailing slash
+ app.get(/^(\/[\w\-\.]+)$/, function(req, res) {
+ res.header('Location', req.params[0] + '/');
+ res.send(302);
});
//routing for css
app.get(/^\/css\/(\w+\.css)?/, function(req, res) {
- serveStatic(res, options['assets_dir'] + '/css/' + req.params[0], 'text/css');
+ serveStatic(res, options['public_dir'] + '/css/' + req.params[0], 'text/css');
});
//routing for js
app.get(/^\/js\/((shared|lib)\/)?([\w\-\.]+\.js)/, function(req, res) {
- var baseDir = options['assets_dir'] + '/js';
+ var baseDir = options['public_dir'] + '/js';
switch (req.params[1]) {
case 'shared':
baseDir = options['shared_dir'];
@@ -110,26 +125,40 @@ models.webServer = function(_options){
serveStatic(res, baseDir + '/' + req.params[2], 'application/javascript');
});
+ //routing for docs
+ app.get(/^\/docs\/([\w\-\.]+\.(css|html))?$/, function(req, res) {
+ var fn = req.params[0] ? req.params[0] : 'index.html';
+ var contentType = 'text/' + (req.params[1] ? req.params[1] : 'html');
+
+ serveStatic(res, options['public_dir'] + '/docs/' + fn, contentType);
+ });
+
+ //simple get request. send undefined data
+ app.get('/', function(req, res) {
+ data = defaultData();
+ serveHTML(res, data);
+ });
+
//fallback routing
app.get(/^.*?/, function(req, res) {
- res.send(404);
+ serveError(res, 404);
});
-
- //simple multiplication function
+
+ //simple post multiplication function
app.post('/', function(req, res) {
- var data = multiply(defaultData({
+ var data = multiplyData(defaultData({
operand1:req.body.operand1,
operand2:req.body.operand2
}));
//choose our render method based on request content type
switch (req['headers']['content-type'].match(/(form|json)/)[0]) {
case 'json':
- renderJSON(res, data);
+ serveJSON(res, data);
break;
case 'form':
default:
- renderHTML(res, data);
+ serveHTML(res, data);
break;
}
});
View
@@ -0,0 +1,14 @@
+!!! 5
+html
+ head
+ script(src='/js/lib/jquery-1.7.1.min.js')
+ script(src='/js/lib/underscore-min.js')
+ script(src='/js/lib/backbone-min.js')
+ script(src='/js/shared/utilities.js')
+ script(src='/js/common.js')
+ link(rel="stylesheet", type="text/css", href="/css/style.css")
+ body
+ #header
+ h1 OH NO 404!
+ #page
+ p We couldn't find that page. Sorry!
View
@@ -0,0 +1,14 @@
+!!! 5
+html
+ head
+ script(src='/js/lib/jquery-1.7.1.min.js')
+ script(src='/js/lib/underscore-min.js')
+ script(src='/js/lib/backbone-min.js')
+ script(src='/js/shared/utilities.js')
+ script(src='/js/common.js')
+ link(rel="stylesheet", type="text/css", href="/css/style.css")
+ body
+ #header
+ h1 OH NO 500!
+ #page
+ p Argh! We crashed! So sorry!

0 comments on commit 9eb9802

Please sign in to comment.